katakata_irb 0.1.12 → 0.2.1
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/Gemfile +1 -0
- data/katakata_irb.gemspec +1 -0
- data/lib/katakata_irb/completor.rb +166 -218
- data/lib/katakata_irb/scope.rb +224 -81
- data/lib/katakata_irb/type_analyzer.rb +1168 -0
- data/lib/katakata_irb/types.rb +25 -11
- data/lib/katakata_irb/version.rb +1 -1
- data/lib/katakata_irb.rb +2 -0
- metadata +17 -4
- data/lib/katakata_irb/nesting_parser.rb +0 -257
- data/lib/katakata_irb/type_simulator.rb +0 -995
@@ -1,995 +0,0 @@
|
|
1
|
-
require 'ripper'
|
2
|
-
require 'set'
|
3
|
-
require_relative 'types'
|
4
|
-
require_relative 'scope'
|
5
|
-
|
6
|
-
class KatakataIrb::TypeSimulator
|
7
|
-
class DigTarget
|
8
|
-
def initialize(parents, receiver, &block)
|
9
|
-
@dig_ids = parents.to_h { [_1.__id__, true] }
|
10
|
-
@target_id = receiver.__id__
|
11
|
-
@block = block
|
12
|
-
end
|
13
|
-
|
14
|
-
def dig?(node) = @dig_ids[node.__id__]
|
15
|
-
def target?(node) = @target_id == node.__id__
|
16
|
-
def resolve(type, scope)
|
17
|
-
@block.call type, scope
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module LexerElemMatcher
|
22
|
-
refine Ripper::Lexer::Elem do
|
23
|
-
def deconstruct_keys(_keys)
|
24
|
-
{
|
25
|
-
tok: tok,
|
26
|
-
event: event,
|
27
|
-
label: state.allbits?(Ripper::EXPR_LABEL),
|
28
|
-
beg: state.allbits?(Ripper::EXPR_BEG),
|
29
|
-
dot: state.allbits?(Ripper::EXPR_DOT)
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
using LexerElemMatcher
|
35
|
-
|
36
|
-
OBJECT_METHODS = {
|
37
|
-
to_s: KatakataIrb::Types::STRING,
|
38
|
-
to_str: KatakataIrb::Types::STRING,
|
39
|
-
to_a: KatakataIrb::Types::ARRAY,
|
40
|
-
to_ary: KatakataIrb::Types::ARRAY,
|
41
|
-
to_h: KatakataIrb::Types::HASH,
|
42
|
-
to_hash: KatakataIrb::Types::HASH,
|
43
|
-
to_i: KatakataIrb::Types::INTEGER,
|
44
|
-
to_int: KatakataIrb::Types::INTEGER,
|
45
|
-
to_f: KatakataIrb::Types::FLOAT,
|
46
|
-
to_c: KatakataIrb::Types::COMPLEX,
|
47
|
-
to_r: KatakataIrb::Types::RATIONAL
|
48
|
-
}
|
49
|
-
|
50
|
-
def initialize(dig_targets)
|
51
|
-
@dig_targets = dig_targets
|
52
|
-
end
|
53
|
-
|
54
|
-
def simulate_evaluate(sexp, scope, case_target: nil)
|
55
|
-
result = simulate_evaluate_inner(sexp, scope, case_target: case_target)
|
56
|
-
@dig_targets.resolve result, scope if @dig_targets.target?(sexp)
|
57
|
-
result
|
58
|
-
end
|
59
|
-
|
60
|
-
def simulate_evaluate_inner(sexp, scope, case_target: nil)
|
61
|
-
case sexp
|
62
|
-
in [:program, statements]
|
63
|
-
statements.map { simulate_evaluate _1, scope }.last
|
64
|
-
in [:def | :defs,]
|
65
|
-
sexp in [:def, _method_name_exp, params, body_stmt]
|
66
|
-
sexp in [:defs, receiver_exp, _dot_exp, _method_name_exp, params, body_stmt]
|
67
|
-
if receiver_exp
|
68
|
-
receiver_exp in [:paren, receiver_exp]
|
69
|
-
self_type = simulate_evaluate receiver_exp, scope
|
70
|
-
else
|
71
|
-
current_self_types = scope.self_type.types
|
72
|
-
self_types = current_self_types.map do |type|
|
73
|
-
if type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
74
|
-
KatakataIrb::Types::InstanceType.new type.module_or_class
|
75
|
-
else
|
76
|
-
type
|
77
|
-
end
|
78
|
-
end
|
79
|
-
self_type = KatakataIrb::Types::UnionType[*self_types]
|
80
|
-
end
|
81
|
-
if @dig_targets.dig? sexp
|
82
|
-
params in [:paren, params]
|
83
|
-
params ||= [:params, nil, nil, nil, nil, nil, nil, nil] # params might be nil in ruby 3.0
|
84
|
-
params_table = extract_param_names(params).to_h { [_1, KatakataIrb::Types::NIL] }
|
85
|
-
method_scope = KatakataIrb::Scope.new(
|
86
|
-
scope,
|
87
|
-
{ **params_table, KatakataIrb::Scope::SELF => self_type, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
|
88
|
-
trace_lvar: false
|
89
|
-
)
|
90
|
-
evaluate_assign_params params, [], method_scope
|
91
|
-
method_scope.conditional { evaluate_param_defaults params, _1 }
|
92
|
-
simulate_evaluate body_stmt, method_scope
|
93
|
-
method_scope.merge_jumps
|
94
|
-
scope.update method_scope
|
95
|
-
end
|
96
|
-
KatakataIrb::Types::SYMBOL
|
97
|
-
in [:@int,]
|
98
|
-
KatakataIrb::Types::INTEGER
|
99
|
-
in [:@float,]
|
100
|
-
KatakataIrb::Types::FLOAT
|
101
|
-
in [:@rational,]
|
102
|
-
KatakataIrb::Types::RATIONAL
|
103
|
-
in [:@imaginary,]
|
104
|
-
KatakataIrb::Types::COMPLEX
|
105
|
-
in [:@tstring_content,]
|
106
|
-
KatakataIrb::Types::STRING
|
107
|
-
in [:symbol_literal,]
|
108
|
-
KatakataIrb::Types::SYMBOL
|
109
|
-
in [:dyna_symbol, [:string_content, *statements]]
|
110
|
-
statements.each { simulate_evaluate _1, scope }
|
111
|
-
KatakataIrb::Types::SYMBOL
|
112
|
-
in [:@CHAR,]
|
113
|
-
KatakataIrb::Types::STRING
|
114
|
-
in [:@backref,]
|
115
|
-
KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
|
116
|
-
in [:string_literal, [:string_content, *statements]]
|
117
|
-
statements.each { simulate_evaluate _1, scope }
|
118
|
-
KatakataIrb::Types::STRING
|
119
|
-
in [:xstring_literal, statements]
|
120
|
-
statements.each { simulate_evaluate _1, scope }
|
121
|
-
KatakataIrb::Types::STRING
|
122
|
-
in [:string_embexpr, statements]
|
123
|
-
statements.each { simulate_evaluate _1, scope }
|
124
|
-
KatakataIrb::Types::STRING
|
125
|
-
in [:string_dvar,]
|
126
|
-
KatakataIrb::Types::STRING
|
127
|
-
in [:regexp_literal, statements, _regexp_end]
|
128
|
-
statements.each { simulate_evaluate _1, scope }
|
129
|
-
KatakataIrb::Types::REGEXP
|
130
|
-
in [:array, [:args_add_star,] => star]
|
131
|
-
args, kwargs = retrieve_method_args star
|
132
|
-
types = args.flat_map do |elem|
|
133
|
-
if elem.is_a? KatakataIrb::Types::Splat
|
134
|
-
splat = simulate_evaluate elem.item, scope
|
135
|
-
array_elem, non_array = partition_to_array splat.nonnillable, :to_a
|
136
|
-
KatakataIrb::Types::UnionType[*array_elem, *non_array]
|
137
|
-
else
|
138
|
-
simulate_evaluate elem, scope
|
139
|
-
end
|
140
|
-
end
|
141
|
-
types << kwargs_type(kwargs, scope) if kwargs && kwargs.any?
|
142
|
-
KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*types]
|
143
|
-
in [:array, statements]
|
144
|
-
if statements.nil? || statements.empty?
|
145
|
-
KatakataIrb::Types::ARRAY
|
146
|
-
elsif statements.all? { _1 in [Symbol,] }
|
147
|
-
# normal array
|
148
|
-
elem = statements ? KatakataIrb::Types::UnionType[*statements.map { simulate_evaluate _1, scope }] : KatakataIrb::Types::NIL
|
149
|
-
KatakataIrb::Types::InstanceType.new Array, Elem: elem
|
150
|
-
else
|
151
|
-
# %I[] or %W[]
|
152
|
-
statements.each do |sub_statements|
|
153
|
-
sub_statements.each { simulate_evaluate _1, scope }
|
154
|
-
end
|
155
|
-
# TODO: use AST because Ripper.sexp('%I[a]') == Ripper.sexp('%W[a]')
|
156
|
-
elem = KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::SYMBOL]
|
157
|
-
KatakataIrb::Types::InstanceType.new Array, Elem: elem
|
158
|
-
end
|
159
|
-
in [:bare_assoc_hash, args]
|
160
|
-
simulate_evaluate [:hash, [:assoclist_from_args, args]], scope
|
161
|
-
in [:hash, [:assoclist_from_args, args]]
|
162
|
-
keys = []
|
163
|
-
values = []
|
164
|
-
args.each do |arg|
|
165
|
-
case arg
|
166
|
-
in [:assoc_new, key, value]
|
167
|
-
if key in [:@label, label, pos]
|
168
|
-
keys << KatakataIrb::Types::SYMBOL
|
169
|
-
name = label.delete ':'
|
170
|
-
value ||= [:__var_ref_or_call, [name =~ /\A[A-Z]/ ? :@const : :@ident, name, pos]]
|
171
|
-
else
|
172
|
-
keys << simulate_evaluate(key, scope)
|
173
|
-
end
|
174
|
-
values << simulate_evaluate(value, scope)
|
175
|
-
in [:assoc_splat, value]
|
176
|
-
hash = simulate_evaluate value, scope
|
177
|
-
unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
|
178
|
-
hash = simulate_call hash, :to_hash, [], nil, nil
|
179
|
-
end
|
180
|
-
if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
|
181
|
-
keys << hash.params[:K] if hash.params[:K]
|
182
|
-
values << hash.params[:V] if hash.params[:V]
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values]
|
187
|
-
in [:hash, nil]
|
188
|
-
KatakataIrb::Types::InstanceType.new Hash
|
189
|
-
in [:paren, [Symbol,] | false => statement]
|
190
|
-
# workaround for `p ()` and `p (foo)`
|
191
|
-
simulate_evaluate statement, scope if statement
|
192
|
-
in [:paren | :ensure | :else, statements]
|
193
|
-
statements.map { simulate_evaluate _1, scope }.last
|
194
|
-
in [:const_path_ref, receiver, [:@const, name,]]
|
195
|
-
r = simulate_evaluate receiver, scope
|
196
|
-
r.is_a?(KatakataIrb::Types::SingletonType) ? KatakataIrb::BaseScope.type_of { r.module_or_class.const_get name } : KatakataIrb::Types::NIL
|
197
|
-
in [:__var_ref_or_call, [type, name, pos]]
|
198
|
-
sexp = scope.has?(name) ? [:var_ref, [type, name, pos]] : [:vcall, [:@ident, name, pos]]
|
199
|
-
simulate_evaluate sexp, scope
|
200
|
-
in [:var_ref, [:@kw, name,]]
|
201
|
-
case name
|
202
|
-
in 'self'
|
203
|
-
scope.self_type
|
204
|
-
in 'true'
|
205
|
-
KatakataIrb::Types::TRUE
|
206
|
-
in 'false'
|
207
|
-
KatakataIrb::Types::FALSE
|
208
|
-
in 'nil'
|
209
|
-
KatakataIrb::Types::NIL
|
210
|
-
in '__FILE__'
|
211
|
-
KatakataIrb::Types::STRING
|
212
|
-
in '__LINE__'
|
213
|
-
KatakataIrb::Types::INTEGER
|
214
|
-
in '__ENCODING__'
|
215
|
-
KatakataIrb::Types::InstanceType.new Encoding
|
216
|
-
end
|
217
|
-
in [:var_ref, [:@const | :@ivar | :@cvar | :@gvar | :@ident, name,]]
|
218
|
-
scope[name] || KatakataIrb::Types::NIL
|
219
|
-
in [:const_ref, [:@const, name,]]
|
220
|
-
scope[name] || KatakataIrb::Types::NIL
|
221
|
-
in [:aref, receiver, args]
|
222
|
-
receiver_type = simulate_evaluate receiver, scope if receiver
|
223
|
-
args, kwargs, _block = retrieve_method_args args
|
224
|
-
args_type = args.map do |arg|
|
225
|
-
if arg.is_a? KatakataIrb::Types::Splat
|
226
|
-
simulate_evaluate arg.item, scope
|
227
|
-
nil # TODO: splat
|
228
|
-
else
|
229
|
-
simulate_evaluate arg, scope
|
230
|
-
end
|
231
|
-
end
|
232
|
-
simulate_call receiver_type, :[], args_type, kwargs_type(kwargs, scope), nil
|
233
|
-
in [:call | :vcall | :command | :command_call | :method_add_arg | :method_add_block,]
|
234
|
-
if (sexp in [:vcall, [:@ident, name,]]) && scope.has?(name)
|
235
|
-
# workaround for https://bugs.ruby-lang.org/issues/19175
|
236
|
-
return scope[name]
|
237
|
-
end
|
238
|
-
receiver, method, args, kwargs, block, optional_chain = retrieve_method_call sexp
|
239
|
-
if receiver.nil? && method == 'raise'
|
240
|
-
scope.terminate_with KatakataIrb::Scope::RAISE_BREAK, KatakataIrb::Types::TRUE
|
241
|
-
return KatakataIrb::Types::NIL
|
242
|
-
end
|
243
|
-
receiver_type = receiver ? simulate_evaluate(receiver, scope) : scope.self_type
|
244
|
-
evaluate_method = lambda do |scope|
|
245
|
-
args_type = args.map do |arg|
|
246
|
-
if arg.is_a? KatakataIrb::Types::Splat
|
247
|
-
simulate_evaluate arg.item, scope
|
248
|
-
nil # TODO: splat
|
249
|
-
else
|
250
|
-
simulate_evaluate arg, scope
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
if block
|
255
|
-
if block in [:symbol_literal, [:symbol, [:@ident, block_name,]]]
|
256
|
-
call_block_proc = ->(block_args, _self_type) do
|
257
|
-
block_receiver, *rest = block_args
|
258
|
-
block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_name, rest, nil, nil) : KatakataIrb::Types::OBJECT
|
259
|
-
end
|
260
|
-
elsif block in [:do_block | :brace_block => type, block_var, body]
|
261
|
-
block_var in [:block_var, params,]
|
262
|
-
call_block_proc = ->(block_args, block_self_type) do
|
263
|
-
scope.conditional do |s|
|
264
|
-
if params
|
265
|
-
names = extract_param_names(params)
|
266
|
-
else
|
267
|
-
names = (1..max_numbered_params(body)).map { "_#{_1}" }
|
268
|
-
params = [:params, names.map { [:@ident, _1, [0, 0]] }, nil, nil, nil, nil, nil, nil]
|
269
|
-
end
|
270
|
-
params_table = names.zip(block_args).to_h { [_1, _2 || KatakataIrb::Types::NIL] }
|
271
|
-
table = { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil }
|
272
|
-
table[KatakataIrb::Scope::SELF] = block_self_type if block_self_type
|
273
|
-
block_scope = KatakataIrb::Scope.new s, table
|
274
|
-
evaluate_assign_params params, block_args, block_scope
|
275
|
-
block_scope.conditional { evaluate_param_defaults params, _1 } if params
|
276
|
-
if type == :do_block
|
277
|
-
result = simulate_evaluate body, block_scope
|
278
|
-
else
|
279
|
-
result = body.map { simulate_evaluate _1, block_scope }.last
|
280
|
-
end
|
281
|
-
block_scope.merge_jumps
|
282
|
-
s.update block_scope
|
283
|
-
nexts = block_scope[KatakataIrb::Scope::NEXT_RESULT]
|
284
|
-
breaks = block_scope[KatakataIrb::Scope::BREAK_RESULT]
|
285
|
-
if block_scope.terminated?
|
286
|
-
[KatakataIrb::Types::UnionType[*nexts], breaks]
|
287
|
-
else
|
288
|
-
[KatakataIrb::Types::UnionType[result, *nexts], breaks]
|
289
|
-
end
|
290
|
-
end
|
291
|
-
end
|
292
|
-
else
|
293
|
-
call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
|
294
|
-
simulate_evaluate block, scope
|
295
|
-
end
|
296
|
-
end
|
297
|
-
simulate_call receiver_type, method, args_type, kwargs_type(kwargs, scope), call_block_proc
|
298
|
-
end
|
299
|
-
if optional_chain
|
300
|
-
result = scope.conditional { evaluate_method.call _1 }
|
301
|
-
if receiver_type.nillable?
|
302
|
-
KatakataIrb::Types::UnionType[result, KatakataIrb::Types::NIL]
|
303
|
-
else
|
304
|
-
result
|
305
|
-
end
|
306
|
-
else
|
307
|
-
evaluate_method.call scope
|
308
|
-
end
|
309
|
-
in [:binary, a, Symbol => op, b]
|
310
|
-
atype = simulate_evaluate a, scope
|
311
|
-
case op
|
312
|
-
when :'&&', :and
|
313
|
-
btype = scope.conditional { simulate_evaluate b, _1 }
|
314
|
-
KatakataIrb::Types::UnionType[btype, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
315
|
-
when :'||', :or
|
316
|
-
btype = scope.conditional { simulate_evaluate b, _1 }
|
317
|
-
KatakataIrb::Types::UnionType[atype, btype]
|
318
|
-
else
|
319
|
-
btype = simulate_evaluate b, scope
|
320
|
-
simulate_call atype, op, [btype], nil, nil
|
321
|
-
end
|
322
|
-
in [:unary, op, receiver]
|
323
|
-
simulate_call simulate_evaluate(receiver, scope), op, [], nil, nil
|
324
|
-
in [:lambda, params, statements]
|
325
|
-
params in [:paren, params] # ->{}, -> do end
|
326
|
-
statements in [:bodystmt, statements, _unknown, _unknown, _unknown] # -> do end
|
327
|
-
params in [:paren, params]
|
328
|
-
params_table = extract_param_names(params).to_h { [_1, KatakataIrb::Types::NIL] }
|
329
|
-
block_scope = KatakataIrb::Scope.new scope, { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }
|
330
|
-
block_scope.conditional do |s|
|
331
|
-
evaluate_assign_params params, [], s
|
332
|
-
s.conditional { evaluate_param_defaults params, _1 }
|
333
|
-
statements.each { simulate_evaluate _1, s }
|
334
|
-
end
|
335
|
-
block_scope.merge_jumps
|
336
|
-
scope.update block_scope
|
337
|
-
KatakataIrb::Types::ProcType.new
|
338
|
-
in [:assign, [:var_field, [:@gvar | :@ivar | :@cvar | :@ident | :@const, name,]], value]
|
339
|
-
res = simulate_evaluate value, scope
|
340
|
-
scope[name] = res
|
341
|
-
res
|
342
|
-
in [:assign, [:aref_field, receiver, key], value]
|
343
|
-
simulate_evaluate receiver, scope
|
344
|
-
args, kwargs, _block = retrieve_method_args key
|
345
|
-
args.each do |arg|
|
346
|
-
item = arg.is_a?(KatakataIrb::Types::Splat) ? arg.item : arg
|
347
|
-
simulate_evaluate item, scope
|
348
|
-
end
|
349
|
-
kwargs_type kwargs, scope
|
350
|
-
simulate_evaluate value, scope
|
351
|
-
in [:assign, [:field, receiver, period, [:@ident,]], value]
|
352
|
-
simulate_evaluate receiver, scope
|
353
|
-
if period in [:@op, '&.',]
|
354
|
-
scope.conditional { simulate_evaluate value, scope }
|
355
|
-
else
|
356
|
-
simulate_evaluate value, scope
|
357
|
-
end
|
358
|
-
in [:opassign, target, [:@op, op,], value]
|
359
|
-
op = op.to_s.delete('=').to_sym
|
360
|
-
if target in [:var_field, *field]
|
361
|
-
receiver = [:var_ref, *field]
|
362
|
-
elsif target in [:field, *field]
|
363
|
-
receiver = [:call, *field]
|
364
|
-
elsif target in [:aref_field, *field]
|
365
|
-
receiver = [:aref, *field]
|
366
|
-
else
|
367
|
-
receiver = target
|
368
|
-
end
|
369
|
-
simulate_evaluate [:assign, target, [:binary, receiver, op, value]], scope
|
370
|
-
in [:assign, target, value]
|
371
|
-
simulate_evaluate target, scope
|
372
|
-
simulate_evaluate value, scope
|
373
|
-
in [:massign, targets, value]
|
374
|
-
targets in [:mlhs, *targets] # (a,b) = value
|
375
|
-
rhs = simulate_evaluate value, scope
|
376
|
-
evaluate_massign targets, rhs, scope
|
377
|
-
rhs
|
378
|
-
in [:mrhs_new_from_args | :mrhs_add_star,]
|
379
|
-
values, = evaluate_mrhs sexp, scope
|
380
|
-
KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*values]
|
381
|
-
in [:ifop, cond, tval, fval]
|
382
|
-
simulate_evaluate cond, scope
|
383
|
-
KatakataIrb::Types::UnionType[*scope.run_branches(
|
384
|
-
-> { simulate_evaluate tval, _1 },
|
385
|
-
-> { simulate_evaluate fval, _1 }
|
386
|
-
)]
|
387
|
-
in [:if_mod | :unless_mod, cond, statement]
|
388
|
-
simulate_evaluate cond, scope
|
389
|
-
KatakataIrb::Types::UnionType[scope.conditional { simulate_evaluate statement, _1 }, KatakataIrb::Types::NIL]
|
390
|
-
in [:if | :unless | :elsif, cond, statements, else_statement]
|
391
|
-
simulate_evaluate cond, scope
|
392
|
-
results = scope.run_branches(
|
393
|
-
->(s) { statements.map { simulate_evaluate _1, s }.last },
|
394
|
-
->(s) { else_statement ? simulate_evaluate(else_statement, s) : KatakataIrb::Types::NIL }
|
395
|
-
)
|
396
|
-
results.empty? ? KatakataIrb::Types::NIL : KatakataIrb::Types::UnionType[*results]
|
397
|
-
in [:while | :until, cond, statements]
|
398
|
-
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }, passthrough: true
|
399
|
-
simulate_evaluate cond, inner_scope
|
400
|
-
inner_scope.conditional { |s| statements.each { simulate_evaluate _1, s } }
|
401
|
-
inner_scope.merge_jumps
|
402
|
-
scope.update inner_scope
|
403
|
-
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
404
|
-
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
405
|
-
in [:while_mod | :until_mod, cond, statement]
|
406
|
-
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }, passthrough: true
|
407
|
-
simulate_evaluate cond, inner_scope
|
408
|
-
inner_scope.conditional { |s| simulate_evaluate statement, s }
|
409
|
-
inner_scope.merge_jumps
|
410
|
-
scope.update inner_scope
|
411
|
-
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
412
|
-
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
413
|
-
in [:break | :next | :return => jump_type, value]
|
414
|
-
internal_key = jump_type == :break ? KatakataIrb::Scope::BREAK_RESULT : jump_type == :next ? KatakataIrb::Scope::NEXT_RESULT : KatakataIrb::Scope::RETURN_RESULT
|
415
|
-
if value.empty?
|
416
|
-
jump_value = KatakataIrb::Types::NIL
|
417
|
-
else
|
418
|
-
values, kw = evaluate_mrhs value, scope
|
419
|
-
values << kw if kw
|
420
|
-
jump_value = values.size == 1 ? values.first : KatakataIrb::Types::InstanceType.new(Array, Elem: KatakataIrb::Types::UnionType[*values])
|
421
|
-
end
|
422
|
-
scope.terminate_with internal_key, jump_value
|
423
|
-
KatakataIrb::Types::NIL
|
424
|
-
in [:return0]
|
425
|
-
scope.terminate_with KatakataIrb::Scope::RETURN_RESULT, KatakataIrb::Types::NIL
|
426
|
-
KatakataIrb::Types::NIL
|
427
|
-
in [:yield, args]
|
428
|
-
evaluate_mrhs args, scope
|
429
|
-
KatakataIrb::Types::OBJECT
|
430
|
-
in [:yield0]
|
431
|
-
KatakataIrb::Types::OBJECT
|
432
|
-
in [:redo | :retry]
|
433
|
-
scope.terminate
|
434
|
-
in [:zsuper]
|
435
|
-
KatakataIrb::Types::OBJECT
|
436
|
-
in [:super, args]
|
437
|
-
args, kwargs, _block = retrieve_method_args args
|
438
|
-
args.each do |arg|
|
439
|
-
item = arg.is_a?(KatakataIrb::Types::Splat) ? arg.item : arg
|
440
|
-
simulate_evaluate item, scope
|
441
|
-
end
|
442
|
-
kwargs_type kwargs, scope
|
443
|
-
KatakataIrb::Types::OBJECT
|
444
|
-
in [:begin, body_stmt]
|
445
|
-
simulate_evaluate body_stmt, scope
|
446
|
-
in [:bodystmt, statements, rescue_stmt, _unknown, ensure_stmt]
|
447
|
-
statements = [statements] if statements in [Symbol,] # oneliner-def body
|
448
|
-
rescue_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::RAISE_BREAK => nil }, passthrough: true if rescue_stmt
|
449
|
-
return_type = statements.map { simulate_evaluate _1, rescue_scope || scope }.last
|
450
|
-
if rescue_stmt
|
451
|
-
rescue_scope.merge_jumps
|
452
|
-
scope.update rescue_scope
|
453
|
-
return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, _1 }]
|
454
|
-
end
|
455
|
-
simulate_evaluate ensure_stmt, scope if ensure_stmt
|
456
|
-
return_type
|
457
|
-
in [:rescue, error_class_stmts, error_var_stmt, statements, rescue_stmt]
|
458
|
-
return_type = scope.conditional do |s|
|
459
|
-
if error_var_stmt in [:var_field, [:@ident, error_var,]]
|
460
|
-
if (error_class_stmts in [:mrhs_new_from_args, Array => stmts, stmt])
|
461
|
-
error_class_stmts = [*stmts, stmt]
|
462
|
-
end
|
463
|
-
error_classes = (error_class_stmts || []).flat_map { simulate_evaluate _1, s }.uniq
|
464
|
-
error_types = error_classes.filter_map { KatakataIrb::Types::InstanceType.new _1.module_or_class if _1.is_a?(KatakataIrb::Types::SingletonType) }
|
465
|
-
error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
|
466
|
-
s[error_var] = KatakataIrb::Types::UnionType[*error_types]
|
467
|
-
end
|
468
|
-
statements.map { simulate_evaluate _1, s }.last
|
469
|
-
end
|
470
|
-
if rescue_stmt
|
471
|
-
return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, _1 }]
|
472
|
-
end
|
473
|
-
return_type
|
474
|
-
in [:rescue_mod, statement1, statement2]
|
475
|
-
rescue_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::RAISE_BREAK => nil }, passthrough: true
|
476
|
-
a = simulate_evaluate statement1, rescue_scope
|
477
|
-
rescue_scope.merge_jumps
|
478
|
-
scope.update rescue_scope
|
479
|
-
b = scope.conditional { simulate_evaluate statement2, _1 }
|
480
|
-
KatakataIrb::Types::UnionType[a, b]
|
481
|
-
in [:module, module_stmt, body_stmt]
|
482
|
-
module_types = simulate_evaluate(module_stmt, scope).types.grep(KatakataIrb::Types::SingletonType)
|
483
|
-
module_types << KatakataIrb::Types::MODULE if module_types.empty?
|
484
|
-
module_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::SELF => KatakataIrb::Types::UnionType[*module_types], KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
|
485
|
-
result = simulate_evaluate body_stmt, module_scope
|
486
|
-
scope.update module_scope
|
487
|
-
result
|
488
|
-
in [:sclass, klass_stmt, body_stmt]
|
489
|
-
klass_types = simulate_evaluate(klass_stmt, scope).types.filter_map do |type|
|
490
|
-
KatakataIrb::Types::SingletonType.new type.klass if type.is_a? KatakataIrb::Types::InstanceType
|
491
|
-
end
|
492
|
-
klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
|
493
|
-
sclass_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::SELF => KatakataIrb::Types::UnionType[*klass_types], KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
|
494
|
-
result = simulate_evaluate body_stmt, sclass_scope
|
495
|
-
scope.update sclass_scope
|
496
|
-
result
|
497
|
-
in [:class, klass_stmt, superclass_stmt, body_stmt]
|
498
|
-
klass_types = simulate_evaluate(klass_stmt, scope).types
|
499
|
-
klass_types += simulate_evaluate(superclass_stmt, scope).types if superclass_stmt
|
500
|
-
klass_types = klass_types.select do |type|
|
501
|
-
type.is_a?(KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
502
|
-
end
|
503
|
-
klass_types << KatakataIrb::Types::CLASS if klass_types.empty?
|
504
|
-
klass_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::SELF => KatakataIrb::Types::UnionType[*klass_types], KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }, trace_cvar: false, trace_ivar: false, trace_lvar: false)
|
505
|
-
result = simulate_evaluate body_stmt, klass_scope
|
506
|
-
scope.update klass_scope
|
507
|
-
result
|
508
|
-
in [:for, fields, enum, statements]
|
509
|
-
fields = [fields] if fields in [:var_field | :field | :aref_field,]
|
510
|
-
params = [:params, fields, nil, nil, nil, nil, nil, nil]
|
511
|
-
enum = simulate_evaluate enum, scope
|
512
|
-
extract_param_names(params).each { scope[_1] = KatakataIrb::Types::NIL }
|
513
|
-
response = simulate_call enum, :first, [], nil, nil
|
514
|
-
evaluate_assign_params params, [response], scope
|
515
|
-
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }, passthrough: true
|
516
|
-
scope.conditional do |s|
|
517
|
-
statements.each { simulate_evaluate _1, s }
|
518
|
-
end
|
519
|
-
inner_scope.merge_jumps
|
520
|
-
scope.update inner_scope
|
521
|
-
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
522
|
-
breaks ? KatakataIrb::Types::UnionType[breaks, enum] : enum
|
523
|
-
in [:when, pattern, if_statements, else_statement]
|
524
|
-
eval_pattern = lambda do |s, pattern, *rest|
|
525
|
-
simulate_evaluate pattern, s
|
526
|
-
scope.conditional { eval_pattern.call(_1, *rest) } if rest.any?
|
527
|
-
end
|
528
|
-
if_branch = lambda do |s|
|
529
|
-
eval_pattern.call(s, *pattern)
|
530
|
-
if_statements.map { simulate_evaluate _1, s }.last
|
531
|
-
end
|
532
|
-
else_branch = lambda do |s|
|
533
|
-
pattern.each { simulate_evaluate _1, s }
|
534
|
-
simulate_evaluate(else_statement, s, case_target: case_target)
|
535
|
-
end
|
536
|
-
if if_statements && else_statement
|
537
|
-
KatakataIrb::Types::UnionType[*scope.run_branches(if_branch, else_branch)]
|
538
|
-
else
|
539
|
-
KatakataIrb::Types::UnionType[scope.conditional { (if_branch || else_branch).call _1 }, KatakataIrb::Types::NIL]
|
540
|
-
end
|
541
|
-
in [:in, [:var_field, [:@ident, name,]], if_statements, else_statement]
|
542
|
-
scope.never { simulate_evaluate else_statement, scope } if else_statement
|
543
|
-
scope[name] = case_target || KatakataIrb::Types::OBJECT
|
544
|
-
if_statements ? if_statements.map { simulate_evaluate _1, scope }.last : KatakataIrb::Types::NIL
|
545
|
-
in [:in, pattern, if_statements, else_statement]
|
546
|
-
pattern_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::PATTERNMATCH_BREAK => nil }, passthrough: true)
|
547
|
-
results = pattern_scope.run_branches(
|
548
|
-
->(s) {
|
549
|
-
match_pattern case_target, pattern, s
|
550
|
-
if_statements ? if_statements.map { simulate_evaluate _1, s }.last : KatakataIrb::Types::NIL
|
551
|
-
},
|
552
|
-
->(s) {
|
553
|
-
else_statement ? simulate_evaluate(else_statement, s, case_target: case_target) : KatakataIrb::Types::NIL
|
554
|
-
}
|
555
|
-
)
|
556
|
-
pattern_scope.merge_jumps
|
557
|
-
scope.update pattern_scope
|
558
|
-
KatakataIrb::Types::UnionType[*results]
|
559
|
-
in [:case, target_exp, match_exp]
|
560
|
-
target = target_exp ? simulate_evaluate(target_exp, scope) : KatakataIrb::Types::NIL
|
561
|
-
simulate_evaluate match_exp, scope, case_target: target
|
562
|
-
in [:void_stmt]
|
563
|
-
KatakataIrb::Types::NIL
|
564
|
-
in [:dot2 | :dot3, range_beg, range_end]
|
565
|
-
beg_type = simulate_evaluate range_beg, scope if range_beg
|
566
|
-
end_type = simulate_evaluate range_end, scope if range_end
|
567
|
-
elem = (KatakataIrb::Types::UnionType[*[beg_type, end_type].compact]).nonnillable
|
568
|
-
KatakataIrb::Types::InstanceType.new Range, { Elem: elem }
|
569
|
-
in [:top_const_ref, [:@const, name,]]
|
570
|
-
KatakataIrb::BaseScope.type_of { Object.const_get name }
|
571
|
-
in [:string_concat, a, b]
|
572
|
-
simulate_evaluate a, scope
|
573
|
-
simulate_evaluate b, scope
|
574
|
-
KatakataIrb::Types::STRING
|
575
|
-
in [:defined, expression]
|
576
|
-
scope.conditional { simulate_evaluate expression, _1 }
|
577
|
-
KatakataIrb::Types::UnionType[KatakataIrb::Types::STRING, KatakataIrb::Types::NIL]
|
578
|
-
else
|
579
|
-
KatakataIrb.log_puts
|
580
|
-
KatakataIrb.log_puts :NOMATCH
|
581
|
-
KatakataIrb.log_puts sexp.inspect
|
582
|
-
KatakataIrb::Types::NIL
|
583
|
-
end
|
584
|
-
end
|
585
|
-
|
586
|
-
def match_pattern(target, pattern, scope)
|
587
|
-
breakable = -> { scope.terminate_with KatakataIrb::Scope::PATTERNMATCH_BREAK, KatakataIrb::Types::NIL }
|
588
|
-
types = target.types
|
589
|
-
case pattern
|
590
|
-
in [:var_field, [:@ident, name,]]
|
591
|
-
scope[name] = target
|
592
|
-
in [:var_ref,] # in Array, in ^a, in nil
|
593
|
-
in [:@int | :@float | :@rational | :@imaginary | :@CHAR | :symbol_literal | :string_literal | :regexp_literal,]
|
594
|
-
in [:begin, statement] # in (statement)
|
595
|
-
simulate_evaluate statement, scope
|
596
|
-
breakable.call
|
597
|
-
in [:binary, lpattern, :|, rpattern]
|
598
|
-
match_pattern target, lpattern, scope
|
599
|
-
scope.conditional { match_pattern target, rpattern, _1 }
|
600
|
-
breakable.call
|
601
|
-
in [:binary, lpattern, :'=>', [:var_field, [:@ident, name,]] => rpattern]
|
602
|
-
if lpattern in [:var_ref, [:@const, _const_name,]]
|
603
|
-
const_value = simulate_evaluate lpattern, scope
|
604
|
-
if const_value.is_a?(KatakataIrb::Types::SingletonType) && const_value.module_or_class.is_a?(Class)
|
605
|
-
scope[name] = KatakataIrb::Types::InstanceType.new const_value.module_or_class
|
606
|
-
else
|
607
|
-
scope[name] = KatakataIrb::Types::OBJECT
|
608
|
-
end
|
609
|
-
breakable.call
|
610
|
-
else
|
611
|
-
match_pattern target, lpattern, scope
|
612
|
-
match_pattern target, rpattern, scope
|
613
|
-
end
|
614
|
-
in [:aryptn, _unknown, items, splat, post_items]
|
615
|
-
# TODO: deconstruct keys
|
616
|
-
array_types = types.select { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
|
617
|
-
elem = KatakataIrb::Types::UnionType[*array_types.filter_map { _1.params[:Elem] }]
|
618
|
-
items&.each do |item|
|
619
|
-
match_pattern elem, item, scope
|
620
|
-
end
|
621
|
-
if splat in [:var_field, [:@ident, name,]]
|
622
|
-
scope[name] = KatakataIrb::Types::InstanceType.new Array, Elem: elem
|
623
|
-
breakable.call
|
624
|
-
end
|
625
|
-
post_items&.each do |item|
|
626
|
-
match_pattern elem, item, scope
|
627
|
-
end
|
628
|
-
in [:hshptn, _unknown, items, splat]
|
629
|
-
# TODO: deconstruct keys
|
630
|
-
hash_types = types.select { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Hash }
|
631
|
-
key_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:K] }]
|
632
|
-
value_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:V] }]
|
633
|
-
items&.each do |key_pattern, value_pattern|
|
634
|
-
if (key_pattern in [:@label, label,]) && !value_pattern
|
635
|
-
name = label.delete ':'
|
636
|
-
scope[name] = value_type
|
637
|
-
breakable.call
|
638
|
-
end
|
639
|
-
match_pattern value_type, value_pattern, scope if value_pattern
|
640
|
-
end
|
641
|
-
if splat in [:var_field, [:@ident, name,]]
|
642
|
-
scope[name] = KatakataIrb::Types::InstanceType.new Hash, K: key_type, V: value_type
|
643
|
-
breakable.call
|
644
|
-
end
|
645
|
-
in [:if_mod, cond, ifpattern]
|
646
|
-
match_pattern target, ifpattern, scope
|
647
|
-
simulate_evaluate cond, scope
|
648
|
-
breakable.call
|
649
|
-
in [:dyna_symbol,]
|
650
|
-
in [:const_path_ref,]
|
651
|
-
else
|
652
|
-
KatakataIrb.log_puts "Unimplemented match pattern: #{pattern}"
|
653
|
-
end
|
654
|
-
end
|
655
|
-
|
656
|
-
def evaluate_mrhs(sexp, scope)
|
657
|
-
args, kwargs, = retrieve_method_args sexp
|
658
|
-
values = args.filter_map do |t|
|
659
|
-
if t.is_a? KatakataIrb::Types::Splat
|
660
|
-
simulate_evaluate t.item, scope
|
661
|
-
# TODO
|
662
|
-
nil
|
663
|
-
else
|
664
|
-
simulate_evaluate t, scope
|
665
|
-
end
|
666
|
-
end
|
667
|
-
unless kwargs.empty?
|
668
|
-
kvs = kwargs.map do |t|
|
669
|
-
case t
|
670
|
-
in KatakataIrb::Types::Splat
|
671
|
-
simulate_evaluate t.item, scope
|
672
|
-
# TODO
|
673
|
-
[KatakataIrb::Types::SYMBOL, KatakataIrb::Types::OBJECT]
|
674
|
-
in [key, value]
|
675
|
-
key_type = (key in [:@label,]) ? KatakataIrb::Types::SYMBOL : simulate_evaluate(key, scope)
|
676
|
-
[key_type, simulate_evaluate(value, scope)]
|
677
|
-
end
|
678
|
-
end
|
679
|
-
key_type = KatakataIrb::Types::UnionType[*kvs.map(&:first)]
|
680
|
-
value_type = KatakataIrb::Types::UnionType[*kvs.map(&:last)]
|
681
|
-
kw = KatakataIrb::Types::InstanceType.new(Hash, K: key_type, V: value_type)
|
682
|
-
end
|
683
|
-
[values, kw]
|
684
|
-
end
|
685
|
-
|
686
|
-
def sized_splat(value, method, size)
|
687
|
-
array_elem, non_array = partition_to_array value, method
|
688
|
-
values = [KatakataIrb::Types::UnionType[*array_elem, *non_array]]
|
689
|
-
values += [array_elem] * (size - 1) if array_elem && size >= 1
|
690
|
-
values
|
691
|
-
end
|
692
|
-
|
693
|
-
def partition_to_array(value, method)
|
694
|
-
arrays, non_arrays = value.types.partition { _1.is_a?(KatakataIrb::Types::InstanceType) && _1.klass == Array }
|
695
|
-
non_arrays.select! do |type|
|
696
|
-
to_array_result = simulate_call type, method, [], nil, nil, name_match: false
|
697
|
-
if to_array_result.is_a?(KatakataIrb::Types::InstanceType) && to_array_result.klass == Array
|
698
|
-
arrays << to_array_result
|
699
|
-
false
|
700
|
-
else
|
701
|
-
true
|
702
|
-
end
|
703
|
-
end
|
704
|
-
array_elem = arrays.empty? ? nil : KatakataIrb::Types::UnionType[*arrays.map { _1.params[:Elem] || KatakataIrb::Types::OBJECT }]
|
705
|
-
non_array = non_arrays.empty? ? nil : KatakataIrb::Types::UnionType[*non_arrays]
|
706
|
-
[array_elem, non_array]
|
707
|
-
end
|
708
|
-
|
709
|
-
def evaluate_massign(sexp, values, scope)
|
710
|
-
values = sized_splat values, :to_ary, sexp.size unless values.is_a? Array
|
711
|
-
rest_index = sexp.find_index { _1 in [:rest_param, ]}
|
712
|
-
if rest_index
|
713
|
-
pre = rest_index ? sexp[0...rest_index] : sexp
|
714
|
-
post = rest_index ? sexp[rest_index + 1..] : []
|
715
|
-
sexp[rest_index] in [:rest_param, rest_field]
|
716
|
-
rest_values = values[pre.size...values.size - post.size] || []
|
717
|
-
rest_type = KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*rest_values]
|
718
|
-
pairs = pre.zip(values.first(pre.size)) + [[rest_field, rest_type]] + post.zip(values.last(post.size))
|
719
|
-
else
|
720
|
-
pairs = sexp.zip values
|
721
|
-
end
|
722
|
-
pairs.each do |field, value|
|
723
|
-
case field
|
724
|
-
in [:@ident, name,]
|
725
|
-
# block arg mlhs
|
726
|
-
scope[name] = value || KatakataIrb::Types::OBJECT
|
727
|
-
in [:var_field, [:@gvar | :@ivar | :@cvar | :@ident | :@const, name,]]
|
728
|
-
# massign
|
729
|
-
scope[name] = value || KatakataIrb::Types::OBJECT
|
730
|
-
in [:mlhs, *mlhs]
|
731
|
-
evaluate_massign mlhs, value || [], scope
|
732
|
-
in [:field, receiver,]
|
733
|
-
# (a=x).b, c = value
|
734
|
-
simulate_evaluate receiver, scope
|
735
|
-
in [:aref_field, *field]
|
736
|
-
# (a=x)[i=y, j=z], b = value
|
737
|
-
simulate_evaluate [:aref, *field], scope
|
738
|
-
in nil
|
739
|
-
# a, *, b = value
|
740
|
-
end
|
741
|
-
end
|
742
|
-
end
|
743
|
-
|
744
|
-
def kwargs_type(kwargs, scope)
|
745
|
-
return if kwargs.empty?
|
746
|
-
keys = []
|
747
|
-
values = []
|
748
|
-
kwargs.each do |kv|
|
749
|
-
if kv.is_a? KatakataIrb::Types::Splat
|
750
|
-
hash = simulate_evaluate kv.item, scope
|
751
|
-
unless hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
|
752
|
-
hash = simulate_call hash, :to_hash, [], nil, nil
|
753
|
-
end
|
754
|
-
if hash.is_a?(KatakataIrb::Types::InstanceType) && hash.klass == Hash
|
755
|
-
keys << hash.params[:K] if hash.params[:K]
|
756
|
-
values << hash.params[:V] if hash.params[:V]
|
757
|
-
end
|
758
|
-
else
|
759
|
-
key, value = kv
|
760
|
-
keys << ((key in [:@label,]) ? KatakataIrb::Types::SYMBOL : simulate_evaluate(key, scope))
|
761
|
-
values << simulate_evaluate(value, scope)
|
762
|
-
end
|
763
|
-
end
|
764
|
-
KatakataIrb::Types::InstanceType.new(Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values])
|
765
|
-
end
|
766
|
-
|
767
|
-
def retrieve_method_call(sexp)
|
768
|
-
optional = -> { _1 in [:@op, '&.',] }
|
769
|
-
case sexp
|
770
|
-
in [:fcall | :vcall, [:@ident | :@const | :@kw | :@op, method,]] # hoge
|
771
|
-
[nil, method, [], [], nil, false]
|
772
|
-
in [:call, receiver, [:@period,] | [:@op, '&.',] | [:@op, '::',] | :'::' => dot, :call]
|
773
|
-
[receiver, :call, [], [], nil, optional[dot]]
|
774
|
-
in [:call, receiver, [:@period,] | [:@op, '&.',] | [:@op, '::',] | :'::' => dot, method]
|
775
|
-
method => [:@ident | :@const | :@kw | :@op, method,] unless method == :call
|
776
|
-
[receiver, method, [], [], nil, optional[dot]]
|
777
|
-
in [:command, [:@ident | :@const | :@kw | :@op, method,], args] # hoge 1, 2
|
778
|
-
args, kwargs, block = retrieve_method_args args
|
779
|
-
[nil, method, args, kwargs, block, false]
|
780
|
-
in [:command_call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, [:@ident | :@const | :@kw | :@op, method,], args] # a.hoge 1; a.hoge 1, 2;
|
781
|
-
args, kwargs, block = retrieve_method_args args
|
782
|
-
[receiver, method, args, kwargs, block, optional[dot]]
|
783
|
-
in [:method_add_arg, call, args]
|
784
|
-
receiver, method, _arg, _kwarg, _block, opt = retrieve_method_call call
|
785
|
-
args, kwargs, block = retrieve_method_args args
|
786
|
-
[receiver, method, args, kwargs, block, opt]
|
787
|
-
in [:method_add_block, call, block]
|
788
|
-
receiver, method, args, kwargs, opt = retrieve_method_call call
|
789
|
-
[receiver, method, args, kwargs, block, opt]
|
790
|
-
end
|
791
|
-
end
|
792
|
-
|
793
|
-
def retrieve_method_args(sexp)
|
794
|
-
case sexp
|
795
|
-
in [:mrhs_add_star, args, star]
|
796
|
-
args, = retrieve_method_args args
|
797
|
-
[[*args, KatakataIrb::Types::Splat.new(star)], [], nil]
|
798
|
-
in [:mrhs_new_from_args, [:args_add_star,] => args]
|
799
|
-
args, = retrieve_method_args args
|
800
|
-
[args, [], nil]
|
801
|
-
in [:mrhs_new_from_args, [:args_add_star,] => args, last_arg]
|
802
|
-
args, = retrieve_method_args args
|
803
|
-
[[*args, last_arg], [], nil]
|
804
|
-
in [:mrhs_new_from_args, args, last_arg]
|
805
|
-
[[*args, last_arg], [], nil]
|
806
|
-
in [:mrhs_new_from_args, args]
|
807
|
-
[args, [], nil]
|
808
|
-
in [:args_add_block, [:args_add_star,] => args, block_arg]
|
809
|
-
args, kwargs, = retrieve_method_args args
|
810
|
-
block_arg = [:void_stmt] if block_arg.nil? # method(*splat, &)
|
811
|
-
[args, kwargs, block_arg]
|
812
|
-
in [:args_add_block, [*args, [:bare_assoc_hash,] => kw], block_arg]
|
813
|
-
block_arg = [:void_stmt] if block_arg.nil? # method(**splat, &)
|
814
|
-
_, kwargs = retrieve_method_args kw
|
815
|
-
[args, kwargs, block_arg]
|
816
|
-
in [:args_add_block, [*args], block_arg]
|
817
|
-
block_arg = [:void_stmt] if block_arg.nil? # method(arg, &)
|
818
|
-
[args, [], block_arg]
|
819
|
-
in [:bare_assoc_hash, kws]
|
820
|
-
kwargs = []
|
821
|
-
kws.each do |kw|
|
822
|
-
if kw in [:assoc_splat, value,]
|
823
|
-
kwargs << KatakataIrb::Types::Splat.new(value) if value
|
824
|
-
elsif kw in [:assoc_new, [:@label, label,] => key, nil]
|
825
|
-
name = label.delete ':'
|
826
|
-
kwargs << [key, [:__var_ref_or_call, [name =~ /\A[A-Z]/ ? :@const : :@ident, name, [0, 0]]]]
|
827
|
-
elsif kw in [:assoc_new, key, value]
|
828
|
-
kwargs << [key, value]
|
829
|
-
end
|
830
|
-
end
|
831
|
-
[[], kwargs, nil]
|
832
|
-
in [:args_add_star, *args, [:bare_assoc_hash,] => kwargs]
|
833
|
-
args, = retrieve_method_args [:args_add_star, *args]
|
834
|
-
_, kwargs = retrieve_method_args kwargs
|
835
|
-
[args, kwargs, nil]
|
836
|
-
in [:args_add_star, pre_args, star_arg, *post_args]
|
837
|
-
pre_args, = retrieve_method_args pre_args if pre_args in [:args_add_star,]
|
838
|
-
args = star_arg ? [*pre_args, KatakataIrb::Types::Splat.new(star_arg), *post_args] : pre_args + post_args
|
839
|
-
[args, [], nil]
|
840
|
-
in [:arg_paren, args]
|
841
|
-
args ? retrieve_method_args(args) : [[], [], nil]
|
842
|
-
in [[:command | :command_call, ] => command_arg] # method(a b, c), method(a.b c, d)
|
843
|
-
[[command_arg], [], nil]
|
844
|
-
else
|
845
|
-
[[], [], nil]
|
846
|
-
end
|
847
|
-
end
|
848
|
-
|
849
|
-
def simulate_call(receiver, method_name, args, kwargs, block, name_match: true)
|
850
|
-
methods = KatakataIrb::Types.rbs_methods receiver, method_name.to_sym, args, kwargs, !!block
|
851
|
-
block_called = false
|
852
|
-
type_breaks = methods.map do |method, given_params, method_params|
|
853
|
-
receiver_vars = (receiver in KatakataIrb::Types::InstanceType) ? receiver.params : {}
|
854
|
-
free_vars = method.type.free_variables - receiver_vars.keys.to_set
|
855
|
-
vars = receiver_vars.merge KatakataIrb::Types.match_free_variables(free_vars, method_params, given_params)
|
856
|
-
if block && method.block
|
857
|
-
params_type = method.block.type.required_positionals.map do |func_param|
|
858
|
-
KatakataIrb::Types.from_rbs_type func_param.type, receiver, vars
|
859
|
-
end
|
860
|
-
self_type = KatakataIrb::Types.from_rbs_type method.block.self_type, receiver, vars if method.block.self_type
|
861
|
-
block_response, breaks = block.call params_type, self_type
|
862
|
-
block_called = true
|
863
|
-
vars.merge! KatakataIrb::Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
|
864
|
-
end
|
865
|
-
[KatakataIrb::Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
|
866
|
-
end
|
867
|
-
block&.call [], nil unless block_called
|
868
|
-
types = type_breaks.map(&:first)
|
869
|
-
breaks = type_breaks.map(&:last).compact
|
870
|
-
types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
|
871
|
-
|
872
|
-
if method_name.to_sym == :new
|
873
|
-
receiver.types.each do |type|
|
874
|
-
if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
875
|
-
types << KatakataIrb::Types::InstanceType.new(type.module_or_class)
|
876
|
-
end
|
877
|
-
end
|
878
|
-
end
|
879
|
-
KatakataIrb::Types::UnionType[*types, *breaks]
|
880
|
-
end
|
881
|
-
|
882
|
-
def extract_param_names(params)
|
883
|
-
params => [:params, pre_required, optional, rest, post_required, keywords, keyrest, block]
|
884
|
-
names = []
|
885
|
-
extract_mlhs = ->(item) do
|
886
|
-
case item
|
887
|
-
in [:var_field, [:@ident, name,],]
|
888
|
-
names << name
|
889
|
-
in [:@ident, name,]
|
890
|
-
names << name
|
891
|
-
in [:mlhs, *items]
|
892
|
-
items.each(&extract_mlhs)
|
893
|
-
in [:rest_param, item]
|
894
|
-
extract_mlhs.call item if item
|
895
|
-
in [:field | :aref_field,]
|
896
|
-
# a.b, c[i] = value
|
897
|
-
in [:excessed_comma]
|
898
|
-
in [:args_forward]
|
899
|
-
end
|
900
|
-
end
|
901
|
-
[*pre_required, *post_required].each(&extract_mlhs)
|
902
|
-
extract_mlhs.call rest if rest
|
903
|
-
optional&.each do |key, _value|
|
904
|
-
key => [:@ident, name,]
|
905
|
-
names << name
|
906
|
-
end
|
907
|
-
keywords&.each do |key, _value|
|
908
|
-
key => [:@label, label,]
|
909
|
-
names << label.delete(':')
|
910
|
-
end
|
911
|
-
if keyrest in [:kwrest_params, [:@ident, name,]]
|
912
|
-
names << name
|
913
|
-
end
|
914
|
-
if block in [:blockarg, [:@ident, name,]]
|
915
|
-
names << name
|
916
|
-
end
|
917
|
-
names
|
918
|
-
end
|
919
|
-
|
920
|
-
def evaluate_assign_params(params, values, scope)
|
921
|
-
values = values.dup
|
922
|
-
params => [:params, pre_required, optional, rest, post_required, _keywords, keyrest, block]
|
923
|
-
size = (pre_required&.size || 0) + (optional&.size || 0) + (post_required&.size || 0) + (rest ? 1 : 0)
|
924
|
-
values = sized_splat values.first, :to_ary, size if values.size == 1 && size >= 2
|
925
|
-
pre_values = values.shift pre_required.size if pre_required
|
926
|
-
post_values = values.pop post_required.size if post_required
|
927
|
-
opt_values = values.shift optional.size if optional
|
928
|
-
rest_values = values
|
929
|
-
evaluate_massign pre_required, pre_values, scope if pre_required
|
930
|
-
evaluate_massign optional.map(&:first), opt_values, scope if optional
|
931
|
-
if rest in [:rest_param, [:@ident, name,]]
|
932
|
-
scope[name] = KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*rest_values]
|
933
|
-
end
|
934
|
-
evaluate_massign post_required, post_values, scope if post_required
|
935
|
-
# TODO: assign keywords
|
936
|
-
if keyrest in [:kwrest_param, [:@ident, name,]]
|
937
|
-
scope[name] = KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::SYMBOL, V: KatakataIrb::Types::OBJECT
|
938
|
-
end
|
939
|
-
if block in [:blockarg, [:@ident, name,]]
|
940
|
-
scope[name] = KatakataIrb::Types::PROC
|
941
|
-
end
|
942
|
-
end
|
943
|
-
|
944
|
-
def evaluate_param_defaults(params, scope)
|
945
|
-
params => [:params, _pre_required, optional, rest, _post_required, keywords, keyrest, block]
|
946
|
-
optional&.each do |item, value|
|
947
|
-
item => [:@ident, name,]
|
948
|
-
scope[name] = simulate_evaluate value, scope
|
949
|
-
end
|
950
|
-
if rest in [:rest_param, [:@ident, name,]]
|
951
|
-
scope[name] = KatakataIrb::Types::ARRAY
|
952
|
-
end
|
953
|
-
keywords&.each do |key, value|
|
954
|
-
key => [:@label, label,]
|
955
|
-
name = label.delete ':'
|
956
|
-
scope[name] = value ? simulate_evaluate(value, scope) : KatakataIrb::Types::OBJECT
|
957
|
-
end
|
958
|
-
if keyrest in [:kwrest_param, [:@ident, name,]]
|
959
|
-
scope[name] = KatakataIrb::Types::HASH
|
960
|
-
end
|
961
|
-
if block in [:blockarg, [:@ident, name,]]
|
962
|
-
scope[name] = KatakataIrb::Types::PROC
|
963
|
-
end
|
964
|
-
end
|
965
|
-
|
966
|
-
def max_numbered_params(sexp)
|
967
|
-
case sexp
|
968
|
-
in [:do_block | :brace_block | :def | :class | :module,]
|
969
|
-
0
|
970
|
-
in [:var_ref, [:@ident, name,]]
|
971
|
-
name.match?(/\A_[1-9]\z/) ? name[1..].to_i : 0
|
972
|
-
else
|
973
|
-
sexp.filter_map do |s|
|
974
|
-
max_numbered_params s if s.is_a? Array
|
975
|
-
end.max || 0
|
976
|
-
end
|
977
|
-
end
|
978
|
-
|
979
|
-
def self.calculate_binding_scope(binding, parents, target)
|
980
|
-
dig_targets = DigTarget.new(parents, target) do |_types, scope|
|
981
|
-
return scope
|
982
|
-
end
|
983
|
-
scope = KatakataIrb::Scope.from_binding(binding)
|
984
|
-
new(dig_targets).simulate_evaluate parents[0], scope
|
985
|
-
scope
|
986
|
-
end
|
987
|
-
|
988
|
-
def self.calculate_receiver(binding, parents, receiver)
|
989
|
-
dig_targets = DigTarget.new(parents, receiver) do |type, _scope|
|
990
|
-
return type
|
991
|
-
end
|
992
|
-
new(dig_targets).simulate_evaluate parents[0], KatakataIrb::Scope.from_binding(binding)
|
993
|
-
KatakataIrb::Types::NIL
|
994
|
-
end
|
995
|
-
end
|