katakata_irb 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/katakata_irb.gemspec +1 -1
- data/lib/katakata_irb/completor.rb +46 -22
- data/lib/katakata_irb/scope.rb +53 -15
- data/lib/katakata_irb/type_analyzer.rb +1172 -0
- data/lib/katakata_irb/types.rb +11 -36
- data/lib/katakata_irb/version.rb +1 -1
- metadata +5 -5
- data/lib/katakata_irb/type_simulator.rb +0 -990
@@ -1,990 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'set'
|
4
|
-
require_relative 'types'
|
5
|
-
require_relative 'scope'
|
6
|
-
require 'prism'
|
7
|
-
|
8
|
-
class KatakataIrb::TypeSimulator
|
9
|
-
class DigTarget
|
10
|
-
def initialize(parents, receiver, &block)
|
11
|
-
@dig_ids = parents.to_h { [_1.__id__, true] }
|
12
|
-
@target_id = receiver.__id__
|
13
|
-
@block = block
|
14
|
-
end
|
15
|
-
|
16
|
-
def dig?(node) = @dig_ids[node.__id__]
|
17
|
-
def target?(node) = @target_id == node.__id__
|
18
|
-
def resolve(type, scope)
|
19
|
-
@block.call type, scope
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
OBJECT_METHODS = {
|
24
|
-
to_s: KatakataIrb::Types::STRING,
|
25
|
-
to_str: KatakataIrb::Types::STRING,
|
26
|
-
to_a: KatakataIrb::Types::ARRAY,
|
27
|
-
to_ary: KatakataIrb::Types::ARRAY,
|
28
|
-
to_h: KatakataIrb::Types::HASH,
|
29
|
-
to_hash: KatakataIrb::Types::HASH,
|
30
|
-
to_i: KatakataIrb::Types::INTEGER,
|
31
|
-
to_int: KatakataIrb::Types::INTEGER,
|
32
|
-
to_f: KatakataIrb::Types::FLOAT,
|
33
|
-
to_c: KatakataIrb::Types::COMPLEX,
|
34
|
-
to_r: KatakataIrb::Types::RATIONAL
|
35
|
-
}
|
36
|
-
|
37
|
-
def initialize(dig_targets)
|
38
|
-
@dig_targets = dig_targets
|
39
|
-
end
|
40
|
-
|
41
|
-
def evaluate(node, scope)
|
42
|
-
result = evaluate_inner(node, scope)
|
43
|
-
@dig_targets.resolve result, scope if @dig_targets.target?(node)
|
44
|
-
result
|
45
|
-
end
|
46
|
-
|
47
|
-
def evaluate_inner(node, scope)
|
48
|
-
case node
|
49
|
-
when Prism::ProgramNode
|
50
|
-
evaluate node.statements, scope
|
51
|
-
when Prism::StatementsNode
|
52
|
-
if node.body.empty?
|
53
|
-
KatakataIrb::Types::NIL
|
54
|
-
else
|
55
|
-
node.body.map { evaluate _1, scope }.last
|
56
|
-
end
|
57
|
-
when Prism::DefNode
|
58
|
-
if node.receiver
|
59
|
-
self_type = evaluate node.receiver, scope
|
60
|
-
else
|
61
|
-
current_self_types = scope.self_type.types
|
62
|
-
self_types = current_self_types.map do |type|
|
63
|
-
if type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
64
|
-
KatakataIrb::Types::InstanceType.new type.module_or_class
|
65
|
-
else
|
66
|
-
type
|
67
|
-
end
|
68
|
-
end
|
69
|
-
self_type = KatakataIrb::Types::UnionType[*self_types]
|
70
|
-
end
|
71
|
-
if @dig_targets.dig?(node.body) || @dig_targets.dig?(node.parameters)
|
72
|
-
params_table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
|
73
|
-
method_scope = KatakataIrb::Scope.new(
|
74
|
-
scope,
|
75
|
-
{ **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
|
76
|
-
self_type: self_type,
|
77
|
-
trace_lvar: false,
|
78
|
-
trace_ivar: false
|
79
|
-
)
|
80
|
-
if node.parameters
|
81
|
-
# node.parameters is Prism::ParametersNode
|
82
|
-
assign_parameters node.parameters, method_scope, [], {}
|
83
|
-
end
|
84
|
-
|
85
|
-
if @dig_targets.dig?(node.body)
|
86
|
-
method_scope.conditional do |s|
|
87
|
-
evaluate node.body, s
|
88
|
-
end
|
89
|
-
end
|
90
|
-
method_scope.merge_jumps
|
91
|
-
scope.update method_scope
|
92
|
-
end
|
93
|
-
KatakataIrb::Types::SYMBOL
|
94
|
-
when Prism::IntegerNode
|
95
|
-
KatakataIrb::Types::INTEGER
|
96
|
-
when Prism::FloatNode
|
97
|
-
KatakataIrb::Types::FLOAT
|
98
|
-
when Prism::RationalNode
|
99
|
-
KatakataIrb::Types::RATIONAL
|
100
|
-
when Prism::ImaginaryNode
|
101
|
-
KatakataIrb::Types::COMPLEX
|
102
|
-
when Prism::StringNode
|
103
|
-
KatakataIrb::Types::STRING
|
104
|
-
when Prism::XStringNode
|
105
|
-
KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
|
106
|
-
when Prism::SymbolNode
|
107
|
-
KatakataIrb::Types::SYMBOL
|
108
|
-
when Prism::RegularExpressionNode
|
109
|
-
KatakataIrb::Types::REGEXP
|
110
|
-
when Prism::StringConcatNode
|
111
|
-
evaluate node.left, scope
|
112
|
-
evaluate node.right, scope
|
113
|
-
KatakataIrb::Types::STRING
|
114
|
-
when Prism::InterpolatedStringNode
|
115
|
-
node.parts.each { evaluate _1, scope }
|
116
|
-
KatakataIrb::Types::STRING
|
117
|
-
when Prism::InterpolatedXStringNode
|
118
|
-
node.parts.each { evaluate _1, scope }
|
119
|
-
KatakataIrb::Types::STRING
|
120
|
-
when Prism::InterpolatedSymbolNode
|
121
|
-
node.parts.each { evaluate _1, scope }
|
122
|
-
KatakataIrb::Types::SYMBOL
|
123
|
-
when Prism::InterpolatedRegularExpressionNode
|
124
|
-
node.parts.each { evaluate _1, scope }
|
125
|
-
KatakataIrb::Types::REGEXP
|
126
|
-
when Prism::EmbeddedStatementsNode
|
127
|
-
node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
|
128
|
-
KatakataIrb::Types::STRING
|
129
|
-
when Prism::EmbeddedVariableNode
|
130
|
-
evaluate node.variable, scope
|
131
|
-
KatakataIrb::Types::STRING
|
132
|
-
when Prism::ArrayNode
|
133
|
-
KatakataIrb::Types.array_of evaluate_list_splat_items(node.elements, scope)
|
134
|
-
when Prism::HashNode, Prism::KeywordHashNode
|
135
|
-
keys = []
|
136
|
-
values = []
|
137
|
-
node.elements.each do |assoc|
|
138
|
-
case assoc
|
139
|
-
when Prism::AssocNode
|
140
|
-
keys << evaluate(assoc.key, scope)
|
141
|
-
values << evaluate(assoc.value, scope)
|
142
|
-
when Prism::AssocSplatNode
|
143
|
-
hash = evaluate assoc.value, scope
|
144
|
-
unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
|
145
|
-
hash = simulate_call hash, :to_hash, [], nil, nil, scope
|
146
|
-
end
|
147
|
-
if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
|
148
|
-
keys << hash.params[:K] if hash.params[:K]
|
149
|
-
values << hash.params[:V] if hash.params[:V]
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
if keys.empty? && values.empty?
|
154
|
-
KatakataIrb::Types::InstanceType.new Hash
|
155
|
-
else
|
156
|
-
KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values]
|
157
|
-
end
|
158
|
-
when Prism::ParenthesesNode
|
159
|
-
node.body ? evaluate(node.body, scope) : KatakataIrb::Types::NIL
|
160
|
-
when Prism::ConstantPathNode
|
161
|
-
type, = evaluate_constant_node node, scope
|
162
|
-
type
|
163
|
-
when Prism::SelfNode
|
164
|
-
scope.self_type
|
165
|
-
when Prism::TrueNode
|
166
|
-
KatakataIrb::Types::TRUE
|
167
|
-
when Prism::FalseNode
|
168
|
-
KatakataIrb::Types::FALSE
|
169
|
-
when Prism::NilNode
|
170
|
-
KatakataIrb::Types::NIL
|
171
|
-
when Prism::SourceFileNode
|
172
|
-
KatakataIrb::Types::STRING
|
173
|
-
when Prism::SourceLineNode
|
174
|
-
KatakataIrb::Types::INTEGER
|
175
|
-
when Prism::SourceEncodingNode
|
176
|
-
KatakataIrb::Types::InstanceType.new Encoding
|
177
|
-
when Prism::NumberedReferenceReadNode, Prism::BackReferenceReadNode
|
178
|
-
KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
|
179
|
-
when Prism::LocalVariableReadNode
|
180
|
-
scope[node.name.to_s] || KatakataIrb::Types::NIL
|
181
|
-
when Prism::ConstantReadNode, Prism::GlobalVariableReadNode, Prism::InstanceVariableReadNode, Prism::ClassVariableReadNode
|
182
|
-
scope[node.name.to_s] || KatakataIrb::Types::NIL
|
183
|
-
when Prism::CallNode
|
184
|
-
# TODO: return type of []=, field= when operator_loc.nil?
|
185
|
-
receiver_type = node.receiver ? evaluate(node.receiver, scope) : scope.self_type
|
186
|
-
evaluate_method = lambda do |scope|
|
187
|
-
args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
|
188
|
-
|
189
|
-
if block_sym_node
|
190
|
-
block_sym = block_sym_node.value
|
191
|
-
if @dig_targets.target? block_sym_node
|
192
|
-
# method(args, &:completion_target)
|
193
|
-
call_block_proc = ->(block_args, _self_type) do
|
194
|
-
block_receiver = block_args.first || KatakataIrb::Types::OBJECT
|
195
|
-
@dig_targets.resolve block_receiver, scope
|
196
|
-
KatakataIrb::Types::OBJECT
|
197
|
-
end
|
198
|
-
else
|
199
|
-
call_block_proc = ->(block_args, _self_type) do
|
200
|
-
block_receiver, *rest = block_args
|
201
|
-
block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_sym, rest, nil, nil, scope) : KatakataIrb::Types::OBJECT
|
202
|
-
end
|
203
|
-
end
|
204
|
-
elsif node.block.is_a? Prism::BlockNode
|
205
|
-
call_block_proc = ->(block_args, block_self_type) do
|
206
|
-
scope.conditional do |s|
|
207
|
-
numbered_parameters = node.block.locals.grep(/\A_[1-9]/).map(&:to_s)
|
208
|
-
params_table = node.block.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
|
209
|
-
table = { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil }
|
210
|
-
block_scope = KatakataIrb::Scope.new s, table, self_type: block_self_type, trace_ivar: !block_self_type
|
211
|
-
# TODO kwargs
|
212
|
-
if node.block.parameters&.parameters
|
213
|
-
# node.block.parameters is Prism::BlockParametersNode
|
214
|
-
assign_parameters node.block.parameters.parameters, block_scope, block_args, {}
|
215
|
-
elsif !numbered_parameters.empty?
|
216
|
-
assign_numbered_parameters numbered_parameters, block_scope, block_args, {}
|
217
|
-
end
|
218
|
-
result = node.block.body ? evaluate(node.block.body, block_scope) : KatakataIrb::Types::NIL
|
219
|
-
block_scope.merge_jumps
|
220
|
-
s.update block_scope
|
221
|
-
nexts = block_scope[KatakataIrb::Scope::NEXT_RESULT]
|
222
|
-
breaks = block_scope[KatakataIrb::Scope::BREAK_RESULT]
|
223
|
-
if block_scope.terminated?
|
224
|
-
[KatakataIrb::Types::UnionType[*nexts], breaks]
|
225
|
-
else
|
226
|
-
[KatakataIrb::Types::UnionType[result, *nexts], breaks]
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
elsif has_block
|
231
|
-
call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
|
232
|
-
end
|
233
|
-
simulate_call receiver_type, node.name, args_types, kwargs_types, call_block_proc, scope
|
234
|
-
end
|
235
|
-
if node.call_operator == '&.'
|
236
|
-
result = scope.conditional { evaluate_method.call _1 }
|
237
|
-
if receiver_type.nillable?
|
238
|
-
KatakataIrb::Types::UnionType[result, KatakataIrb::Types::NIL]
|
239
|
-
else
|
240
|
-
result
|
241
|
-
end
|
242
|
-
else
|
243
|
-
evaluate_method.call scope
|
244
|
-
end
|
245
|
-
when Prism::AndNode, Prism::OrNode
|
246
|
-
left = evaluate node.left, scope
|
247
|
-
right = scope.conditional { evaluate node.right, _1 }
|
248
|
-
if node.operator == '&&'
|
249
|
-
KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
250
|
-
else
|
251
|
-
KatakataIrb::Types::UnionType[left, right]
|
252
|
-
end
|
253
|
-
when Prism::CallOperatorWriteNode, Prism::CallAndWriteNode, Prism::CallOrWriteNode
|
254
|
-
receiver_type = evaluate node.receiver, scope
|
255
|
-
args_types, kwargs_types, block_sym_node, has_block = evaluate_call_node_arguments node, scope
|
256
|
-
if block_sym_node
|
257
|
-
block_sym = block_sym_node.value
|
258
|
-
call_block_proc = ->(block_args, _self_type) do
|
259
|
-
block_receiver, *rest = block_args
|
260
|
-
block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_sym, rest, nil, nil, scope) : KatakataIrb::Types::OBJECT
|
261
|
-
end
|
262
|
-
elsif has_block
|
263
|
-
call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
|
264
|
-
end
|
265
|
-
method = node.write_name.to_s.delete_suffix('=')
|
266
|
-
left = simulate_call receiver_type, method, args_types, kwargs_types, call_block_proc, scope
|
267
|
-
if node.operator == '&&='
|
268
|
-
right = scope.conditional { evaluate node.value, _1 }
|
269
|
-
KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
270
|
-
elsif node.operator == '||='
|
271
|
-
right = scope.conditional { evaluate node.value, _1 }
|
272
|
-
KatakataIrb::Types::UnionType[left, right]
|
273
|
-
else
|
274
|
-
right = evaluate node.value, scope
|
275
|
-
simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
|
276
|
-
end
|
277
|
-
when Prism::ClassVariableOperatorWriteNode, Prism::InstanceVariableOperatorWriteNode, Prism::LocalVariableOperatorWriteNode, Prism::GlobalVariableOperatorWriteNode
|
278
|
-
left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
|
279
|
-
right = evaluate node.value, scope
|
280
|
-
scope[node.name.to_s] = simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
|
281
|
-
when Prism::ClassVariableAndWriteNode, Prism::InstanceVariableAndWriteNode, Prism::LocalVariableAndWriteNode, Prism::GlobalVariableAndWriteNode
|
282
|
-
right = scope.conditional { evaluate node.value, scope }
|
283
|
-
scope[node.name.to_s] = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
284
|
-
when Prism::ClassVariableOrWriteNode, Prism::InstanceVariableOrWriteNode, Prism::LocalVariableOrWriteNode, Prism::GlobalVariableOrWriteNode
|
285
|
-
left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
|
286
|
-
right = scope.conditional { evaluate node.value, scope }
|
287
|
-
scope[node.name.to_s] = KatakataIrb::Types::UnionType[left, right]
|
288
|
-
when Prism::ConstantOperatorWriteNode
|
289
|
-
left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
|
290
|
-
right = evaluate node.value, scope
|
291
|
-
scope[node.name.to_s] = simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
|
292
|
-
when Prism::ConstantAndWriteNode
|
293
|
-
right = scope.conditional { evaluate node.value, scope }
|
294
|
-
scope[node.name.to_s] = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
295
|
-
when Prism::ConstantOrWriteNode
|
296
|
-
left = scope[node.name.to_s] || KatakataIrb::Types::OBJECT
|
297
|
-
right = scope.conditional { evaluate node.value, scope }
|
298
|
-
scope[node.name.to_s] = KatakataIrb::Types::UnionType[left, right]
|
299
|
-
when Prism::ConstantPathOperatorWriteNode
|
300
|
-
left, receiver, _parent_module, name = evaluate_constant_node node.target, scope
|
301
|
-
right = evaluate node.value, scope
|
302
|
-
value = simulate_call left, node.operator, [right], nil, nil, scope, name_match: false
|
303
|
-
const_path_write receiver, name, value, scope
|
304
|
-
value
|
305
|
-
when Prism::ConstantPathAndWriteNode
|
306
|
-
_left, receiver, _parent_module, name = evaluate_constant_node node.target, scope
|
307
|
-
right = scope.conditional { evaluate node.value, scope }
|
308
|
-
value = KatakataIrb::Types::UnionType[right, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
309
|
-
const_path_write receiver, name, value, scope
|
310
|
-
value
|
311
|
-
when Prism::ConstantPathOrWriteNode
|
312
|
-
left, receiver, _parent_module, name = evaluate_constant_node node.target, scope
|
313
|
-
right = scope.conditional { evaluate node.value, scope }
|
314
|
-
value = KatakataIrb::Types::UnionType[left, right]
|
315
|
-
const_path_write receiver, name, value, scope
|
316
|
-
value
|
317
|
-
when Prism::ConstantPathWriteNode
|
318
|
-
receiver = evaluate node.target.parent, scope if node.target.parent
|
319
|
-
value = evaluate node.value, scope
|
320
|
-
const_path_write receiver, node.target.child.name.to_s, value, scope
|
321
|
-
value
|
322
|
-
when Prism::LambdaNode
|
323
|
-
local_table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::OBJECT] }
|
324
|
-
block_scope = KatakataIrb::Scope.new scope, { **local_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }
|
325
|
-
block_scope.conditional do |s|
|
326
|
-
assign_parameters node.parameters.parameters, s, [], {} if node.parameters&.parameters
|
327
|
-
evaluate node.body, s if node.body
|
328
|
-
end
|
329
|
-
block_scope.merge_jumps
|
330
|
-
scope.update block_scope
|
331
|
-
KatakataIrb::Types::ProcType.new
|
332
|
-
when Prism::LocalVariableWriteNode, Prism::GlobalVariableWriteNode, Prism::InstanceVariableWriteNode, Prism::ClassVariableWriteNode, Prism::ConstantWriteNode
|
333
|
-
scope[node.name.to_s] = evaluate node.value, scope
|
334
|
-
when Prism::MultiWriteNode
|
335
|
-
evaluated_receivers = {}
|
336
|
-
evaluate_multi_write_receiver node, scope, evaluated_receivers
|
337
|
-
value = (
|
338
|
-
if node.value.is_a? Prism::ArrayNode
|
339
|
-
if node.value.elements.any?(Prism::SplatNode)
|
340
|
-
evaluate node.value, scope
|
341
|
-
else
|
342
|
-
node.value.elements.map do |n|
|
343
|
-
evaluate n, scope
|
344
|
-
end
|
345
|
-
end
|
346
|
-
elsif node.value
|
347
|
-
evaluate node.value, scope
|
348
|
-
else
|
349
|
-
# For syntax invalid code like `(*a).b`
|
350
|
-
KatakataIrb::Types::NIL
|
351
|
-
end
|
352
|
-
)
|
353
|
-
evaluate_multi_write node, value, scope, evaluated_receivers
|
354
|
-
when Prism::IfNode, Prism::UnlessNode
|
355
|
-
evaluate node.predicate, scope
|
356
|
-
KatakataIrb::Types::UnionType[*scope.run_branches(
|
357
|
-
-> { node.statements ? evaluate(node.statements, _1) : KatakataIrb::Types::NIL },
|
358
|
-
-> { node.consequent ? evaluate(node.consequent, _1) : KatakataIrb::Types::NIL }
|
359
|
-
)]
|
360
|
-
when Prism::ElseNode
|
361
|
-
node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
|
362
|
-
when Prism::WhileNode, Prism::UntilNode
|
363
|
-
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }
|
364
|
-
evaluate node.predicate, inner_scope
|
365
|
-
if node.statements
|
366
|
-
inner_scope.conditional do |s|
|
367
|
-
evaluate node.statements, s
|
368
|
-
end
|
369
|
-
end
|
370
|
-
inner_scope.merge_jumps
|
371
|
-
scope.update inner_scope
|
372
|
-
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
373
|
-
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
374
|
-
when Prism::BreakNode, Prism::NextNode, Prism::ReturnNode
|
375
|
-
internal_key = (
|
376
|
-
case node
|
377
|
-
when Prism::BreakNode
|
378
|
-
KatakataIrb::Scope::BREAK_RESULT
|
379
|
-
when Prism::NextNode
|
380
|
-
KatakataIrb::Scope::NEXT_RESULT
|
381
|
-
when Prism::ReturnNode
|
382
|
-
KatakataIrb::Scope::RETURN_RESULT
|
383
|
-
end
|
384
|
-
)
|
385
|
-
jump_value = (
|
386
|
-
arguments = node.arguments&.arguments
|
387
|
-
if arguments.nil? || arguments.empty?
|
388
|
-
KatakataIrb::Types::NIL
|
389
|
-
elsif arguments.size == 1 && !arguments.first.is_a?(Prism::SplatNode)
|
390
|
-
evaluate arguments.first, scope
|
391
|
-
else
|
392
|
-
KatakataIrb::Types.array_of evaluate_list_splat_items(arguments, scope)
|
393
|
-
end
|
394
|
-
)
|
395
|
-
scope.terminate_with internal_key, jump_value
|
396
|
-
KatakataIrb::Types::NIL
|
397
|
-
when Prism::YieldNode
|
398
|
-
evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
|
399
|
-
KatakataIrb::Types::OBJECT
|
400
|
-
when Prism::RedoNode, Prism::RetryNode
|
401
|
-
scope.terminate
|
402
|
-
when Prism::ForwardingSuperNode
|
403
|
-
KatakataIrb::Types::OBJECT
|
404
|
-
when Prism::SuperNode
|
405
|
-
evaluate_list_splat_items node.arguments.arguments, scope if node.arguments
|
406
|
-
KatakataIrb::Types::OBJECT
|
407
|
-
when Prism::BeginNode
|
408
|
-
return_type = node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
|
409
|
-
if node.rescue_clause
|
410
|
-
if node.else_clause
|
411
|
-
return_types = scope.run_branches(
|
412
|
-
->{ evaluate node.rescue_clause, _1 },
|
413
|
-
->{ evaluate node.else_clause, _1 }
|
414
|
-
)
|
415
|
-
else
|
416
|
-
return_types = [
|
417
|
-
return_type,
|
418
|
-
scope.conditional { evaluate node.rescue_clause, _1 }
|
419
|
-
]
|
420
|
-
end
|
421
|
-
return_type = KatakataIrb::Types::UnionType[*return_types]
|
422
|
-
end
|
423
|
-
if node.ensure_clause&.statements
|
424
|
-
# ensure_clause is Prism::EnsureNode
|
425
|
-
evaluate node.ensure_clause.statements, scope
|
426
|
-
end
|
427
|
-
return_type
|
428
|
-
when Prism::RescueNode
|
429
|
-
run_rescue = lambda do |s|
|
430
|
-
if node.reference
|
431
|
-
error_classes_type = evaluate_list_splat_items node.exceptions, s
|
432
|
-
error_types = error_classes_type.types.filter_map do
|
433
|
-
KatakataIrb::Types::InstanceType.new _1.module_or_class if _1.is_a?(KatakataIrb::Types::SingletonType)
|
434
|
-
end
|
435
|
-
error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
|
436
|
-
error_type = KatakataIrb::Types::UnionType[*error_types]
|
437
|
-
case node.reference
|
438
|
-
when Prism::LocalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::ConstantTargetNode
|
439
|
-
s[node.reference.name.to_s] = error_type
|
440
|
-
when Prism::CallNode
|
441
|
-
evaluate node.reference, s
|
442
|
-
end
|
443
|
-
end
|
444
|
-
node.statements ? evaluate(node.statements, s) : KatakataIrb::Types::NIL
|
445
|
-
end
|
446
|
-
if node.consequent # begin; rescue A; rescue B; end
|
447
|
-
types = scope.run_branches(
|
448
|
-
run_rescue,
|
449
|
-
-> { evaluate node.consequent, _1 }
|
450
|
-
)
|
451
|
-
KatakataIrb::Types::UnionType[*types]
|
452
|
-
else
|
453
|
-
run_rescue.call scope
|
454
|
-
end
|
455
|
-
when Prism::RescueModifierNode
|
456
|
-
a = evaluate node.expression, scope
|
457
|
-
b = scope.conditional { evaluate node.rescue_expression, _1 }
|
458
|
-
KatakataIrb::Types::UnionType[a, b]
|
459
|
-
when Prism::SingletonClassNode
|
460
|
-
klass_types = evaluate(node.expression, scope).types.filter_map do |type|
|
461
|
-
KatakataIrb::Types::SingletonType.new type.klass if type.is_a? KatakataIrb::Types::InstanceType
|
462
|
-
end
|
463
|
-
klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
|
464
|
-
table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
|
465
|
-
sclass_scope = KatakataIrb::Scope.new(
|
466
|
-
scope,
|
467
|
-
{ **table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
|
468
|
-
trace_ivar: false,
|
469
|
-
trace_lvar: false,
|
470
|
-
self_type: KatakataIrb::Types::UnionType[*klass_types]
|
471
|
-
)
|
472
|
-
result = node.body ? evaluate(node.body, sclass_scope) : KatakataIrb::Types::NIL
|
473
|
-
scope.update sclass_scope
|
474
|
-
result
|
475
|
-
when Prism::ModuleNode, Prism::ClassNode
|
476
|
-
unless node.constant_path.is_a?(Prism::ConstantReadNode) || node.constant_path.is_a?(Prism::ConstantPathNode)
|
477
|
-
# Syntax error code, example: `module a.b; end`
|
478
|
-
return KatakataIrb::Types::NIL
|
479
|
-
end
|
480
|
-
const_type, _receiver, parent_module, name = evaluate_constant_node node.constant_path, scope
|
481
|
-
if node.is_a? Prism::ModuleNode
|
482
|
-
module_types = const_type.types.select { _1.is_a?(KatakataIrb::Types::SingletonType) && !_1.module_or_class.is_a?(Class) }
|
483
|
-
module_types << KatakataIrb::Types::MODULE if module_types.empty?
|
484
|
-
else
|
485
|
-
select_class_type = -> { _1.is_a?(KatakataIrb::Types::SingletonType) && _1.module_or_class.is_a?(Class) }
|
486
|
-
module_types = const_type.types.select(&select_class_type)
|
487
|
-
module_types += evaluate(node.superclass, scope).types.select(&select_class_type) if node.superclass
|
488
|
-
module_types << KatakataIrb::Types::CLASS if module_types.empty?
|
489
|
-
end
|
490
|
-
return KatakataIrb::Types::NIL unless node.body
|
491
|
-
|
492
|
-
table = node.locals.to_h { [_1.to_s, KatakataIrb::Types::NIL] }
|
493
|
-
if parent_module.is_a?(Module) || parent_module.nil?
|
494
|
-
value = parent_module.const_get name if parent_module&.const_defined?(name)
|
495
|
-
unless value
|
496
|
-
value_type = scope[name]
|
497
|
-
value = value_type.module_or_class if value_type.is_a? KatakataIrb::Types::SingletonType
|
498
|
-
end
|
499
|
-
|
500
|
-
if value.is_a? Module
|
501
|
-
nesting = [value, []]
|
502
|
-
else
|
503
|
-
if parent_module
|
504
|
-
nesting = [parent_module, [name]]
|
505
|
-
else
|
506
|
-
parent_nesting, parent_path = scope.module_nesting.first
|
507
|
-
nesting = [parent_nesting, parent_path + [name]]
|
508
|
-
end
|
509
|
-
nesting_key = [nesting[0].__id__, nesting[1]].join('::')
|
510
|
-
nesting_value = node.is_a?(Prism::ModuleNode) ? KatakataIrb::Types::MODULE : KatakataIrb::Types::CLASS
|
511
|
-
end
|
512
|
-
else
|
513
|
-
# parent_module == :unknown
|
514
|
-
# TODO: dummy module
|
515
|
-
end
|
516
|
-
module_scope = KatakataIrb::Scope.new(
|
517
|
-
scope,
|
518
|
-
{ **table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
|
519
|
-
trace_cvar: false,
|
520
|
-
trace_ivar: false,
|
521
|
-
trace_lvar: false,
|
522
|
-
self_type: KatakataIrb::Types::UnionType[*module_types],
|
523
|
-
nesting: nesting
|
524
|
-
)
|
525
|
-
module_scope[nesting_key] = nesting_value if nesting_value
|
526
|
-
result = evaluate(node.body, module_scope)
|
527
|
-
scope.update module_scope
|
528
|
-
result
|
529
|
-
when Prism::ForNode
|
530
|
-
node.statements
|
531
|
-
collection = evaluate node.collection, scope
|
532
|
-
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }
|
533
|
-
ary_type = simulate_call collection, :to_ary, [], nil, nil, nil, name_match: false
|
534
|
-
element_types = ary_type.types.filter_map do |ary|
|
535
|
-
ary.params[:Elem] if ary.is_a?(KatakataIrb::Types::InstanceType) && ary.klass == Array
|
536
|
-
end
|
537
|
-
element_type = KatakataIrb::Types::UnionType[*element_types]
|
538
|
-
inner_scope.conditional do |s|
|
539
|
-
evaluate_write node.index, element_type, s, nil
|
540
|
-
evaluate node.statements, s if node.statements
|
541
|
-
end
|
542
|
-
inner_scope.merge_jumps
|
543
|
-
scope.update inner_scope
|
544
|
-
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
545
|
-
breaks ? KatakataIrb::Types::UnionType[breaks, collection] : collection
|
546
|
-
when Prism::CaseNode
|
547
|
-
target = evaluate(node.predicate, scope) if node.predicate
|
548
|
-
# TODO
|
549
|
-
branches = node.conditions.map do |condition|
|
550
|
-
->(s) { evaluate_case_match target, condition, s }
|
551
|
-
end
|
552
|
-
if node.consequent
|
553
|
-
branches << ->(s) { evaluate node.consequent, s }
|
554
|
-
elsif node.conditions.any? { _1.is_a? Prism::WhenNode }
|
555
|
-
branches << ->(s) { KatakataIrb::Types::NIL }
|
556
|
-
end
|
557
|
-
KatakataIrb::Types::UnionType[*scope.run_branches(*branches)]
|
558
|
-
when Prism::MatchRequiredNode
|
559
|
-
value_type = evaluate node.value, scope
|
560
|
-
evaluate_match_pattern value_type, node.pattern, scope
|
561
|
-
KatakataIrb::Types::NIL # void value
|
562
|
-
when Prism::MatchPredicateNode
|
563
|
-
value_type = evaluate node.value, scope
|
564
|
-
scope.conditional { evaluate_match_pattern value_type, node.pattern, _1 }
|
565
|
-
KatakataIrb::Types::BOOLEAN
|
566
|
-
when Prism::RangeNode
|
567
|
-
beg_type = evaluate node.left, scope if node.left
|
568
|
-
end_type = evaluate node.right, scope if node.right
|
569
|
-
elem = (KatakataIrb::Types::UnionType[*[beg_type, end_type].compact]).nonnillable
|
570
|
-
KatakataIrb::Types::InstanceType.new Range, Elem: elem
|
571
|
-
when Prism::DefinedNode
|
572
|
-
scope.conditional { evaluate node.value, _1 }
|
573
|
-
KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
|
574
|
-
when Prism::FlipFlopNode
|
575
|
-
scope.conditional { evaluate node.left, _1 } if node.left
|
576
|
-
scope.conditional { evaluate node.right, _1 } if node.right
|
577
|
-
KatakataIrb::Types::BOOLEAN
|
578
|
-
when Prism::MultiTargetNode
|
579
|
-
# Raw MultiTargetNode, incomplete code like `a,b`, `*a`.
|
580
|
-
evaluate_multi_write_receiver node, scope, nil
|
581
|
-
KatakataIrb::Types::NIL
|
582
|
-
when Prism::ImplicitNode
|
583
|
-
evaluate node.value, scope
|
584
|
-
when Prism::MatchWriteNode
|
585
|
-
# /(?<a>)(?<b>)/ =~ string
|
586
|
-
evaluate node.call, scope
|
587
|
-
node.locals.each { scope[_1.to_s] = KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL] }
|
588
|
-
KatakataIrb::Types::BOOLEAN
|
589
|
-
when Prism::MatchLastLineNode
|
590
|
-
KatakataIrb::Types::BOOLEAN
|
591
|
-
when Prism::InterpolatedMatchLastLineNode
|
592
|
-
node.parts.each { evaluate _1, scope }
|
593
|
-
KatakataIrb::Types::BOOLEAN
|
594
|
-
when Prism::PreExecutionNode, Prism::PostExecutionNode
|
595
|
-
node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
|
596
|
-
when Prism::AliasMethodNode, Prism::AliasGlobalVariableNode, Prism::UndefNode, Prism::MissingNode
|
597
|
-
# do nothing
|
598
|
-
KatakataIrb::Types::NIL
|
599
|
-
else
|
600
|
-
KatakataIrb.log_puts
|
601
|
-
KatakataIrb.log_puts :NOMATCH
|
602
|
-
KatakataIrb.log_puts node.inspect
|
603
|
-
KatakataIrb::Types::NIL
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
def evaluate_call_node_arguments(call_node, scope)
|
608
|
-
# call_node.arguments is Prism::ArgumentsNode
|
609
|
-
arguments = call_node.arguments&.arguments&.dup || []
|
610
|
-
block_arg = call_node.block.expression if call_node.respond_to?(:block) && call_node.block.is_a?(Prism::BlockArgumentNode)
|
611
|
-
kwargs = arguments.pop.elements if arguments.last.is_a?(Prism::KeywordHashNode)
|
612
|
-
args_types = arguments.map do |arg|
|
613
|
-
case arg
|
614
|
-
when Prism::ForwardingArgumentsNode
|
615
|
-
# `f(a, ...)` treat like splat
|
616
|
-
nil
|
617
|
-
when Prism::SplatNode
|
618
|
-
evaluate arg.expression, scope
|
619
|
-
nil # TODO: splat
|
620
|
-
else
|
621
|
-
evaluate arg, scope
|
622
|
-
end
|
623
|
-
end
|
624
|
-
if kwargs
|
625
|
-
kwargs_types = kwargs.map do |arg|
|
626
|
-
case arg
|
627
|
-
when Prism::AssocNode
|
628
|
-
if arg.key.is_a?(Prism::SymbolNode)
|
629
|
-
[arg.key.value, evaluate(arg.value, scope)]
|
630
|
-
else
|
631
|
-
evaluate arg.key, scope
|
632
|
-
evaluate arg.value, scope
|
633
|
-
nil
|
634
|
-
end
|
635
|
-
when Prism::AssocSplatNode
|
636
|
-
evaluate arg.value, scope
|
637
|
-
nil
|
638
|
-
end
|
639
|
-
end.compact.to_h
|
640
|
-
end
|
641
|
-
if block_arg.is_a? Prism::SymbolNode
|
642
|
-
block_sym_node = block_arg
|
643
|
-
elsif block_arg
|
644
|
-
evaluate block_arg, scope
|
645
|
-
end
|
646
|
-
[args_types, kwargs_types, block_sym_node, !!block_arg]
|
647
|
-
end
|
648
|
-
|
649
|
-
def const_path_write(receiver, name, value, scope)
|
650
|
-
if receiver # receiver::A = value
|
651
|
-
singleton_type = receiver.types.find { _1.is_a? KatakataIrb::Types::SingletonType }
|
652
|
-
scope.set_const singleton_type.module_or_class, name, value if singleton_type
|
653
|
-
else # ::A = value
|
654
|
-
scope.set_const Object, name, value
|
655
|
-
end
|
656
|
-
end
|
657
|
-
|
658
|
-
def assign_required_parameter(node, value, scope)
|
659
|
-
case node
|
660
|
-
when Prism::RequiredParameterNode
|
661
|
-
scope[node.name.to_s] = value || KatakataIrb::Types::OBJECT
|
662
|
-
when Prism::RequiredDestructuredParameterNode
|
663
|
-
values = value ? sized_splat(value, :to_ary, node.parameters.size) : []
|
664
|
-
node.parameters.zip values do |n, v|
|
665
|
-
assign_required_parameter n, v, scope
|
666
|
-
end
|
667
|
-
when Prism::SplatNode
|
668
|
-
splat_value = value ? KatakataIrb::Types.array_of(value) : KatakataIrb::Types::ARRAY
|
669
|
-
assign_required_parameter node.expression, splat_value, scope
|
670
|
-
end
|
671
|
-
end
|
672
|
-
|
673
|
-
def evaluate_constant_node(node, scope)
|
674
|
-
case node
|
675
|
-
when Prism::ConstantPathNode
|
676
|
-
name = node.child.name.to_s
|
677
|
-
if node.parent
|
678
|
-
receiver = evaluate node.parent, scope
|
679
|
-
if receiver.is_a? KatakataIrb::Types::SingletonType
|
680
|
-
parent_module = receiver.module_or_class
|
681
|
-
end
|
682
|
-
else
|
683
|
-
parent_module = Object
|
684
|
-
end
|
685
|
-
if parent_module
|
686
|
-
type = scope.get_const(parent_module, [name]) || KatakataIrb::Types::NIL
|
687
|
-
else
|
688
|
-
parent_module = :unknown
|
689
|
-
type = KatakataIrb::Types::NIL
|
690
|
-
end
|
691
|
-
when Prism::ConstantReadNode
|
692
|
-
name = node.name.to_s
|
693
|
-
type = scope[name]
|
694
|
-
end
|
695
|
-
[type, receiver, parent_module, name]
|
696
|
-
end
|
697
|
-
|
698
|
-
|
699
|
-
def assign_parameters(node, scope, args, kwargs)
|
700
|
-
args = args.dup
|
701
|
-
kwargs = kwargs.dup
|
702
|
-
size = node.requireds.size + node.optionals.size + (node.rest ? 1 : 0) + node.posts.size
|
703
|
-
args = sized_splat(args.first, :to_ary, size) if size >= 2 && args.size == 1
|
704
|
-
reqs = args.shift node.requireds.size
|
705
|
-
if node.rest
|
706
|
-
# node.rest.class is Prism::RestParameterNode
|
707
|
-
posts = []
|
708
|
-
opts = args.shift node.optionals.size
|
709
|
-
rest = args
|
710
|
-
else
|
711
|
-
posts = args.pop node.posts.size
|
712
|
-
opts = args
|
713
|
-
rest = []
|
714
|
-
end
|
715
|
-
node.requireds.zip reqs do |n, v|
|
716
|
-
assign_required_parameter n, v, scope
|
717
|
-
end
|
718
|
-
node.optionals.zip opts do |n, v|
|
719
|
-
# n is Prism::OptionalParameterNode
|
720
|
-
values = [v]
|
721
|
-
values << evaluate(n.value, scope) if n.value
|
722
|
-
scope[n.name.to_s] = KatakataIrb::Types::UnionType[*values.compact]
|
723
|
-
end
|
724
|
-
node.posts.zip posts do |n, v|
|
725
|
-
assign_required_parameter n, v, scope
|
726
|
-
end
|
727
|
-
if node.rest&.name
|
728
|
-
# node.rest is Prism::RestParameterNode
|
729
|
-
scope[node.rest.name.to_s] = KatakataIrb::Types.array_of(*rest)
|
730
|
-
end
|
731
|
-
node.keywords.each do |n|
|
732
|
-
# n is Prism::KeywordParameterNode
|
733
|
-
name = n.name.to_s.delete(':')
|
734
|
-
values = [kwargs.delete(name)]
|
735
|
-
values << evaluate(n.value, scope) if n.value
|
736
|
-
scope[name] = KatakataIrb::Types::UnionType[*values.compact]
|
737
|
-
end
|
738
|
-
# node.keyword_rest is Prism::KeywordRestParameterNode or Prism::ForwardingParameterNode or Prism::NoKeywordsParameterNode
|
739
|
-
if node.keyword_rest.is_a?(Prism::KeywordRestParameterNode) && node.keyword_rest.name
|
740
|
-
scope[node.keyword_rest.name.to_s] = KatakataIrb::Types::InstanceType.new(Hash, K: KatakataIrb::Types::SYMBOL, V: KatakataIrb::Types::UnionType[*kwargs.values])
|
741
|
-
end
|
742
|
-
if node.block&.name
|
743
|
-
# node.block is Prism::BlockParameterNode
|
744
|
-
scope[node.block.name.to_s] = KatakataIrb::Types::PROC
|
745
|
-
end
|
746
|
-
end
|
747
|
-
|
748
|
-
def assign_numbered_parameters(numbered_parameters, scope, args, _kwargs)
|
749
|
-
return if numbered_parameters.empty?
|
750
|
-
max_num = numbered_parameters.map { _1[1].to_i }.max
|
751
|
-
if max_num == 1
|
752
|
-
if args.size == 0
|
753
|
-
scope['_1'] = KatakataIrb::Types::NIL
|
754
|
-
elsif args.size == 1
|
755
|
-
scope['_1'] = args.first
|
756
|
-
else
|
757
|
-
scope['_1'] = KatakataIrb::Types.array_of(*args)
|
758
|
-
end
|
759
|
-
else
|
760
|
-
args = sized_splat(args.first, :to_ary, max_num) if args.size == 1
|
761
|
-
numbered_parameters.each do |name|
|
762
|
-
index = name[1].to_i - 1
|
763
|
-
scope[name] = args[index] || KatakataIrb::Types::NIL
|
764
|
-
end
|
765
|
-
end
|
766
|
-
end
|
767
|
-
|
768
|
-
def evaluate_case_match(target, node, scope)
|
769
|
-
case node
|
770
|
-
when Prism::WhenNode
|
771
|
-
node.conditions.each { evaluate _1, scope }
|
772
|
-
node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
|
773
|
-
when Prism::InNode
|
774
|
-
pattern = node.pattern
|
775
|
-
if pattern in Prism::IfNode | Prism::UnlessNode
|
776
|
-
cond_node = pattern.predicate
|
777
|
-
pattern = pattern.statements.body.first
|
778
|
-
end
|
779
|
-
evaluate_match_pattern(target, pattern, scope)
|
780
|
-
evaluate cond_node, scope if cond_node # TODO: conditional branch
|
781
|
-
node.statements ? evaluate(node.statements, scope) : KatakataIrb::Types::NIL
|
782
|
-
end
|
783
|
-
end
|
784
|
-
|
785
|
-
def evaluate_match_pattern(value, pattern, scope)
|
786
|
-
# TODO: scope.terminate_with KatakataIrb::Scope::PATTERNMATCH_BREAK, KatakataIrb::Types::NIL
|
787
|
-
case pattern
|
788
|
-
when Prism::FindPatternNode
|
789
|
-
# TODO
|
790
|
-
evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.left, scope
|
791
|
-
pattern.requireds.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
|
792
|
-
evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.right, scope
|
793
|
-
when Prism::ArrayPatternNode
|
794
|
-
# TODO
|
795
|
-
pattern.requireds.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
|
796
|
-
evaluate_match_pattern KatakataIrb::Types::OBJECT, pattern.rest, scope if pattern.rest
|
797
|
-
pattern.posts.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
|
798
|
-
KatakataIrb::Types::ARRAY
|
799
|
-
when Prism::HashPatternNode
|
800
|
-
# TODO
|
801
|
-
pattern.assocs.each { evaluate_match_pattern KatakataIrb::Types::OBJECT, _1, scope }
|
802
|
-
KatakataIrb::Types::HASH
|
803
|
-
when Prism::AssocNode
|
804
|
-
evaluate_match_pattern value, pattern.value, scope if pattern.value
|
805
|
-
KatakataIrb::Types::OBJECT
|
806
|
-
when Prism::AssocSplatNode
|
807
|
-
# TODO
|
808
|
-
evaluate_match_pattern KatakataIrb::Types::HASH, pattern.value, scope
|
809
|
-
KatakataIrb::Types::OBJECT
|
810
|
-
when Prism::PinnedVariableNode
|
811
|
-
evaluate pattern.variable, scope
|
812
|
-
when Prism::PinnedExpressionNode
|
813
|
-
evaluate pattern.expression, scope
|
814
|
-
when Prism::LocalVariableTargetNode
|
815
|
-
scope[pattern.name.to_s] = value
|
816
|
-
when Prism::AlternationPatternNode
|
817
|
-
KatakataIrb::Types::UnionType[evaluate_match_pattern(value, pattern.left, scope), evaluate_match_pattern(value, pattern.right, scope)]
|
818
|
-
when Prism::CapturePatternNode
|
819
|
-
capture_type = class_or_value_to_instance evaluate_match_pattern(value, pattern.value, scope)
|
820
|
-
value = capture_type unless capture_type.types.empty? || capture_type.types == [KatakataIrb::Types::OBJECT]
|
821
|
-
evaluate_match_pattern value, pattern.target, scope
|
822
|
-
when Prism::SplatNode
|
823
|
-
value = KatakataIrb::Types.array_of value
|
824
|
-
evaluate_match_pattern value, pattern.expression, scope if pattern.expression
|
825
|
-
value
|
826
|
-
else
|
827
|
-
# literal node
|
828
|
-
type = evaluate(pattern, scope)
|
829
|
-
class_or_value_to_instance(type)
|
830
|
-
end
|
831
|
-
end
|
832
|
-
|
833
|
-
def class_or_value_to_instance(type)
|
834
|
-
instance_types = type.types.map do |t|
|
835
|
-
t.is_a?(KatakataIrb::Types::SingletonType) ? KatakataIrb::Types::InstanceType.new(t.module_or_class) : t
|
836
|
-
end
|
837
|
-
KatakataIrb::Types::UnionType[*instance_types]
|
838
|
-
end
|
839
|
-
|
840
|
-
def evaluate_write(node, value, scope, evaluated_receivers)
|
841
|
-
case node
|
842
|
-
when Prism::MultiTargetNode
|
843
|
-
evaluate_multi_write node, value, scope, evaluated_receivers
|
844
|
-
when Prism::CallNode
|
845
|
-
evaluated_receivers&.[](node.receiver) || evaluate(node.receiver, scope) if node.receiver
|
846
|
-
when Prism::SplatNode
|
847
|
-
evaluate_write node.expression, KatakataIrb::Types.array_of(value), scope, evaluated_receivers
|
848
|
-
when Prism::LocalVariableTargetNode, Prism::GlobalVariableTargetNode, Prism::InstanceVariableTargetNode, Prism::ClassVariableTargetNode, Prism::ConstantTargetNode
|
849
|
-
scope[node.name.to_s] = value
|
850
|
-
when Prism::ConstantPathTargetNode
|
851
|
-
receiver = evaluated_receivers&.[](node.parent) || evaluate(node.parent, scope) if node.parent
|
852
|
-
const_path_write receiver, node.child.name.to_s, value, scope
|
853
|
-
value
|
854
|
-
end
|
855
|
-
end
|
856
|
-
|
857
|
-
def evaluate_multi_write(node, values, scope, evaluated_receivers)
|
858
|
-
values = sized_splat values, :to_ary, node.targets.size unless values.is_a? Array
|
859
|
-
splat_index = node.targets.find_index { _1.is_a? Prism::SplatNode }
|
860
|
-
if splat_index
|
861
|
-
pre_targets = node.targets[0...splat_index]
|
862
|
-
splat_target = node.targets[splat_index]
|
863
|
-
post_targets = node.targets[splat_index + 1..]
|
864
|
-
pre_values = values.shift pre_targets.size
|
865
|
-
post_values = values.pop post_targets.size
|
866
|
-
splat_value = KatakataIrb::Types::UnionType[*values]
|
867
|
-
zips = pre_targets.zip(pre_values) + [[splat_target, splat_value]] + post_targets.zip(post_values)
|
868
|
-
else
|
869
|
-
zips = node.targets.zip(values)
|
870
|
-
end
|
871
|
-
zips.each do |target, value|
|
872
|
-
evaluate_write target, value || KatakataIrb::Types::NIL, scope, evaluated_receivers
|
873
|
-
end
|
874
|
-
end
|
875
|
-
|
876
|
-
def evaluate_multi_write_receiver(node, scope, evaluated_receivers)
|
877
|
-
case node
|
878
|
-
when Prism::MultiWriteNode, Prism::MultiTargetNode
|
879
|
-
node.targets.each { evaluate_multi_write_receiver _1, scope, evaluated_receivers }
|
880
|
-
when Prism::CallNode
|
881
|
-
if node.receiver
|
882
|
-
receiver = evaluate(node.receiver, scope)
|
883
|
-
evaluated_receivers[node.receiver] = receiver if evaluated_receivers
|
884
|
-
end
|
885
|
-
if node.arguments
|
886
|
-
node.arguments.arguments&.each do |arg|
|
887
|
-
if arg.is_a? Prism::SplatNode
|
888
|
-
evaluate arg.expression, scope
|
889
|
-
else
|
890
|
-
evaluate arg, scope
|
891
|
-
end
|
892
|
-
end
|
893
|
-
end
|
894
|
-
when Prism::SplatNode
|
895
|
-
evaluate_multi_write_receiver node.expression, scope, evaluated_receivers if node.expression
|
896
|
-
end
|
897
|
-
end
|
898
|
-
|
899
|
-
def evaluate_list_splat_items(list, scope)
|
900
|
-
items = list.flat_map do |node|
|
901
|
-
if node.is_a? Prism::SplatNode
|
902
|
-
splat = evaluate node.expression, scope
|
903
|
-
array_elem, non_array = partition_to_array splat.nonnillable, :to_a
|
904
|
-
[*array_elem, *non_array]
|
905
|
-
else
|
906
|
-
evaluate node, scope
|
907
|
-
end
|
908
|
-
end.uniq
|
909
|
-
KatakataIrb::Types::UnionType[*items]
|
910
|
-
end
|
911
|
-
|
912
|
-
def sized_splat(value, method, size)
|
913
|
-
array_elem, non_array = partition_to_array value, method
|
914
|
-
values = [KatakataIrb::Types::UnionType[*array_elem, *non_array]]
|
915
|
-
values += [array_elem] * (size - 1) if array_elem && size >= 1
|
916
|
-
values
|
917
|
-
end
|
918
|
-
|
919
|
-
def partition_to_array(value, method)
|
920
|
-
arrays, non_arrays = value.types.partition { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
|
921
|
-
non_arrays.select! do |type|
|
922
|
-
to_array_result = simulate_call type, method, [], nil, nil, nil, name_match: false
|
923
|
-
if to_array_result.is_a?(KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
|
924
|
-
arrays << to_array_result
|
925
|
-
false
|
926
|
-
else
|
927
|
-
true
|
928
|
-
end
|
929
|
-
end
|
930
|
-
array_elem = arrays.empty? ? nil : KatakataIrb::Types::UnionType[*arrays.map { _1.params[:Elem] || KatakataIrb::Types::OBJECT }]
|
931
|
-
non_array = non_arrays.empty? ? nil : KatakataIrb::Types::UnionType[*non_arrays]
|
932
|
-
[array_elem, non_array]
|
933
|
-
end
|
934
|
-
|
935
|
-
def simulate_call(receiver, method_name, args, kwargs, block, scope, name_match: true)
|
936
|
-
methods = KatakataIrb::Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
|
937
|
-
block_called = false
|
938
|
-
type_breaks = methods.map do |method, given_params, method_params|
|
939
|
-
receiver_vars = (receiver in KatakataIrb::Types::InstanceType) ? receiver.params : {}
|
940
|
-
free_vars = method.type.free_variables - receiver_vars.keys.to_set
|
941
|
-
vars = receiver_vars.merge KatakataIrb::Types.match_free_variables(free_vars, method_params, given_params)
|
942
|
-
if block && method.block
|
943
|
-
params_type = method.block.type.required_positionals.map do |func_param|
|
944
|
-
KatakataIrb::Types.from_rbs_type func_param.type, receiver, vars
|
945
|
-
end
|
946
|
-
self_type = KatakataIrb::Types.from_rbs_type method.block.self_type, receiver, vars if method.block.self_type
|
947
|
-
block_response, breaks = block.call params_type, self_type
|
948
|
-
block_called = true
|
949
|
-
vars.merge! KatakataIrb::Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
|
950
|
-
end
|
951
|
-
if KatakataIrb::Types.method_return_bottom?(method)
|
952
|
-
[nil, breaks]
|
953
|
-
else
|
954
|
-
[KatakataIrb::Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
|
955
|
-
end
|
956
|
-
end
|
957
|
-
block&.call [], nil unless block_called
|
958
|
-
terminates = !type_breaks.empty? && type_breaks.map(&:first).all?(&:nil?)
|
959
|
-
types = type_breaks.map(&:first).compact
|
960
|
-
breaks = type_breaks.map(&:last).compact
|
961
|
-
types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
|
962
|
-
|
963
|
-
if method_name.to_sym == :new
|
964
|
-
receiver.types.each do |type|
|
965
|
-
if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
966
|
-
types << KatakataIrb::Types::InstanceType.new(type.module_or_class)
|
967
|
-
end
|
968
|
-
end
|
969
|
-
end
|
970
|
-
scope&.terminate if terminates && breaks.empty?
|
971
|
-
KatakataIrb::Types::UnionType[*types, *breaks]
|
972
|
-
end
|
973
|
-
|
974
|
-
def evaluate_program(program, scope)
|
975
|
-
# statements.body[0] is local variable assign code
|
976
|
-
program.statements.body[1..].each do |statement|
|
977
|
-
evaluate statement, scope
|
978
|
-
end
|
979
|
-
end
|
980
|
-
|
981
|
-
def self.calculate_target_type_scope(binding, parents, target)
|
982
|
-
dig_targets = DigTarget.new(parents, target) do |type, scope|
|
983
|
-
return type, scope
|
984
|
-
end
|
985
|
-
program = parents.first
|
986
|
-
scope = KatakataIrb::Scope.from_binding(binding, program.locals)
|
987
|
-
new(dig_targets).evaluate_program program, scope
|
988
|
-
[KatakataIrb::Types::NIL, scope]
|
989
|
-
end
|
990
|
-
end
|