katakata_irb 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/bin/console +1 -1
- data/exe/kirb +2 -1
- data/lib/katakata_irb/completor.rb +12 -12
- data/lib/katakata_irb/reline_patch.rb +6 -3
- data/lib/katakata_irb/ruby_lex_patch.rb +49 -30
- data/lib/katakata_irb/trex.rb +4 -4
- data/lib/katakata_irb/type_simulator.rb +94 -51
- data/lib/katakata_irb/types.rb +1 -1
- data/lib/katakata_irb/version.rb +1 -1
- data/lib/katakata_irb.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b1d8be38e882e8b24f1f3add323f4160e36d8300d9ae1d9e22572a6c7c272ad
|
4
|
+
data.tar.gz: a2918483fbfd537fcfaa7fd6423727ec3a9b458da86329b803fc8f48dbe565d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c9437f1bd885f507bac318bfef116f3c0aa86c606a694167b4436eb3e48e7b51789d9fcb8387155ec20cf28166fdb3fe0f162fbc9777f57758d74f368fcfad7
|
7
|
+
data.tar.gz: b4512a603b807f8566dc5fb0d60cb0185e384b2c0129c6a91dceecbba4abd093df8d8a07ad9a817b18279fec7f9dfc6011560128b68e5e55e177ca9a7ae3a5dc
|
data/Gemfile.lock
CHANGED
data/bin/console
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require_relative '../lib/katakata_irb'
|
3
3
|
require_relative '../lib/katakata_irb/reline_patch'
|
4
|
-
KatakataIrb::RelinePatch.require_patched_reline
|
5
4
|
KatakataIrb.log_output = STDERR
|
5
|
+
KatakataIrb::RelinePatch.require_patched_reline
|
6
6
|
require 'bundler/setup'
|
7
7
|
require 'katakata_irb'
|
8
8
|
require 'katakata_irb/ruby_lex_patch'
|
data/exe/kirb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require_relative '../lib/katakata_irb'
|
3
|
+
KatakataIrb.log_output = STDERR if ARGV.delete '--debug-output'
|
2
4
|
unless ARGV.delete '--without-patch'
|
3
5
|
require_relative '../lib/katakata_irb/reline_patch'
|
4
6
|
KatakataIrb::RelinePatch.require_patched_reline
|
@@ -6,5 +8,4 @@ unless ARGV.delete '--without-patch'
|
|
6
8
|
KatakataIrb::RubyLexPatch.patch_to_ruby_lex
|
7
9
|
end
|
8
10
|
require 'katakata_irb'
|
9
|
-
KatakataIrb.log_output = STDERR if ARGV.delete '--debug-output'
|
10
11
|
KatakataIrb.repl
|
@@ -61,25 +61,26 @@ module KatakataIrb::Completor
|
|
61
61
|
code = lvars_code + code
|
62
62
|
tokens = RubyLex.ripper_lex_without_warning code
|
63
63
|
tokens = KatakataIrb::TRex.interpolate_ripper_ignored_tokens code, tokens
|
64
|
-
last_opens
|
65
|
-
closings =
|
64
|
+
last_opens = KatakataIrb::TRex.parse(tokens)
|
65
|
+
closings = last_opens.map do |t|
|
66
66
|
case t.tok
|
67
67
|
when /\A%.[<>]\z/
|
68
|
-
'>'
|
68
|
+
$/ + '>'
|
69
69
|
when '{', '#{', /\A%.?[{}]\z/
|
70
|
-
'}'
|
70
|
+
$/ + '}'
|
71
71
|
when '(', /\A%.?[()]\z/
|
72
|
+
# do not insert \n before closing paren. workaround to avoid syntax error of "a in ^(b\n)"
|
72
73
|
')'
|
73
74
|
when '[', /\A%.?[\[\]]\z/
|
74
|
-
']'
|
75
|
+
$/ + ']'
|
75
76
|
when /\A%.?(.)\z/
|
76
77
|
$1
|
77
78
|
when '"', "'", '/', '`'
|
78
79
|
t.tok
|
79
|
-
when /\A<<(?:"(?<s>.+)"|'(?<s>.+)'|(?<s>.+))/
|
80
|
-
$3
|
80
|
+
when /\A<<[~-]?(?:"(?<s>.+)"|'(?<s>.+)'|(?<s>.+))/
|
81
|
+
$/ + ($1 || $2 || $3) + $/
|
81
82
|
else
|
82
|
-
'end'
|
83
|
+
$/ + 'end'
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
@@ -107,8 +108,7 @@ module KatakataIrb::Completor
|
|
107
108
|
return
|
108
109
|
end
|
109
110
|
|
110
|
-
|
111
|
-
sexp = Ripper.sexp code + suffix + closings
|
111
|
+
sexp = Ripper.sexp code + suffix + closings.reverse.join
|
112
112
|
lines = code.lines
|
113
113
|
line_no = lines.size
|
114
114
|
col = lines.last.bytesize
|
@@ -117,14 +117,14 @@ module KatakataIrb::Completor
|
|
117
117
|
col = 0
|
118
118
|
end
|
119
119
|
|
120
|
-
if sexp in [:program, [
|
120
|
+
if sexp in [:program, [_lvars_exp, *rest_statements]]
|
121
121
|
sexp = [:program, rest_statements]
|
122
122
|
end
|
123
123
|
|
124
124
|
*parents, expression, target = find_target sexp, line_no, col
|
125
125
|
in_class_module = parents&.any? { _1 in [:class | :module,] }
|
126
126
|
icvar_available = !in_class_module
|
127
|
-
return unless target in [
|
127
|
+
return unless target in [_type, String, [Integer, Integer]]
|
128
128
|
if target in [:@ivar,]
|
129
129
|
return [:ivar, name] if icvar_available
|
130
130
|
elsif target in [:@cvar,]
|
@@ -16,14 +16,17 @@ module KatakataIrb::RelinePatch
|
|
16
16
|
diff.split(/^@@.+\n/).drop(1).map(&:lines).each do |lines|
|
17
17
|
target = lines.reject { _1[0] == '+' }.map { _1[1..] }.join
|
18
18
|
replace = lines.reject { _1[0] == '-' }.map { _1[1..] }.join
|
19
|
-
|
20
|
-
|
19
|
+
if code.include? target
|
20
|
+
code = code.sub target, replace
|
21
|
+
elsif !code.include?(replace)
|
22
|
+
raise
|
23
|
+
end
|
21
24
|
end
|
22
25
|
current_patched[path] = code
|
23
26
|
end
|
24
27
|
patched.update current_patched
|
25
28
|
rescue
|
26
|
-
|
29
|
+
KatakataIrb.log_puts "Failed to apply katakata_irb/reline_patches/#{patch_name}.patch to reline"
|
27
30
|
end
|
28
31
|
|
29
32
|
RelinePatchIseqLoader.define_method :load_iseq do |fname|
|
@@ -3,7 +3,7 @@ require_relative 'trex'
|
|
3
3
|
|
4
4
|
module KatakataIrb::RubyLexPatch
|
5
5
|
def self.patch_to_ruby_lex
|
6
|
-
(RubyLex.instance_methods(false) - [:
|
6
|
+
(RubyLex.instance_methods(false) - [:set_prompt, :process_continue, :check_code_block]).each { RubyLex.remove_method _1 }
|
7
7
|
RubyLex.prepend self
|
8
8
|
end
|
9
9
|
|
@@ -12,20 +12,20 @@ module KatakataIrb::RubyLexPatch
|
|
12
12
|
KatakataIrb::TRex.interpolate_ripper_ignored_tokens(code, incomplete_tokens)
|
13
13
|
end
|
14
14
|
|
15
|
-
def calc_nesting_depth(
|
15
|
+
def calc_nesting_depth(opens)
|
16
16
|
indent_level = 0
|
17
17
|
nesting_level = 0
|
18
|
-
|
18
|
+
opens.each_with_index do |t, index|
|
19
19
|
case t.event
|
20
20
|
when :on_heredoc_beg
|
21
|
-
if
|
21
|
+
if opens[index + 1]&.event != :on_heredoc_beg
|
22
22
|
if t.tok.start_with?('<<~')
|
23
23
|
indent_level += 1
|
24
24
|
else
|
25
25
|
indent_level = 0
|
26
26
|
end
|
27
27
|
end
|
28
|
-
when :on_tstring_beg, :on_regexp_beg
|
28
|
+
when :on_tstring_beg, :on_regexp_beg, :on_symbeg
|
29
29
|
indent_level += 1 if t.tok[0] == '%'
|
30
30
|
when :on_embdoc_beg
|
31
31
|
indent_level = 0
|
@@ -38,18 +38,18 @@ module KatakataIrb::RubyLexPatch
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def process_indent_level(tokens)
|
41
|
-
opens
|
42
|
-
indent, _nesting = calc_nesting_depth(opens
|
41
|
+
opens = KatakataIrb::TRex.parse(tokens)
|
42
|
+
indent, _nesting = calc_nesting_depth(opens)
|
43
43
|
indent * 2
|
44
44
|
end
|
45
45
|
|
46
46
|
def check_corresponding_token_depth(tokens, line_index)
|
47
|
-
|
48
|
-
result =
|
47
|
+
line_results = KatakataIrb::TRex.parse_line(tokens)
|
48
|
+
result = line_results[line_index]
|
49
49
|
return unless result
|
50
50
|
_tokens, prev, opens, min_depth = result
|
51
|
-
depth, = calc_nesting_depth(opens.take(min_depth)
|
52
|
-
prev_depth, = calc_nesting_depth(prev
|
51
|
+
depth, = calc_nesting_depth(opens.take(min_depth))
|
52
|
+
prev_depth, = calc_nesting_depth(prev)
|
53
53
|
depth * 2 if depth < prev_depth
|
54
54
|
end
|
55
55
|
|
@@ -62,9 +62,9 @@ module KatakataIrb::RubyLexPatch
|
|
62
62
|
?'
|
63
63
|
when ?", /^<</, /^%.$/, /^%Q.$/
|
64
64
|
?"
|
65
|
-
when ":'", ':"', ':', /^%s
|
65
|
+
when ":'", ':"', ':', /^%s.$/
|
66
66
|
':'
|
67
|
-
when /^%[iwIW]
|
67
|
+
when /^%[iwIW].$/
|
68
68
|
']'
|
69
69
|
when '/', /^%r.$/
|
70
70
|
'/'
|
@@ -72,14 +72,28 @@ module KatakataIrb::RubyLexPatch
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def check_termination_in_prev_line(code, context: nil)
|
75
|
-
|
76
|
-
|
75
|
+
tokens = self.class.ripper_lex_without_warning(code, context: context)
|
76
|
+
last_newline_index = tokens.rindex { |t| t.tok.include?("\n") }
|
77
|
+
index = (0...last_newline_index).reverse_each.find { |i| tokens[i].tok.include?("\n") }
|
78
|
+
return false unless index
|
79
|
+
|
80
|
+
last_line_tokens = tokens[(index + 1)..(tokens.size - 1)]
|
81
|
+
first_token = last_line_tokens.find do |t|
|
82
|
+
![:on_sp, :on_ignored_sp, :on_comment].include?(t.event)
|
83
|
+
end
|
84
|
+
|
85
|
+
if first_token && first_token.state != Ripper::EXPR_DOT
|
86
|
+
tokens_without_last_line = tokens[0..index]
|
87
|
+
if check_termination(tokens_without_last_line)
|
88
|
+
return last_line_tokens.map(&:tok).join
|
89
|
+
end
|
90
|
+
end
|
91
|
+
false
|
77
92
|
end
|
78
93
|
|
79
|
-
def check_termination(
|
80
|
-
|
81
|
-
opens
|
82
|
-
opens.empty? && heredocs.empty? && !process_continue(tokens)
|
94
|
+
def check_termination(tokens)
|
95
|
+
opens = KatakataIrb::TRex.parse(tokens)
|
96
|
+
opens.empty? && !process_continue(tokens)
|
83
97
|
end
|
84
98
|
|
85
99
|
def set_input(io, p = nil, context: nil, &block)
|
@@ -99,7 +113,8 @@ module KatakataIrb::RubyLexPatch
|
|
99
113
|
false
|
100
114
|
end
|
101
115
|
else
|
102
|
-
|
116
|
+
tokens = KatakataIrb::RubyLexPatch.complete_tokens(code, context: context)
|
117
|
+
check_termination(tokens)
|
103
118
|
end
|
104
119
|
end
|
105
120
|
end
|
@@ -108,10 +123,14 @@ module KatakataIrb::RubyLexPatch
|
|
108
123
|
lines << '' if lines.empty?
|
109
124
|
code = lines.map{ |l| l + "\n" }.join
|
110
125
|
tokens = KatakataIrb::RubyLexPatch.complete_tokens code, context: context
|
111
|
-
|
126
|
+
line_results = KatakataIrb::TRex.parse_line(tokens)
|
112
127
|
continue = false
|
113
|
-
|
114
|
-
|
128
|
+
tokens_until_line = []
|
129
|
+
line_results.map.with_index do |(line_tokens, _prev_opens, next_opens), line_num_offset|
|
130
|
+
line_tokens.each do |token, _s|
|
131
|
+
tokens_until_line << token if token != tokens_until_line.last
|
132
|
+
end
|
133
|
+
unless (c = process_continue(tokens_until_line)).nil?
|
115
134
|
continue = c
|
116
135
|
end
|
117
136
|
prompt next_opens, continue, line_num_offset
|
@@ -146,8 +165,8 @@ module KatakataIrb::RubyLexPatch
|
|
146
165
|
end
|
147
166
|
|
148
167
|
def prompt(opens, continue, line_num_offset)
|
149
|
-
ltype = ltype_from_open_tokens
|
150
|
-
_indent, nesting_level = calc_nesting_depth
|
168
|
+
ltype = ltype_from_open_tokens(opens)
|
169
|
+
_indent, nesting_level = calc_nesting_depth(opens)
|
151
170
|
@prompt.call(ltype, nesting_level, opens.any? || continue, @line_no + line_num_offset)
|
152
171
|
end
|
153
172
|
|
@@ -166,10 +185,13 @@ module KatakataIrb::RubyLexPatch
|
|
166
185
|
store_prompt_to_irb [], false, 0
|
167
186
|
loop do
|
168
187
|
l = @input.call
|
169
|
-
|
188
|
+
unless l
|
189
|
+
return if line.empty?
|
190
|
+
next
|
191
|
+
end
|
170
192
|
line << l
|
171
193
|
tokens = KatakataIrb::RubyLexPatch.complete_tokens(line, context: context)
|
172
|
-
|
194
|
+
_line_tokens, _prev_opens, next_opens = KatakataIrb::TRex.parse_line(tokens).last
|
173
195
|
return line if next_opens.empty?
|
174
196
|
line_offset += 1
|
175
197
|
store_prompt_to_irb next_opens, true, line_offset
|
@@ -178,7 +200,6 @@ module KatakataIrb::RubyLexPatch
|
|
178
200
|
end
|
179
201
|
|
180
202
|
def each_top_level_statement(context = nil)
|
181
|
-
initialize_input
|
182
203
|
loop do
|
183
204
|
begin
|
184
205
|
line = readmultiline(context)
|
@@ -188,9 +209,7 @@ module KatakataIrb::RubyLexPatch
|
|
188
209
|
yield line, @line_no
|
189
210
|
end
|
190
211
|
@line_no += line.count("\n")
|
191
|
-
raise RubyLex::TerminateLineInput if @io.eof?
|
192
212
|
rescue RubyLex::TerminateLineInput
|
193
|
-
initialize_input
|
194
213
|
end
|
195
214
|
end
|
196
215
|
end
|
data/lib/katakata_irb/trex.rb
CHANGED
@@ -176,7 +176,7 @@ module KatakataIrb::TRex
|
|
176
176
|
end
|
177
177
|
yield t, index, opens if block_given?
|
178
178
|
end
|
179
|
-
|
179
|
+
opens.map(&:first) + pending_heredocs.reverse
|
180
180
|
end
|
181
181
|
|
182
182
|
def self.parse_line(tokens)
|
@@ -184,14 +184,14 @@ module KatakataIrb::TRex
|
|
184
184
|
prev_opens = []
|
185
185
|
min_depth = 0
|
186
186
|
output = []
|
187
|
-
last_opens
|
187
|
+
last_opens = KatakataIrb::TRex.parse(tokens) do |t, _index, opens|
|
188
188
|
depth = t == opens.last&.first ? opens.size - 1 : opens.size
|
189
189
|
min_depth = depth if depth < min_depth
|
190
190
|
if t.tok.include? "\n"
|
191
191
|
t.tok.each_line do |line|
|
192
192
|
line_tokens << [t, line]
|
193
193
|
next if line[-1] != "\n"
|
194
|
-
next_opens = opens.
|
194
|
+
next_opens = opens.map(&:first)
|
195
195
|
output << [line_tokens, prev_opens, next_opens, min_depth]
|
196
196
|
prev_opens = next_opens
|
197
197
|
min_depth = prev_opens.size
|
@@ -202,6 +202,6 @@ module KatakataIrb::TRex
|
|
202
202
|
end
|
203
203
|
end
|
204
204
|
output << [line_tokens, prev_opens, last_opens, min_depth] if line_tokens.any?
|
205
|
-
|
205
|
+
output
|
206
206
|
end
|
207
207
|
end
|
@@ -104,12 +104,18 @@ class KatakataIrb::TypeSimulator
|
|
104
104
|
@terminated
|
105
105
|
end
|
106
106
|
|
107
|
-
def terminate_with(type)
|
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)
|
108
115
|
scopes = ancestors.select(&:mutable?)
|
109
116
|
scope = scopes.find { _1.has_own? type } || scopes.last
|
110
117
|
index = scopes.index scope
|
111
118
|
scope.jump_branches << scopes.drop(index).map(&:branch_table_clone)
|
112
|
-
terminate
|
113
119
|
end
|
114
120
|
|
115
121
|
def terminate
|
@@ -132,8 +138,7 @@ class KatakataIrb::TypeSimulator
|
|
132
138
|
end
|
133
139
|
|
134
140
|
def []=(name, type)
|
135
|
-
|
136
|
-
if @passthrough && !BaseScope.type_by_name(name) == :internal
|
141
|
+
if @passthrough && BaseScope.type_by_name(name) != :internal
|
137
142
|
@parent[name] = type
|
138
143
|
elsif trace?(name) && @parent.mutable? && !@tables.any? { _1.key? name } && @parent.has?(name)
|
139
144
|
@parent[name] = type
|
@@ -189,6 +194,10 @@ class KatakataIrb::TypeSimulator
|
|
189
194
|
run_branches(block, -> {}).first || KatakataIrb::Types::NIL
|
190
195
|
end
|
191
196
|
|
197
|
+
def never(&block)
|
198
|
+
branch(&block)
|
199
|
+
end
|
200
|
+
|
192
201
|
def run_branches(*blocks)
|
193
202
|
results = blocks.map { branch(&_1) }.reject(&:last)
|
194
203
|
merge results.map { _2 }
|
@@ -263,6 +272,8 @@ class KatakataIrb::TypeSimulator
|
|
263
272
|
BREAK_RESULT = '%break'
|
264
273
|
NEXT_RESULT = '%next'
|
265
274
|
RETURN_RESULT = '%return'
|
275
|
+
PATTERNMATCH_BREAK = '%match'
|
276
|
+
RAISE_BREAK = '%raise'
|
266
277
|
|
267
278
|
def initialize(dig_targets)
|
268
279
|
@dig_targets = dig_targets
|
@@ -279,8 +290,8 @@ class KatakataIrb::TypeSimulator
|
|
279
290
|
in [:program, statements]
|
280
291
|
statements.map { simulate_evaluate _1, scope }.last
|
281
292
|
in [:def | :defs,]
|
282
|
-
sexp in [:def,
|
283
|
-
sexp in [:defs, receiver_exp,
|
293
|
+
sexp in [:def, _method_name_exp, params, body_stmt]
|
294
|
+
sexp in [:defs, receiver_exp, _dot_exp, _method_name_exp, params, body_stmt]
|
284
295
|
if receiver_exp
|
285
296
|
receiver_exp in [:paren, receiver_exp]
|
286
297
|
self_type = simulate_evaluate receiver_exp, scope
|
@@ -443,6 +454,10 @@ class KatakataIrb::TypeSimulator
|
|
443
454
|
return scope[name]
|
444
455
|
end
|
445
456
|
receiver, method, args, kwargs, block, conditional = retrieve_method_call sexp
|
457
|
+
if receiver.nil? && method == 'raise'
|
458
|
+
scope.terminate_with RAISE_BREAK, KatakataIrb::Types::TRUE
|
459
|
+
return KatakataIrb::Types::NIL
|
460
|
+
end
|
446
461
|
receiver_type = receiver ? simulate_evaluate(receiver, scope) : scope.self_type
|
447
462
|
evaluate_method = lambda do
|
448
463
|
args_type = args.map do |arg|
|
@@ -486,6 +501,7 @@ class KatakataIrb::TypeSimulator
|
|
486
501
|
[KatakataIrb::Types::UnionType[result, *nexts], breaks]
|
487
502
|
end
|
488
503
|
else
|
504
|
+
call_block_proc = ->(_block_args) { KatakataIrb::Types::OBJECT }
|
489
505
|
simulate_evaluate block, scope
|
490
506
|
end
|
491
507
|
end
|
@@ -584,33 +600,37 @@ class KatakataIrb::TypeSimulator
|
|
584
600
|
inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
|
585
601
|
simulate_evaluate cond, inner_scope
|
586
602
|
scope.conditional { statements.each { simulate_evaluate _1, inner_scope } }
|
587
|
-
breaks = inner_scope[BREAK_RESULT]
|
588
603
|
inner_scope.merge_jumps
|
604
|
+
breaks = inner_scope[BREAK_RESULT]
|
589
605
|
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
590
606
|
in [:while_mod | :until_mod, cond, statement]
|
591
|
-
|
592
|
-
|
593
|
-
|
607
|
+
inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
|
608
|
+
simulate_evaluate cond, inner_scope
|
609
|
+
scope.conditional { simulate_evaluate statement, inner_scope }
|
610
|
+
inner_scope.merge_jumps
|
611
|
+
breaks = inner_scope[BREAK_RESULT]
|
612
|
+
breaks ? KatakataIrb::Types::UnionType[breaks, KatakataIrb::Types::NIL] : KatakataIrb::Types::NIL
|
594
613
|
in [:break | :next | :return => jump_type, value]
|
595
614
|
internal_key = jump_type == :break ? BREAK_RESULT : jump_type == :next ? NEXT_RESULT : RETURN_RESULT
|
596
615
|
if value.empty?
|
597
|
-
|
616
|
+
jump_value = KatakataIrb::Types::NIL
|
598
617
|
else
|
599
618
|
values, kw = evaluate_mrhs value, scope
|
600
619
|
values << kw if kw
|
601
|
-
|
620
|
+
jump_value = values.size == 1 ? values.first : KatakataIrb::Types::InstanceType.new(Array, Elem: KatakataIrb::Types::UnionType[*values])
|
602
621
|
end
|
603
|
-
scope.terminate_with internal_key
|
622
|
+
scope.terminate_with internal_key, jump_value
|
604
623
|
KatakataIrb::Types::NIL
|
605
624
|
in [:return0]
|
606
|
-
scope
|
607
|
-
scope.terminate_with RETURN_RESULT
|
625
|
+
scope.terminate_with RETURN_RESULT, KatakataIrb::Types::NIL
|
608
626
|
KatakataIrb::Types::NIL
|
609
627
|
in [:yield, args]
|
610
628
|
evaluate_mrhs args, scope
|
611
629
|
KatakataIrb::Types::OBJECT
|
612
630
|
in [:yield0]
|
613
631
|
KatakataIrb::Types::OBJECT
|
632
|
+
in [:redo | :retry]
|
633
|
+
scope.terminate
|
614
634
|
in [:super, args]
|
615
635
|
args, kwargs, _block = retrieve_method_args args
|
616
636
|
args.each do |arg|
|
@@ -623,7 +643,9 @@ class KatakataIrb::TypeSimulator
|
|
623
643
|
simulate_evaluate body_stmt, scope
|
624
644
|
in [:bodystmt, statements, rescue_stmt, _unknown, ensure_stmt]
|
625
645
|
statements = [statements] if statements in [Symbol,] # oneliner-def body
|
626
|
-
|
646
|
+
rescue_scope = Scope.new scope, { RAISE_BREAK => nil }, passthrough: true if rescue_stmt
|
647
|
+
return_type = statements.map { simulate_evaluate _1, rescue_scope || scope }.last
|
648
|
+
rescue_scope&.merge_jumps
|
627
649
|
if rescue_stmt
|
628
650
|
return_type = KatakataIrb::Types::UnionType[return_type, scope.conditional { simulate_evaluate rescue_stmt, scope }]
|
629
651
|
end
|
@@ -647,7 +669,9 @@ class KatakataIrb::TypeSimulator
|
|
647
669
|
end
|
648
670
|
return_type
|
649
671
|
in [:rescue_mod, statement1, statement2]
|
650
|
-
|
672
|
+
rescue_scope = Scope.new scope, { RAISE_BREAK => nil }, passthrough: true
|
673
|
+
a = simulate_evaluate statement1, rescue_scope
|
674
|
+
rescue_scope.merge_jumps
|
651
675
|
b = scope.conditional { simulate_evaluate statement2, scope }
|
652
676
|
KatakataIrb::Types::UnionType[a, b]
|
653
677
|
in [:module, module_stmt, body_stmt]
|
@@ -675,39 +699,48 @@ class KatakataIrb::TypeSimulator
|
|
675
699
|
extract_param_names(params).each { scope[_1] = KatakataIrb::Types::NIL }
|
676
700
|
response = simulate_call enum, :first, [], nil, nil
|
677
701
|
evaluate_assign_params params, [response], scope
|
702
|
+
inner_scope = Scope.new scope, { BREAK_RESULT => nil }, passthrough: true
|
678
703
|
scope.conditional do
|
679
|
-
statements.each { simulate_evaluate _1,
|
704
|
+
statements.each { simulate_evaluate _1, inner_scope }
|
680
705
|
end
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
simulate_evaluate pattern, scope
|
689
|
-
scope.conditional { eval_pattern.call(*rest) } if rest.any?
|
690
|
-
end
|
691
|
-
if_match = -> { eval_pattern.call(*pattern) }
|
692
|
-
else_match = -> { pattern.each { simulate_evaluate _1, scope } }
|
706
|
+
inner_scope.merge_jumps
|
707
|
+
breaks = inner_scope[BREAK_RESULT]
|
708
|
+
breaks ? KatakataIrb::Types::UnionType[breaks, enum] : enum
|
709
|
+
in [:when, pattern, if_statements, else_statement]
|
710
|
+
eval_pattern = lambda do |pattern, *rest|
|
711
|
+
simulate_evaluate pattern, scope
|
712
|
+
scope.conditional { eval_pattern.call(*rest) } if rest.any?
|
693
713
|
end
|
694
714
|
if_branch = lambda do
|
695
|
-
|
715
|
+
eval_pattern.call(*pattern)
|
696
716
|
if_statements.map { simulate_evaluate _1, scope }.last
|
697
717
|
end
|
698
718
|
else_branch = lambda do
|
699
|
-
|
719
|
+
pattern.each { simulate_evaluate _1, scope }
|
700
720
|
simulate_evaluate(else_statement, scope, case_target:)
|
701
721
|
end
|
702
722
|
if if_statements && else_statement
|
703
723
|
KatakataIrb::Types::UnionType[*scope.run_branches(if_branch, else_branch)]
|
704
|
-
elsif if_statements
|
705
|
-
KatakataIrb::Types::UnionType[scope.conditional { if_branch.call }, KatakataIrb::Types::NIL]
|
706
|
-
elsif else_statement
|
707
|
-
KatakataIrb::Types::UnionType[scope.conditional { else_branch.call }, KatakataIrb::Types::NIL]
|
708
724
|
else
|
709
|
-
KatakataIrb::Types::NIL
|
725
|
+
KatakataIrb::Types::UnionType[scope.conditional { (if_branch || else_branch).call }, KatakataIrb::Types::NIL]
|
710
726
|
end
|
727
|
+
in [:in, [:var_field, [:@ident, name,]], if_statements, else_statement]
|
728
|
+
scope.never { simulate_evaluate else_statement, scope } if else_statement
|
729
|
+
scope[name] = case_target || KatakataIrb::Types::OBJECT
|
730
|
+
if_statements ? if_statements.map { simulate_evaluate _1, scope }.last : KatakataIrb::Types::NIL
|
731
|
+
in [:in, pattern, if_statements, else_statement]
|
732
|
+
pattern_scope = Scope.new(scope, { PATTERNMATCH_BREAK => nil }, passthrough: true)
|
733
|
+
results = scope.run_branches(
|
734
|
+
-> {
|
735
|
+
match_pattern case_target, pattern, pattern_scope
|
736
|
+
if_statements ? if_statements.map { simulate_evaluate _1, scope }.last : KatakataIrb::Types::NIL
|
737
|
+
},
|
738
|
+
-> {
|
739
|
+
pattern_scope.merge_jumps
|
740
|
+
else_statement ? simulate_evaluate(else_statement, scope, case_target:) : KatakataIrb::Types::NIL
|
741
|
+
}
|
742
|
+
)
|
743
|
+
KatakataIrb::Types::UnionType[*results]
|
711
744
|
in [:case, target_exp, match_exp]
|
712
745
|
target = simulate_evaluate target_exp, scope
|
713
746
|
simulate_evaluate match_exp, scope, case_target: target
|
@@ -728,6 +761,7 @@ class KatakataIrb::TypeSimulator
|
|
728
761
|
end
|
729
762
|
|
730
763
|
def match_pattern(target, pattern, scope)
|
764
|
+
breakable = -> { scope.store_jump PATTERNMATCH_BREAK }
|
731
765
|
types = target.types
|
732
766
|
case pattern
|
733
767
|
in [:var_field, [:@ident, name,]]
|
@@ -736,17 +770,20 @@ class KatakataIrb::TypeSimulator
|
|
736
770
|
in [:@int | :@float | :@rational | :@imaginary | :@CHAR | :symbol_literal | :string_literal | :regexp_literal,]
|
737
771
|
in [:begin, statement] # in (statement)
|
738
772
|
simulate_evaluate statement, scope
|
773
|
+
breakable.call
|
739
774
|
in [:binary, lpattern, :|, rpattern]
|
740
775
|
match_pattern target, lpattern, scope
|
741
|
-
match_pattern target, rpattern, scope
|
776
|
+
scope.conditional { match_pattern target, rpattern, scope }
|
777
|
+
breakable.call
|
742
778
|
in [:binary, lpattern, :'=>', [:var_field, [:@ident, name,]] => rpattern]
|
743
|
-
if lpattern in [:var_ref, [:@const,
|
779
|
+
if lpattern in [:var_ref, [:@const, _const_name,]]
|
744
780
|
const_value = simulate_evaluate lpattern, scope
|
745
781
|
if (const_value in KatakataIrb::Types::SingletonType) && const_value.module_or_class.is_a?(Class)
|
746
782
|
scope[name] = KatakataIrb::Types::InstanceType.new const_value.module_or_class
|
747
783
|
else
|
748
784
|
scope[name] = KatakataIrb::Types::OBJECT
|
749
785
|
end
|
786
|
+
breakable.call
|
750
787
|
else
|
751
788
|
match_pattern target, lpattern, scope
|
752
789
|
match_pattern target, rpattern, scope
|
@@ -760,6 +797,7 @@ class KatakataIrb::TypeSimulator
|
|
760
797
|
end
|
761
798
|
if splat in [:var_field, [:@ident, name,]]
|
762
799
|
scope[name] = KatakataIrb::Types::InstanceType.new Array, Elem: elem
|
800
|
+
breakable.call
|
763
801
|
end
|
764
802
|
post_items&.each do |item|
|
765
803
|
match_pattern elem, item, scope
|
@@ -770,18 +808,21 @@ class KatakataIrb::TypeSimulator
|
|
770
808
|
key_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:K] }]
|
771
809
|
value_type = KatakataIrb::Types::UnionType[*hash_types.filter_map { _1.params[:V] }]
|
772
810
|
items&.each do |key_pattern, value_pattern|
|
773
|
-
if key_pattern in [:@label, label,]
|
811
|
+
if (key_pattern in [:@label, label,]) && !value_pattern
|
774
812
|
name = label.delete ':'
|
775
|
-
scope[name] = value_type
|
813
|
+
scope[name] = value_type
|
814
|
+
breakable.call
|
776
815
|
end
|
777
816
|
match_pattern value_type, value_pattern, scope if value_pattern
|
778
817
|
end
|
779
818
|
if splat in [:var_field, [:@ident, name,]]
|
780
819
|
scope[name] = KatakataIrb::Types::InstanceType.new Hash, K: key_type, V: value_type
|
820
|
+
breakable.call
|
781
821
|
end
|
782
822
|
in [:if_mod, cond, ifpattern]
|
783
|
-
simulate_evaluate cond, scope
|
784
823
|
match_pattern target, ifpattern, scope
|
824
|
+
simulate_evaluate cond, scope
|
825
|
+
breakable.call
|
785
826
|
in [:dyna_symbol,]
|
786
827
|
in [:const_path_ref,]
|
787
828
|
else
|
@@ -852,6 +893,8 @@ class KatakataIrb::TypeSimulator
|
|
852
893
|
scope[name] = value || KatakataIrb::Types::OBJECT
|
853
894
|
in [:mlhs, *mlhs]
|
854
895
|
evaluate_massign mlhs, value || [], scope
|
896
|
+
in nil
|
897
|
+
# a, *, b = value
|
855
898
|
end
|
856
899
|
end
|
857
900
|
end
|
@@ -930,17 +973,20 @@ class KatakataIrb::TypeSimulator
|
|
930
973
|
[args, [], nil]
|
931
974
|
in [:args_add_block, [:args_add_star,] => args, block_arg]
|
932
975
|
args, kwargs, = retrieve_method_args args
|
976
|
+
block_arg = [:void_stmt] if block_arg.nil? # method(*splat, &)
|
933
977
|
[args, kwargs, block_arg]
|
934
978
|
in [:args_add_block, [*args, [:bare_assoc_hash,] => kw], block_arg]
|
979
|
+
block_arg = [:void_stmt] if block_arg.nil? # method(**splat, &)
|
935
980
|
_, kwargs = retrieve_method_args kw
|
936
981
|
[args, kwargs, block_arg]
|
937
982
|
in [:args_add_block, [*args], block_arg]
|
983
|
+
block_arg = [:void_stmt] if block_arg.nil? # method(arg, &)
|
938
984
|
[args, [], block_arg]
|
939
985
|
in [:bare_assoc_hash, kws]
|
940
986
|
kwargs = []
|
941
987
|
kws.each do |kw|
|
942
988
|
if kw in [:assoc_splat, value,]
|
943
|
-
kwargs << KatakataIrb::Types::Splat.new(value)
|
989
|
+
kwargs << KatakataIrb::Types::Splat.new(value) if value
|
944
990
|
elsif kw in [:assoc_new, [:@label, label,] => key, nil]
|
945
991
|
name = label.delete ':'
|
946
992
|
kwargs << [key, [:__var_ref_or_call, [name =~ /\A[A-Z]/ ? :@const : :@ident, name, [0, 0]]]]
|
@@ -955,7 +1001,7 @@ class KatakataIrb::TypeSimulator
|
|
955
1001
|
[args, kwargs, nil]
|
956
1002
|
in [:args_add_star, pre_args, star_arg, *post_args]
|
957
1003
|
pre_args, = retrieve_method_args pre_args if pre_args in [:args_add_star,]
|
958
|
-
args = [*pre_args, KatakataIrb::Types::Splat.new(star_arg), *post_args]
|
1004
|
+
args = star_arg ? [*pre_args, KatakataIrb::Types::Splat.new(star_arg), *post_args] : pre_args + post_args
|
959
1005
|
[args, [], nil]
|
960
1006
|
in [:arg_paren, args]
|
961
1007
|
args ? retrieve_method_args(args) : [[], [], nil]
|
@@ -1025,7 +1071,7 @@ class KatakataIrb::TypeSimulator
|
|
1025
1071
|
|
1026
1072
|
def evaluate_assign_params(params, values, scope)
|
1027
1073
|
values = values.dup
|
1028
|
-
params => [:params, pre_required, optional, rest, post_required,
|
1074
|
+
params => [:params, pre_required, optional, rest, post_required, _keywords, keyrest, block]
|
1029
1075
|
size = (pre_required&.size || 0) + (optional&.size || 0) + (post_required&.size || 0) + (rest ? 1 : 0)
|
1030
1076
|
if values.size == 1 && size >= 2
|
1031
1077
|
value = values.first
|
@@ -1042,6 +1088,7 @@ class KatakataIrb::TypeSimulator
|
|
1042
1088
|
scope[name] = KatakataIrb::Types::InstanceType.new Array, Elem: KatakataIrb::Types::UnionType[*rest_values]
|
1043
1089
|
end
|
1044
1090
|
evaluate_massign post_required, post_values, scope if post_required
|
1091
|
+
# TODO: assign keywords
|
1045
1092
|
if keyrest in [:kwrest_param, [:@ident, name,]]
|
1046
1093
|
scope[name] = KatakataIrb::Types::InstanceType.new Hash, K: KatakataIrb::Types::SYMBOL, V: KatakataIrb::Types::OBJECT
|
1047
1094
|
end
|
@@ -1064,14 +1111,10 @@ class KatakataIrb::TypeSimulator
|
|
1064
1111
|
name = label.delete ':'
|
1065
1112
|
scope[name] = value ? simulate_evaluate(value, scope) : KatakataIrb::Types::OBJECT
|
1066
1113
|
end
|
1067
|
-
|
1068
|
-
in [:args_forward] | nil
|
1069
|
-
in [:kwrest_param, [:@ident, name,]]
|
1114
|
+
if keyrest in [:kwrest_param, [:@ident, name,]]
|
1070
1115
|
scope[name] = KatakataIrb::Types::HASH
|
1071
1116
|
end
|
1072
|
-
|
1073
|
-
in :& | nil
|
1074
|
-
in [:blockarg, [:@ident, name,]]
|
1117
|
+
if block in [:blockarg, [:@ident, name,]]
|
1075
1118
|
scope[name] = KatakataIrb::Types::PROC
|
1076
1119
|
end
|
1077
1120
|
end
|
data/lib/katakata_irb/types.rb
CHANGED
@@ -17,7 +17,7 @@ module KatakataIrb::Types
|
|
17
17
|
type_name = RBS::TypeName(ancestor.name).absolute!
|
18
18
|
definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
|
19
19
|
method = definition&.methods&.[](method_name)
|
20
|
-
return method if
|
20
|
+
return method if method
|
21
21
|
end
|
22
22
|
nil
|
23
23
|
end
|
data/lib/katakata_irb/version.rb
CHANGED
data/lib/katakata_irb.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: katakata_irb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tompng
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-12-
|
11
|
+
date: 2022-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|