katakata_irb 0.1.3 → 0.1.5
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.lock +8 -2
- data/README.md +16 -26
- data/bin/console +2 -7
- data/katakata_irb.gemspec +2 -1
- data/lib/katakata_irb/completor.rb +128 -14
- data/lib/katakata_irb/{trex.rb → nesting_parser.rb} +47 -11
- data/lib/katakata_irb/scope.rb +248 -0
- data/lib/katakata_irb/type_simulator.rb +148 -332
- data/lib/katakata_irb/types.rb +96 -22
- data/lib/katakata_irb/version.rb +1 -1
- data/lib/katakata_irb.rb +5 -7
- metadata +21 -15
- data/exe/kirb +0 -11
- data/lib/katakata_irb/reline_patch.rb +0 -43
- data/lib/katakata_irb/reline_patches/escapeseq.patch +0 -45
- data/lib/katakata_irb/reline_patches/indent.patch +0 -25
- data/lib/katakata_irb/reline_patches/raw.patch +0 -95
- data/lib/katakata_irb/reline_patches/scrollbar.patch +0 -34
- data/lib/katakata_irb/reline_patches/wholelines.patch +0 -102
- data/lib/katakata_irb/ruby_lex_patch.rb +0 -221
@@ -1,6 +1,7 @@
|
|
1
|
-
require_relative 'types'
|
2
1
|
require 'ripper'
|
3
2
|
require 'set'
|
3
|
+
require_relative 'types'
|
4
|
+
require_relative 'scope'
|
4
5
|
|
5
6
|
class KatakataIrb::TypeSimulator
|
6
7
|
class DigTarget
|
@@ -17,234 +18,12 @@ class KatakataIrb::TypeSimulator
|
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
class BaseScope
|
21
|
-
def initialize(binding, self_object)
|
22
|
-
@binding, @self_object = binding, self_object
|
23
|
-
@cache = { SELF => KatakataIrb::Types.type_from_object(self_object) }
|
24
|
-
@local_variables = binding.local_variables.map(&:to_s).to_set
|
25
|
-
end
|
26
|
-
|
27
|
-
def mutable?() = false
|
28
|
-
|
29
|
-
def [](name)
|
30
|
-
@cache[name] ||= (
|
31
|
-
fallback = KatakataIrb::Types::NIL
|
32
|
-
case BaseScope.type_by_name name
|
33
|
-
when :cvar
|
34
|
-
KatakataIrb::TypeSimulator.type_of(fallback:) { @self_object.class_variable_get name }
|
35
|
-
when :ivar
|
36
|
-
KatakataIrb::TypeSimulator.type_of(fallback:) { @self_object.instance_variable_get name }
|
37
|
-
when :lvar
|
38
|
-
KatakataIrb::TypeSimulator.type_of(fallback:) { @binding.local_variable_get(name) }
|
39
|
-
when :const
|
40
|
-
KatakataIrb::TypeSimulator.type_of(fallback:) { @binding.eval name }
|
41
|
-
end
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
|
-
def self_type
|
46
|
-
self[SELF]
|
47
|
-
end
|
48
|
-
|
49
|
-
def local_variables
|
50
|
-
@local_variables.to_a
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.type_by_name(name)
|
54
|
-
if name.start_with? '@@'
|
55
|
-
:cvar
|
56
|
-
elsif name.start_with? '@'
|
57
|
-
:ivar
|
58
|
-
elsif name.start_with? '$'
|
59
|
-
:gvar
|
60
|
-
elsif name.start_with? '%'
|
61
|
-
:internal
|
62
|
-
elsif name[0].downcase != name[0]
|
63
|
-
:const
|
64
|
-
else
|
65
|
-
:lvar
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def has?(name)
|
70
|
-
case BaseScope.type_by_name name
|
71
|
-
when :cvar
|
72
|
-
@self_object.class_variable_defined? name
|
73
|
-
when :ivar
|
74
|
-
@self_object.instance_variable_defined? name
|
75
|
-
when :lvar
|
76
|
-
@local_variables.include? name
|
77
|
-
when :const
|
78
|
-
@binding.eval("#{name};true") rescue false
|
79
|
-
when :internal
|
80
|
-
true
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class Scope
|
86
|
-
attr_reader :parent, :jump_branches
|
87
|
-
|
88
|
-
def self.from_binding(binding) = new BaseScope.new(binding, binding.eval('self'))
|
89
|
-
|
90
|
-
def initialize(parent, table = {}, trace_cvar: true, trace_ivar: true, trace_lvar: true, passthrough: false)
|
91
|
-
@tables = [table]
|
92
|
-
@parent = parent
|
93
|
-
@trace_cvar = trace_cvar
|
94
|
-
@trace_ivar = trace_ivar
|
95
|
-
@trace_lvar = trace_lvar
|
96
|
-
@passthrough = passthrough
|
97
|
-
@terminated = false
|
98
|
-
@jump_branches = []
|
99
|
-
end
|
100
|
-
|
101
|
-
def mutable? = true
|
102
|
-
|
103
|
-
def terminated?
|
104
|
-
@terminated
|
105
|
-
end
|
106
|
-
|
107
|
-
def terminate_with(type, value)
|
108
|
-
return if terminated?
|
109
|
-
self[type] = value
|
110
|
-
store_jump type
|
111
|
-
terminate
|
112
|
-
end
|
113
|
-
|
114
|
-
def store_jump(type)
|
115
|
-
scopes = ancestors.select(&:mutable?)
|
116
|
-
scope = scopes.find { _1.has_own? type } || scopes.last
|
117
|
-
index = scopes.index scope
|
118
|
-
scope.jump_branches << scopes.drop(index).map(&:branch_table_clone)
|
119
|
-
end
|
120
|
-
|
121
|
-
def terminate
|
122
|
-
@terminated = true
|
123
|
-
end
|
124
|
-
|
125
|
-
def branch_table_clone() = @tables.last.dup
|
126
|
-
|
127
|
-
def trace?(name)
|
128
|
-
return false unless @parent
|
129
|
-
type = BaseScope.type_by_name(name)
|
130
|
-
type == :cvar ? @trace_cvar : type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
|
131
|
-
end
|
132
|
-
|
133
|
-
def [](name)
|
134
|
-
@tables.reverse_each do |table|
|
135
|
-
return table[name] if table.key? name
|
136
|
-
end
|
137
|
-
@parent[name] if trace? name
|
138
|
-
end
|
139
|
-
|
140
|
-
def []=(name, type)
|
141
|
-
if @passthrough && BaseScope.type_by_name(name) != :internal
|
142
|
-
@parent[name] = type
|
143
|
-
elsif trace?(name) && @parent.mutable? && !@tables.any? { _1.key? name } && @parent.has?(name)
|
144
|
-
@parent[name] = type
|
145
|
-
else
|
146
|
-
@tables.last[name] = type
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def self_type
|
151
|
-
self[SELF]
|
152
|
-
end
|
153
|
-
|
154
|
-
def local_variables
|
155
|
-
lvar_keys = @tables.flat_map(&:keys).select do |name|
|
156
|
-
BaseScope.type_by_name(name) == :lvar
|
157
|
-
end
|
158
|
-
lvar_keys |= @parent.local_variables if @trace_lvar
|
159
|
-
lvar_keys
|
160
|
-
end
|
161
|
-
|
162
|
-
def start_branch
|
163
|
-
@tables << {}
|
164
|
-
end
|
165
|
-
|
166
|
-
def end_branch
|
167
|
-
@tables.pop
|
168
|
-
end
|
169
|
-
|
170
|
-
def merge_jumps
|
171
|
-
if terminated?
|
172
|
-
merge @jump_branches
|
173
|
-
else
|
174
|
-
merge [*@jump_branches, [{}] * ancestors.size]
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def merge_branch(tables)
|
179
|
-
target_table = @tables.last
|
180
|
-
keys = tables.flat_map(&:keys).uniq
|
181
|
-
keys.each do |key|
|
182
|
-
original_value = self[key] || KatakataIrb::Types::NIL
|
183
|
-
target_table[key] = KatakataIrb::Types::UnionType[*tables.map { _1[key] || original_value }.uniq]
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def ancestors
|
188
|
-
scopes = [self]
|
189
|
-
scopes << scopes.last.parent while scopes.last.parent&.mutable?
|
190
|
-
scopes
|
191
|
-
end
|
192
|
-
|
193
|
-
def conditional(&block)
|
194
|
-
run_branches(block, -> {}).first || KatakataIrb::Types::NIL
|
195
|
-
end
|
196
|
-
|
197
|
-
def never(&block)
|
198
|
-
branch(&block)
|
199
|
-
end
|
200
|
-
|
201
|
-
def run_branches(*blocks)
|
202
|
-
results = blocks.map { branch(&_1) }.reject(&:last)
|
203
|
-
merge results.map { _2 }
|
204
|
-
if results.empty?
|
205
|
-
terminate
|
206
|
-
[]
|
207
|
-
else
|
208
|
-
results.map(&:first)
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
def branch
|
213
|
-
scopes = ancestors
|
214
|
-
scopes.each(&:start_branch)
|
215
|
-
@terminated = false
|
216
|
-
result = yield
|
217
|
-
terminated = @terminated
|
218
|
-
@terminated = false
|
219
|
-
[result, scopes.map(&:end_branch), terminated]
|
220
|
-
end
|
221
|
-
|
222
|
-
def merge(branches)
|
223
|
-
scopes = ancestors
|
224
|
-
scopes.zip(*branches).each do |scope, *tables|
|
225
|
-
scope.merge_branch(tables)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def base_scope
|
230
|
-
@parent&.mutable? ? @parent.base_scope : @parent
|
231
|
-
end
|
232
|
-
|
233
|
-
def has_own?(name)
|
234
|
-
@tables.any? { _1.key? name }
|
235
|
-
end
|
236
|
-
|
237
|
-
def has?(name)
|
238
|
-
has_own?(name) || (trace?(name) && @parent.has?(name))
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
21
|
module LexerElemMatcher
|
243
22
|
refine Ripper::Lexer::Elem do
|
244
23
|
def deconstruct_keys(_keys)
|
245
24
|
{
|
246
|
-
tok
|
247
|
-
event
|
25
|
+
tok: tok,
|
26
|
+
event: event,
|
248
27
|
label: state.allbits?(Ripper::EXPR_LABEL),
|
249
28
|
beg: state.allbits?(Ripper::EXPR_BEG),
|
250
29
|
dot: state.allbits?(Ripper::EXPR_DOT)
|
@@ -268,19 +47,12 @@ class KatakataIrb::TypeSimulator
|
|
268
47
|
to_r: KatakataIrb::Types::RATIONAL
|
269
48
|
}
|
270
49
|
|
271
|
-
SELF = '%self'
|
272
|
-
BREAK_RESULT = '%break'
|
273
|
-
NEXT_RESULT = '%next'
|
274
|
-
RETURN_RESULT = '%return'
|
275
|
-
PATTERNMATCH_BREAK = '%match'
|
276
|
-
RAISE_BREAK = '%raise'
|
277
|
-
|
278
50
|
def initialize(dig_targets)
|
279
51
|
@dig_targets = dig_targets
|
280
52
|
end
|
281
53
|
|
282
54
|
def simulate_evaluate(sexp, scope, case_target: nil)
|
283
|
-
result = simulate_evaluate_inner(sexp, scope, case_target:)
|
55
|
+
result = simulate_evaluate_inner(sexp, scope, case_target: case_target)
|
284
56
|
@dig_targets.resolve result, scope if @dig_targets.target?(sexp)
|
285
57
|
result
|
286
58
|
end
|
@@ -309,10 +81,16 @@ class KatakataIrb::TypeSimulator
|
|
309
81
|
if @dig_targets.dig? sexp
|
310
82
|
params in [:paren, params]
|
311
83
|
params_table = extract_param_names(params).to_h { [_1, KatakataIrb::Types::NIL] }
|
312
|
-
method_scope = Scope.new
|
84
|
+
method_scope = KatakataIrb::Scope.new(
|
85
|
+
scope,
|
86
|
+
{ **params_table, KatakataIrb::Scope::SELF => self_type, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil },
|
87
|
+
trace_lvar: false
|
88
|
+
)
|
313
89
|
evaluate_assign_params params, [], method_scope
|
314
|
-
method_scope.conditional { evaluate_param_defaults params,
|
90
|
+
method_scope.conditional { evaluate_param_defaults params, _1 }
|
315
91
|
simulate_evaluate body_stmt, method_scope
|
92
|
+
method_scope.merge_jumps
|
93
|
+
scope.update method_scope
|
316
94
|
end
|
317
95
|
KatakataIrb::Types::SYMBOL
|
318
96
|
in [:@int,]
|
@@ -414,7 +192,7 @@ class KatakataIrb::TypeSimulator
|
|
414
192
|
statements.map { simulate_evaluate _1, scope }.last
|
415
193
|
in [:const_path_ref, receiver, [:@const, name,]]
|
416
194
|
r = simulate_evaluate receiver, scope
|
417
|
-
(r in KatakataIrb::Types::SingletonType) ?
|
195
|
+
(r in KatakataIrb::Types::SingletonType) ? KatakataIrb::BaseScope.type_of { r.module_or_class.const_get name } : KatakataIrb::Types::NIL
|
418
196
|
in [:__var_ref_or_call, [type, name, pos]]
|
419
197
|
sexp = scope.has?(name) ? [:var_ref, [type, name, pos]] : [:vcall, [:@ident, name, pos]]
|
420
198
|
simulate_evaluate sexp, scope
|
@@ -456,13 +234,13 @@ class KatakataIrb::TypeSimulator
|
|
456
234
|
# workaround for https://bugs.ruby-lang.org/issues/19175
|
457
235
|
return scope[name]
|
458
236
|
end
|
459
|
-
receiver, method, args, kwargs, block,
|
237
|
+
receiver, method, args, kwargs, block, optional_chain = retrieve_method_call sexp
|
460
238
|
if receiver.nil? && method == 'raise'
|
461
|
-
scope.terminate_with RAISE_BREAK, KatakataIrb::Types::TRUE
|
239
|
+
scope.terminate_with KatakataIrb::Scope::RAISE_BREAK, KatakataIrb::Types::TRUE
|
462
240
|
return KatakataIrb::Types::NIL
|
463
241
|
end
|
464
242
|
receiver_type = receiver ? simulate_evaluate(receiver, scope) : scope.self_type
|
465
|
-
evaluate_method = lambda do
|
243
|
+
evaluate_method = lambda do |scope|
|
466
244
|
args_type = args.map do |arg|
|
467
245
|
if arg in KatakataIrb::Types::Splat
|
468
246
|
simulate_evaluate arg.item, scope
|
@@ -474,14 +252,14 @@ class KatakataIrb::TypeSimulator
|
|
474
252
|
|
475
253
|
if block
|
476
254
|
if block in [:symbol_literal, [:symbol, [:@ident, block_name,]]]
|
477
|
-
call_block_proc = ->(block_args) do
|
255
|
+
call_block_proc = ->(block_args, _self_type) do
|
478
256
|
block_receiver, *rest = block_args
|
479
257
|
block_receiver ? simulate_call(block_receiver || KatakataIrb::Types::OBJECT, block_name, rest, nil, nil) : KatakataIrb::Types::OBJECT
|
480
258
|
end
|
481
259
|
elsif block in [:do_block | :brace_block => type, block_var, body]
|
482
260
|
block_var in [:block_var, params,]
|
483
|
-
call_block_proc = ->(block_args) do
|
484
|
-
|
261
|
+
call_block_proc = ->(block_args, block_self_type) do
|
262
|
+
scope.conditional do |s|
|
485
263
|
if params
|
486
264
|
names = extract_param_names(params)
|
487
265
|
else
|
@@ -489,40 +267,52 @@ class KatakataIrb::TypeSimulator
|
|
489
267
|
params = [:params, names.map { [:@ident, _1, [0, 0]] }, nil, nil, nil, nil, nil, nil]
|
490
268
|
end
|
491
269
|
params_table = names.zip(block_args).to_h { [_1, _2 || KatakataIrb::Types::NIL] }
|
492
|
-
|
270
|
+
table = { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil }
|
271
|
+
table[KatakataIrb::Scope::SELF] = block_self_type if block_self_type
|
272
|
+
block_scope = KatakataIrb::Scope.new s, table
|
493
273
|
evaluate_assign_params params, block_args, block_scope
|
494
|
-
block_scope.conditional { evaluate_param_defaults params,
|
274
|
+
block_scope.conditional { evaluate_param_defaults params, _1 } if params
|
495
275
|
if type == :do_block
|
496
276
|
result = simulate_evaluate body, block_scope
|
497
277
|
else
|
498
278
|
result = body.map { simulate_evaluate _1, block_scope }.last
|
499
279
|
end
|
500
280
|
block_scope.merge_jumps
|
501
|
-
|
502
|
-
|
281
|
+
s.update block_scope
|
282
|
+
nexts = block_scope[KatakataIrb::Scope::NEXT_RESULT]
|
283
|
+
breaks = block_scope[KatakataIrb::Scope::BREAK_RESULT]
|
284
|
+
if block_scope.terminated?
|
285
|
+
[KatakataIrb::Types::UnionType[*nexts], breaks]
|
286
|
+
else
|
287
|
+
[KatakataIrb::Types::UnionType[result, *nexts], breaks]
|
288
|
+
end
|
503
289
|
end
|
504
|
-
[KatakataIrb::Types::UnionType[result, *nexts], breaks]
|
505
290
|
end
|
506
291
|
else
|
507
|
-
call_block_proc = ->(_block_args) { KatakataIrb::Types::OBJECT }
|
292
|
+
call_block_proc = ->(_block_args, _self_type) { KatakataIrb::Types::OBJECT }
|
508
293
|
simulate_evaluate block, scope
|
509
294
|
end
|
510
295
|
end
|
511
296
|
simulate_call receiver_type, method, args_type, kwargs_type(kwargs, scope), call_block_proc
|
512
297
|
end
|
513
|
-
if
|
514
|
-
scope.conditional { evaluate_method.call }
|
298
|
+
if optional_chain
|
299
|
+
result = scope.conditional { evaluate_method.call _1 }
|
300
|
+
if receiver_type.nillable?
|
301
|
+
KatakataIrb::Types::UnionType[result, KatakataIrb::Types::NIL]
|
302
|
+
else
|
303
|
+
result
|
304
|
+
end
|
515
305
|
else
|
516
|
-
evaluate_method.call
|
306
|
+
evaluate_method.call scope
|
517
307
|
end
|
518
308
|
in [:binary, a, Symbol => op, b]
|
519
309
|
atype = simulate_evaluate a, scope
|
520
310
|
case op
|
521
311
|
when :'&&', :and
|
522
|
-
btype = scope.conditional { simulate_evaluate b,
|
312
|
+
btype = scope.conditional { simulate_evaluate b, _1 }
|
523
313
|
KatakataIrb::Types::UnionType[btype, KatakataIrb::Types::NIL, KatakataIrb::Types::FALSE]
|
524
314
|
when :'||', :or
|
525
|
-
btype = scope.conditional { simulate_evaluate b,
|
315
|
+
btype = scope.conditional { simulate_evaluate b, _1 }
|
526
316
|
KatakataIrb::Types::UnionType[atype, btype]
|
527
317
|
else
|
528
318
|
btype = simulate_evaluate b, scope
|
@@ -535,11 +325,14 @@ class KatakataIrb::TypeSimulator
|
|
535
325
|
statements in [:bodystmt, statements, _unknown, _unknown, _unknown] # -> do end
|
536
326
|
params in [:paren, params]
|
537
327
|
params_table = extract_param_names(params).to_h { [_1, KatakataIrb::Types::NIL] }
|
538
|
-
block_scope = Scope.new scope, { **params_table, BREAK_RESULT => nil, NEXT_RESULT => nil, RETURN_RESULT => nil }
|
539
|
-
|
540
|
-
|
541
|
-
|
328
|
+
block_scope = KatakataIrb::Scope.new scope, { **params_table, KatakataIrb::Scope::BREAK_RESULT => nil, KatakataIrb::Scope::NEXT_RESULT => nil, KatakataIrb::Scope::RETURN_RESULT => nil }
|
329
|
+
block_scope.conditional do |s|
|
330
|
+
evaluate_assign_params params, [], s
|
331
|
+
s.conditional { evaluate_param_defaults params, _1 }
|
332
|
+
statements.each { simulate_evaluate _1, s }
|
333
|
+
end
|
542
334
|
block_scope.merge_jumps
|
335
|
+
scope.update block_scope
|
543
336
|
KatakataIrb::Types::ProcType.new
|
544
337
|
in [:assign, [:var_field, [:@gvar | :@ivar | :@cvar | :@ident | :@const, name,]], value]
|
545
338
|
res = simulate_evaluate value, scope
|
@@ -587,35 +380,37 @@ class KatakataIrb::TypeSimulator
|
|
587
380
|
in [:ifop, cond, tval, fval]
|
588
381
|
simulate_evaluate cond, scope
|
589
382
|
KatakataIrb::Types::UnionType[*scope.run_branches(
|
590
|
-
-> { simulate_evaluate tval,
|
591
|
-
-> { simulate_evaluate fval,
|
383
|
+
-> { simulate_evaluate tval, _1 },
|
384
|
+
-> { simulate_evaluate fval, _1 }
|
592
385
|
)]
|
593
386
|
in [:if_mod | :unless_mod, cond, statement]
|
594
387
|
simulate_evaluate cond, scope
|
595
|
-
KatakataIrb::Types::UnionType[scope.conditional { simulate_evaluate statement,
|
388
|
+
KatakataIrb::Types::UnionType[scope.conditional { simulate_evaluate statement, _1 }, KatakataIrb::Types::NIL]
|
596
389
|
in [:if | :unless | :elsif, cond, statements, else_statement]
|
597
390
|
simulate_evaluate cond, scope
|
598
391
|
results = scope.run_branches(
|
599
|
-
-> { statements.map { simulate_evaluate _1,
|
600
|
-
-> { else_statement ? simulate_evaluate(else_statement,
|
392
|
+
->(s) { statements.map { simulate_evaluate _1, s }.last },
|
393
|
+
->(s) { else_statement ? simulate_evaluate(else_statement, s) : KatakataIrb::Types::NIL }
|
601
394
|
)
|
602
395
|
results.empty? ? KatakataIrb::Types::NIL : KatakataIrb::Types::UnionType[*results]
|
603
396
|
in [:while | :until, cond, statements]
|
604
|
-
inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
|
397
|
+
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }, passthrough: true
|
605
398
|
simulate_evaluate cond, inner_scope
|
606
|
-
|
399
|
+
inner_scope.conditional { |s| statements.each { simulate_evaluate _1, s } }
|
607
400
|
inner_scope.merge_jumps
|
608
|
-
|
401
|
+
scope.update inner_scope
|
402
|
+
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
609
403
|
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
610
404
|
in [:while_mod | :until_mod, cond, statement]
|
611
|
-
inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
|
405
|
+
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }, passthrough: true
|
612
406
|
simulate_evaluate cond, inner_scope
|
613
|
-
|
407
|
+
inner_scope.conditional { |s| simulate_evaluate statement, s }
|
614
408
|
inner_scope.merge_jumps
|
615
|
-
|
409
|
+
scope.update inner_scope
|
410
|
+
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
616
411
|
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
617
412
|
in [:break | :next | :return => jump_type, value]
|
618
|
-
internal_key = jump_type == :break ? BREAK_RESULT : jump_type == :next ? NEXT_RESULT : RETURN_RESULT
|
413
|
+
internal_key = jump_type == :break ? KatakataIrb::Scope::BREAK_RESULT : jump_type == :next ? KatakataIrb::Scope::NEXT_RESULT : KatakataIrb::Scope::RETURN_RESULT
|
619
414
|
if value.empty?
|
620
415
|
jump_value = KatakataIrb::Types::NIL
|
621
416
|
else
|
@@ -626,7 +421,7 @@ class KatakataIrb::TypeSimulator
|
|
626
421
|
scope.terminate_with internal_key, jump_value
|
627
422
|
KatakataIrb::Types::NIL
|
628
423
|
in [:return0]
|
629
|
-
scope.terminate_with RETURN_RESULT, KatakataIrb::Types::NIL
|
424
|
+
scope.terminate_with KatakataIrb::Scope::RETURN_RESULT, KatakataIrb::Types::NIL
|
630
425
|
KatakataIrb::Types::NIL
|
631
426
|
in [:yield, args]
|
632
427
|
evaluate_mrhs args, scope
|
@@ -635,6 +430,8 @@ class KatakataIrb::TypeSimulator
|
|
635
430
|
KatakataIrb::Types::OBJECT
|
636
431
|
in [:redo | :retry]
|
637
432
|
scope.terminate
|
433
|
+
in [:zsuper]
|
434
|
+
KatakataIrb::Types::OBJECT
|
638
435
|
in [:super, args]
|
639
436
|
args, kwargs, _block = retrieve_method_args args
|
640
437
|
args.each do |arg|
|
@@ -647,47 +444,55 @@ class KatakataIrb::TypeSimulator
|
|
647
444
|
simulate_evaluate body_stmt, scope
|
648
445
|
in [:bodystmt, statements, rescue_stmt, _unknown, ensure_stmt]
|
649
446
|
statements = [statements] if statements in [Symbol,] # oneliner-def body
|
650
|
-
rescue_scope = Scope.new scope, { RAISE_BREAK => nil }, passthrough: true if rescue_stmt
|
447
|
+
rescue_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::RAISE_BREAK => nil }, passthrough: true if rescue_stmt
|
651
448
|
return_type = statements.map { simulate_evaluate _1, rescue_scope || scope }.last
|
652
|
-
rescue_scope&.merge_jumps
|
653
449
|
if rescue_stmt
|
654
|
-
|
450
|
+
rescue_scope.merge_jumps
|
451
|
+
scope.update rescue_scope
|
452
|
+
return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, _1 }]
|
655
453
|
end
|
656
454
|
simulate_evaluate ensure_stmt, scope if ensure_stmt
|
657
455
|
return_type
|
658
456
|
in [:rescue, error_class_stmts, error_var_stmt, statements, rescue_stmt]
|
659
|
-
return_type = scope.conditional do
|
457
|
+
return_type = scope.conditional do |s|
|
660
458
|
if error_var_stmt in [:var_field, [:@ident, error_var,]]
|
661
459
|
if (error_class_stmts in [:mrhs_new_from_args, Array => stmts, stmt])
|
662
460
|
error_class_stmts = [*stmts, stmt]
|
663
461
|
end
|
664
|
-
error_classes = (error_class_stmts || []).flat_map { simulate_evaluate _1,
|
462
|
+
error_classes = (error_class_stmts || []).flat_map { simulate_evaluate _1, s }.uniq
|
665
463
|
error_types = error_classes.filter_map { KatakataIrb::Types::InstanceType.new _1.module_or_class if _1 in KatakataIrb::Types::SingletonType }
|
666
464
|
error_types << KatakataIrb::Types::InstanceType.new(StandardError) if error_types.empty?
|
667
|
-
|
465
|
+
s[error_var] = KatakataIrb::Types::UnionType[*error_types]
|
668
466
|
end
|
669
|
-
statements.map { simulate_evaluate _1,
|
467
|
+
statements.map { simulate_evaluate _1, s }.last
|
670
468
|
end
|
671
469
|
if rescue_stmt
|
672
|
-
return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt,
|
470
|
+
return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, _1 }]
|
673
471
|
end
|
674
472
|
return_type
|
675
473
|
in [:rescue_mod, statement1, statement2]
|
676
|
-
rescue_scope = Scope.new scope, { RAISE_BREAK => nil }, passthrough: true
|
474
|
+
rescue_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::RAISE_BREAK => nil }, passthrough: true
|
677
475
|
a = simulate_evaluate statement1, rescue_scope
|
678
476
|
rescue_scope.merge_jumps
|
679
|
-
|
477
|
+
scope.update rescue_scope
|
478
|
+
b = scope.conditional { simulate_evaluate statement2, _1 }
|
680
479
|
KatakataIrb::Types::UnionType[a, b]
|
681
480
|
in [:module, module_stmt, body_stmt]
|
682
481
|
module_types = simulate_evaluate(module_stmt, scope).types.grep(KatakataIrb::Types::SingletonType)
|
683
482
|
module_types << KatakataIrb::Types::MODULE if module_types.empty?
|
684
|
-
|
483
|
+
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)
|
484
|
+
result = simulate_evaluate body_stmt, module_scope
|
485
|
+
scope.update module_scope
|
486
|
+
result
|
685
487
|
in [:sclass, klass_stmt, body_stmt]
|
686
488
|
klass_types = simulate_evaluate(klass_stmt, scope).types.filter_map do |type|
|
687
489
|
KatakataIrb::Types::SingletonType.new type.klass if type in KatakataIrb::Types::InstanceType
|
688
490
|
end
|
689
491
|
klass_types = [KatakataIrb::Types::CLASS] if klass_types.empty?
|
690
|
-
|
492
|
+
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)
|
493
|
+
result = simulate_evaluate body_stmt, sclass_scope
|
494
|
+
scope.update sclass_scope
|
495
|
+
result
|
691
496
|
in [:class, klass_stmt, superclass_stmt, body_stmt]
|
692
497
|
klass_types = simulate_evaluate(klass_stmt, scope).types
|
693
498
|
klass_types += simulate_evaluate(superclass_stmt, scope).types if superclass_stmt
|
@@ -695,7 +500,10 @@ class KatakataIrb::TypeSimulator
|
|
695
500
|
(type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
696
501
|
end
|
697
502
|
klass_types << KatakataIrb::Types::CLASS if klass_types.empty?
|
698
|
-
|
503
|
+
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)
|
504
|
+
result = simulate_evaluate body_stmt, klass_scope
|
505
|
+
scope.update klass_scope
|
506
|
+
result
|
699
507
|
in [:for, fields, enum, statements]
|
700
508
|
fields = [fields] if fields in [:var_field | :field | :aref_field,]
|
701
509
|
params = [:params, fields, nil, nil, nil, nil, nil, nil]
|
@@ -703,47 +511,49 @@ class KatakataIrb::TypeSimulator
|
|
703
511
|
extract_param_names(params).each { scope[_1] = KatakataIrb::Types::NIL }
|
704
512
|
response = simulate_call enum, :first, [], nil, nil
|
705
513
|
evaluate_assign_params params, [response], scope
|
706
|
-
inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
|
707
|
-
scope.conditional do
|
708
|
-
statements.each { simulate_evaluate _1,
|
514
|
+
inner_scope = KatakataIrb::Scope.new scope, { KatakataIrb::Scope::BREAK_RESULT => nil }, passthrough: true
|
515
|
+
scope.conditional do |s|
|
516
|
+
statements.each { simulate_evaluate _1, s }
|
709
517
|
end
|
710
518
|
inner_scope.merge_jumps
|
711
|
-
|
519
|
+
scope.update inner_scope
|
520
|
+
breaks = inner_scope[KatakataIrb::Scope::BREAK_RESULT]
|
712
521
|
breaks ? KatakataIrb::Types::UnionType[breaks, enum] : enum
|
713
522
|
in [:when, pattern, if_statements, else_statement]
|
714
|
-
eval_pattern = lambda do |pattern, *rest|
|
715
|
-
simulate_evaluate pattern,
|
716
|
-
scope.conditional { eval_pattern.call(*rest) } if rest.any?
|
523
|
+
eval_pattern = lambda do |s, pattern, *rest|
|
524
|
+
simulate_evaluate pattern, s
|
525
|
+
scope.conditional { eval_pattern.call(_1, *rest) } if rest.any?
|
717
526
|
end
|
718
|
-
if_branch = lambda do
|
719
|
-
eval_pattern.call(*pattern)
|
720
|
-
if_statements.map { simulate_evaluate _1,
|
527
|
+
if_branch = lambda do |s|
|
528
|
+
eval_pattern.call(s, *pattern)
|
529
|
+
if_statements.map { simulate_evaluate _1, s }.last
|
721
530
|
end
|
722
|
-
else_branch = lambda do
|
723
|
-
pattern.each { simulate_evaluate _1,
|
724
|
-
simulate_evaluate(else_statement,
|
531
|
+
else_branch = lambda do |s|
|
532
|
+
pattern.each { simulate_evaluate _1, s }
|
533
|
+
simulate_evaluate(else_statement, s, case_target: case_target)
|
725
534
|
end
|
726
535
|
if if_statements && else_statement
|
727
536
|
KatakataIrb::Types::UnionType[*scope.run_branches(if_branch, else_branch)]
|
728
537
|
else
|
729
|
-
KatakataIrb::Types::UnionType[scope.conditional { (if_branch || else_branch).call }, KatakataIrb::Types::NIL]
|
538
|
+
KatakataIrb::Types::UnionType[scope.conditional { (if_branch || else_branch).call _1 }, KatakataIrb::Types::NIL]
|
730
539
|
end
|
731
540
|
in [:in, [:var_field, [:@ident, name,]], if_statements, else_statement]
|
732
541
|
scope.never { simulate_evaluate else_statement, scope } if else_statement
|
733
542
|
scope[name] = case_target || KatakataIrb::Types::OBJECT
|
734
543
|
if_statements ? if_statements.map { simulate_evaluate _1, scope }.last : KatakataIrb::Types::NIL
|
735
544
|
in [:in, pattern, if_statements, else_statement]
|
736
|
-
pattern_scope = Scope.new(scope, { PATTERNMATCH_BREAK => nil }, passthrough: true)
|
737
|
-
results =
|
738
|
-
-> {
|
739
|
-
match_pattern case_target, pattern,
|
740
|
-
if_statements ? if_statements.map { simulate_evaluate _1,
|
545
|
+
pattern_scope = KatakataIrb::Scope.new(scope, { KatakataIrb::Scope::PATTERNMATCH_BREAK => nil }, passthrough: true)
|
546
|
+
results = pattern_scope.run_branches(
|
547
|
+
->(s) {
|
548
|
+
match_pattern case_target, pattern, s
|
549
|
+
if_statements ? if_statements.map { simulate_evaluate _1, s }.last : KatakataIrb::Types::NIL
|
741
550
|
},
|
742
|
-
-> {
|
743
|
-
|
744
|
-
else_statement ? simulate_evaluate(else_statement, scope, case_target:) : KatakataIrb::Types::NIL
|
551
|
+
->(s) {
|
552
|
+
else_statement ? simulate_evaluate(else_statement, s, case_target: case_target) : KatakataIrb::Types::NIL
|
745
553
|
}
|
746
554
|
)
|
555
|
+
pattern_scope.merge_jumps
|
556
|
+
scope.update pattern_scope
|
747
557
|
KatakataIrb::Types::UnionType[*results]
|
748
558
|
in [:case, target_exp, match_exp]
|
749
559
|
target = simulate_evaluate target_exp, scope
|
@@ -751,11 +561,16 @@ class KatakataIrb::TypeSimulator
|
|
751
561
|
in [:void_stmt]
|
752
562
|
KatakataIrb::Types::NIL
|
753
563
|
in [:dot2 | :dot3, range_beg, range_end]
|
754
|
-
simulate_evaluate range_beg, scope if range_beg
|
755
|
-
simulate_evaluate range_end, scope if range_end
|
756
|
-
KatakataIrb::Types::
|
564
|
+
beg_type = simulate_evaluate range_beg, scope if range_beg
|
565
|
+
end_type = simulate_evaluate range_end, scope if range_end
|
566
|
+
elem = (KatakataIrb::Types::UnionType[*[beg_type, end_type].compact]).nonnillable
|
567
|
+
KatakataIrb::Types::InstanceType.new Range, { Elem: elem }
|
757
568
|
in [:top_const_ref, [:@const, name,]]
|
758
|
-
|
569
|
+
KatakataIrb::BaseScope.type_of { Object.const_get name }
|
570
|
+
in [:string_concat, a, b]
|
571
|
+
simulate_evaluate a, scope
|
572
|
+
simulate_evaluate b, scope
|
573
|
+
KatakataIrb::Types::STRING
|
759
574
|
else
|
760
575
|
KatakataIrb.log_puts
|
761
576
|
KatakataIrb.log_puts :NOMATCH
|
@@ -765,7 +580,7 @@ class KatakataIrb::TypeSimulator
|
|
765
580
|
end
|
766
581
|
|
767
582
|
def match_pattern(target, pattern, scope)
|
768
|
-
breakable = -> { scope.
|
583
|
+
breakable = -> { scope.terminate_with KatakataIrb::Scope::PATTERNMATCH_BREAK, KatakataIrb::Types::NIL }
|
769
584
|
types = target.types
|
770
585
|
case pattern
|
771
586
|
in [:var_field, [:@ident, name,]]
|
@@ -777,7 +592,7 @@ class KatakataIrb::TypeSimulator
|
|
777
592
|
breakable.call
|
778
593
|
in [:binary, lpattern, :|, rpattern]
|
779
594
|
match_pattern target, lpattern, scope
|
780
|
-
scope.conditional { match_pattern target, rpattern,
|
595
|
+
scope.conditional { match_pattern target, rpattern, _1 }
|
781
596
|
breakable.call
|
782
597
|
in [:binary, lpattern, :'=>', [:var_field, [:@ident, name,]] => rpattern]
|
783
598
|
if lpattern in [:var_ref, [:@const, _const_name,]]
|
@@ -892,7 +707,7 @@ class KatakataIrb::TypeSimulator
|
|
892
707
|
in [:@ident, name,]
|
893
708
|
# block arg mlhs
|
894
709
|
scope[name] = value || KatakataIrb::Types::OBJECT
|
895
|
-
in [:var_field, [:@
|
710
|
+
in [:var_field, [:@gvar | :@ivar | :@cvar | :@ident | :@const, name,]]
|
896
711
|
# massign
|
897
712
|
scope[name] = value || KatakataIrb::Types::OBJECT
|
898
713
|
in [:mlhs, *mlhs]
|
@@ -932,37 +747,29 @@ class KatakataIrb::TypeSimulator
|
|
932
747
|
KatakataIrb::Types::InstanceType.new(Hash, K: KatakataIrb::Types::UnionType[*keys], V: KatakataIrb::Types::UnionType[*values])
|
933
748
|
end
|
934
749
|
|
935
|
-
def self.type_of(fallback: KatakataIrb::Types::OBJECT)
|
936
|
-
begin
|
937
|
-
KatakataIrb::Types.type_from_object yield
|
938
|
-
rescue
|
939
|
-
fallback
|
940
|
-
end
|
941
|
-
end
|
942
|
-
|
943
750
|
def retrieve_method_call(sexp)
|
944
|
-
|
751
|
+
optional = -> { _1 in [:@op, '&.',] }
|
945
752
|
case sexp
|
946
753
|
in [:fcall | :vcall, [:@ident | :@const | :@kw | :@op, method,]] # hoge
|
947
754
|
[nil, method, [], [], nil, false]
|
948
755
|
in [:call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, :call]
|
949
|
-
[receiver, :call, [], [], nil,
|
756
|
+
[receiver, :call, [], [], nil, optional[dot]]
|
950
757
|
in [:call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, method]
|
951
758
|
method => [:@ident | :@const | :@kw | :@op, method,] unless method == :call
|
952
|
-
[receiver, method, [], [], nil,
|
759
|
+
[receiver, method, [], [], nil, optional[dot]]
|
953
760
|
in [:command, [:@ident | :@const | :@kw | :@op, method,], args] # hoge 1, 2
|
954
761
|
args, kwargs, block = retrieve_method_args args
|
955
762
|
[nil, method, args, kwargs, block, false]
|
956
763
|
in [:command_call, receiver, [:@period,] | [:@op, '&.',] | :'::' => dot, [:@ident | :@const | :@kw | :@op, method,], args] # a.hoge 1; a.hoge 1, 2;
|
957
764
|
args, kwargs, block = retrieve_method_args args
|
958
|
-
[receiver, method, args, kwargs, block,
|
765
|
+
[receiver, method, args, kwargs, block, optional[dot]]
|
959
766
|
in [:method_add_arg, call, args]
|
960
|
-
receiver, method, _arg, _kwarg, _block,
|
767
|
+
receiver, method, _arg, _kwarg, _block, opt = retrieve_method_call call
|
961
768
|
args, kwargs, block = retrieve_method_args args
|
962
|
-
[receiver, method, args, kwargs, block,
|
769
|
+
[receiver, method, args, kwargs, block, opt]
|
963
770
|
in [:method_add_block, call, block]
|
964
|
-
receiver, method, args, kwargs,
|
965
|
-
[receiver, method, args, kwargs, block,
|
771
|
+
receiver, method, args, kwargs, opt = retrieve_method_call call
|
772
|
+
[receiver, method, args, kwargs, block, opt]
|
966
773
|
end
|
967
774
|
end
|
968
775
|
|
@@ -1031,16 +838,25 @@ class KatakataIrb::TypeSimulator
|
|
1031
838
|
params_type = method.block.type.required_positionals.map do |func_param|
|
1032
839
|
KatakataIrb::Types.from_rbs_type func_param.type, receiver, vars
|
1033
840
|
end
|
1034
|
-
|
841
|
+
self_type = KatakataIrb::Types.from_rbs_type method.block.self_type, receiver, vars if method.block.self_type
|
842
|
+
block_response, breaks = block.call params_type, self_type
|
1035
843
|
block_called = true
|
1036
844
|
vars.merge! KatakataIrb::Types.match_free_variables(free_vars - vars.keys.to_set, [method.block.type.return_type], [block_response])
|
1037
845
|
end
|
1038
846
|
[KatakataIrb::Types.from_rbs_type(method.type.return_type, receiver, vars || {}), breaks]
|
1039
847
|
end
|
1040
|
-
block&.call [] unless block_called
|
848
|
+
block&.call [], nil unless block_called
|
1041
849
|
types = type_breaks.map(&:first)
|
1042
850
|
breaks = type_breaks.map(&:last).compact
|
1043
851
|
types << OBJECT_METHODS[method_name.to_sym] if name_match && OBJECT_METHODS.has_key?(method_name.to_sym)
|
852
|
+
|
853
|
+
if method_name.to_sym == :new
|
854
|
+
receiver.types.each do |type|
|
855
|
+
if (type in KatakataIrb::Types::SingletonType) && type.module_or_class.is_a?(Class)
|
856
|
+
types << KatakataIrb::Types::InstanceType.new(type.module_or_class)
|
857
|
+
end
|
858
|
+
end
|
859
|
+
end
|
1044
860
|
KatakataIrb::Types::UnionType[*types, *breaks]
|
1045
861
|
end
|
1046
862
|
|
@@ -1148,7 +964,7 @@ class KatakataIrb::TypeSimulator
|
|
1148
964
|
dig_targets = DigTarget.new(parents, target) do |_types, scope|
|
1149
965
|
return scope
|
1150
966
|
end
|
1151
|
-
scope = Scope.from_binding(binding)
|
967
|
+
scope = KatakataIrb::Scope.from_binding(binding)
|
1152
968
|
new(dig_targets).simulate_evaluate parents[0], scope
|
1153
969
|
scope
|
1154
970
|
end
|
@@ -1157,7 +973,7 @@ class KatakataIrb::TypeSimulator
|
|
1157
973
|
dig_targets = DigTarget.new(parents, receiver) do |type, _scope|
|
1158
974
|
return type
|
1159
975
|
end
|
1160
|
-
new(dig_targets).simulate_evaluate parents[0], Scope.from_binding(binding)
|
976
|
+
new(dig_targets).simulate_evaluate parents[0], KatakataIrb::Scope.from_binding(binding)
|
1161
977
|
KatakataIrb::Types::NIL
|
1162
978
|
end
|
1163
979
|
end
|