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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07b0eb3288cc4eec15c83de9bd27948379bca2c1dfa233104cba59dff6826c7c
4
- data.tar.gz: 20d4feb90c4df7e10554e045addfb242af50205dd0b187635a81ac3bc5b073b2
3
+ metadata.gz: 4b1d8be38e882e8b24f1f3add323f4160e36d8300d9ae1d9e22572a6c7c272ad
4
+ data.tar.gz: a2918483fbfd537fcfaa7fd6423727ec3a9b458da86329b803fc8f48dbe565d7
5
5
  SHA512:
6
- metadata.gz: 7a376d7deb729f3a2e2f3b18041e89606d668e331ece73c32d5b7ae9ff6b8d87bffa89f4ab3d1dc66c8354b3af2ad733bee211868e01bd8814055f3cc72fe83b
7
- data.tar.gz: 50eaa7061da8609623f1fccc5d0fbe12685f888d7a565eede06e19993b435aa766ce6458668fa787369bef62ce5601b6dd9c4118fa534457c89341881367722d
6
+ metadata.gz: 7c9437f1bd885f507bac318bfef116f3c0aa86c606a694167b4436eb3e48e7b51789d9fcb8387155ec20cf28166fdb3fe0f162fbc9777f57758d74f368fcfad7
7
+ data.tar.gz: b4512a603b807f8566dc5fb0d60cb0185e384b2c0129c6a91dceecbba4abd093df8d8a07ad9a817b18279fec7f9dfc6011560128b68e5e55e177ca9a7ae3a5dc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- katakata_irb (0.1.0)
4
+ katakata_irb (0.1.1)
5
5
  rbs
6
6
 
7
7
  GEM
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, unclosed_heredocs = KatakataIrb::TRex.parse(tokens)
65
- closings = (last_opens + unclosed_heredocs).map do |t,|
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
- closings = $/ + closings.reverse.join($/)
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, [lvars_exp, *rest_statements]]
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 [type, String, [Integer, Integer]]
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
- raise unless code.include? target
20
- code.sub! target, replace
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
- puts "Failed to apply katakata_irb/reline_patches/#{patch_name}.patch to reline"
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) - [:initialize_input, :set_prompt, :process_continue, :check_code_block]).each { RubyLex.remove_method _1 }
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(tokens)
15
+ def calc_nesting_depth(opens)
16
16
  indent_level = 0
17
17
  nesting_level = 0
18
- tokens.each_with_index do |t, index|
18
+ opens.each_with_index do |t, index|
19
19
  case t.event
20
20
  when :on_heredoc_beg
21
- if tokens[index + 1]&.event != :on_heredoc_beg
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, heredocs = KatakataIrb::TRex.parse(tokens)
42
- indent, _nesting = calc_nesting_depth(opens.map(&:first) + heredocs)
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
- lines, = KatakataIrb::TRex.parse_line(tokens)
48
- result = lines[line_index]
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).map(&:first))
52
- prev_depth, = calc_nesting_depth(prev.map(&:first))
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
- *lines, last_line = code.lines
76
- last_line if lines.any? && check_termination(lines.join, context: context)
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(code, context: nil)
80
- tokens = KatakataIrb::RubyLexPatch.complete_tokens(code, context: context)
81
- opens, heredocs = KatakataIrb::TRex.parse(tokens)
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
- check_termination(code, context: context)
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
- lines, _unclosed_heredocs = KatakataIrb::TRex.parse_line(tokens)
126
+ line_results = KatakataIrb::TRex.parse_line(tokens)
112
127
  continue = false
113
- lines.map.with_index do |(line, _prev_opens, next_opens), line_num_offset|
114
- unless (c = process_continue(line.map(&:first))).nil?
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 opens.map(&:first)
150
- _indent, nesting_level = calc_nesting_depth opens.map(&:first)
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
- next if l.nil?
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
- _line, _prev_opens, next_opens = KatakataIrb::TRex.parse_line(tokens).first.last
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
@@ -176,7 +176,7 @@ module KatakataIrb::TRex
176
176
  end
177
177
  yield t, index, opens if block_given?
178
178
  end
179
- [opens, pending_heredocs.reverse]
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, unclosed_heredocs = KatakataIrb::TRex.parse(tokens) do |t, _index, 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.dup
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
- [output, unclosed_heredocs]
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
- # return if terminated?
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, method_name_exp, params, body_stmt]
283
- sexp in [:defs, receiver_exp, dot_exp, method_name_exp, params, body_stmt]
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
- simulate_evaluate cond, scope
592
- scope.conditional { simulate_evaluate statement, scope }
593
- KatakataIrb::Types::NIL
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
- scope[internal_key] = KatakataIrb::Types::NIL
616
+ jump_value = KatakataIrb::Types::NIL
598
617
  else
599
618
  values, kw = evaluate_mrhs value, scope
600
619
  values << kw if kw
601
- scope[internal_key] = values.size == 1 ? values.first : KatakataIrb::Types::InstanceType.new(Array, Elem: KatakataIrb::Types::UnionType[*values])
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[RETURN_RESULT] = KatakataIrb::Types::NIL
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
- return_type = statements.map { simulate_evaluate _1, scope }.last
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
- a = simulate_evaluate statement1, scope
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, scope }
704
+ statements.each { simulate_evaluate _1, inner_scope }
680
705
  end
681
- enum
682
- in [:in | :when => mode, pattern, if_statements, else_statement]
683
- if mode == :in
684
- if_match = -> { match_pattern case_target, pattern, scope }
685
- else_match = -> { scope.conditional { if_match.call } }
686
- else
687
- eval_pattern = lambda do |pattern, *rest|
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
- if_match.call
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
- else_match.call
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, const_name,]]
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 unless value_pattern
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, keywords, keyrest, block]
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
- case keyrest
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
- case block
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
@@ -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 definition
20
+ return method if method
21
21
  end
22
22
  nil
23
23
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KatakataIrb
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/katakata_irb.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'io/console'
1
2
  module KatakataIrb
2
3
  def self.repl
3
4
  require 'katakata_irb/completor'
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.0
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-09 00:00:00.000000000 Z
11
+ date: 2022-12-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbs