katakata_irb 0.1.0 → 0.1.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.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
|