katakata_irb 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e13d1b43d98e8be7595125b4e1e27533d83da1ee4d87df0dfb613d8fb8adee4
4
- data.tar.gz: ae508bc65cd1049100fe4811b1d2b27036b30131cab13821d52b637e91e2ed41
3
+ metadata.gz: 882c0834b6d52916911b26b82083e1100491dd24cafdb1c948c4c1795fe03d7e
4
+ data.tar.gz: 2250eaec5d0b1cabc236f238249e132206b62e70ada1c16429567b680ace2093
5
5
  SHA512:
6
- metadata.gz: be9ed49c8de27772f7ec154df136134e9d5319a851fe392656a67d3c49069ed040a41b2af8deb6e81577c0c59c6d5bc0918a8165e09ccab2bce15fd6f09abba8
7
- data.tar.gz: 8d9554e6532488742e156d39e7ee63c3c2461900db42badfd0d49990e35769b1e0f34a8cd746d5aab57839d3f31e894a081ec42389cd2383dafab5043d3fa578
6
+ metadata.gz: 60f3c4de13636f2948e740b3a57b6091c1f193ae7fa259d665c69a404833ef413b90aca3da7360f97be2d7a669e9a0d5fc101ff172890c4f0714c9eb63db8dd4
7
+ data.tar.gz: eb496c54819de4f1e035e261a6afffcc13d2809b316428602567614dbc5671df5ead97fb4a0696afbb34a7ade9ce8a2b3e9579ebad4ddd006d9a32b120b3e05d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- katakata_irb (0.1.4)
4
+ katakata_irb (0.1.5)
5
5
  irb (>= 1.4.0)
6
6
  rbs
7
7
 
@@ -27,18 +27,18 @@ module KatakataIrb::Completor
27
27
  ((self_call ? type.all_methods: type.methods).map(&:to_s) - HIDDEN_METHODS) | type.constants
28
28
  in [:const, type, name]
29
29
  type.constants
30
- in [:ivar, name, _scope]
30
+ in [:ivar, name, *_scope]
31
31
  # TODO: scope
32
32
  ivars = binding.eval('self').instance_variables rescue []
33
33
  cvars = (binding.eval('self').class_variables rescue nil) if name == '@'
34
34
  ivars | (cvars || [])
35
- in [:cvar, name, _scope]
35
+ in [:cvar, name, *_scope]
36
36
  # TODO: scope
37
37
  binding.eval('self').class_variables rescue []
38
38
  in [:gvar, name]
39
39
  global_variables
40
40
  in [:symbol, name]
41
- Symbol.all_symbols
41
+ Symbol.all_symbols.map { _1.inspect[1..] }
42
42
  in [:call, type, name, self_call]
43
43
  (self_call ? type.all_methods : type.methods).map(&:to_s) - HIDDEN_METHODS
44
44
  in [:lvar_or_method, name, scope]
@@ -67,15 +67,15 @@ module KatakataIrb::Completor
67
67
  method_doc = -> type do
68
68
  type = type.types.find { _1.all_methods.include? name.to_sym }
69
69
  if type in KatakataIrb::Types::SingletonType
70
- "#{type.module_or_class.name}.#{name}"
70
+ "#{KatakataIrb::Types.class_name_of(type.module_or_class)}.#{name}"
71
71
  elsif type in KatakataIrb::Types::InstanceType
72
- "#{type.klass.name}##{name}"
72
+ "#{KatakataIrb::Types.class_name_of(type.klass)}##{name}"
73
73
  end
74
74
  end
75
75
  call_or_const_doc = -> type do
76
76
  if name =~ /\A[A-Z]/
77
77
  type = type.types.grep(KatakataIrb::Types::SingletonType).find { _1.module_or_class.const_defined?(name) }
78
- type.module_or_class == Object ? name : "#{type.module_or_class.name}::#{name}" if type
78
+ type.module_or_class == Object ? name : "#{KatakataIrb::Types.class_name_of(type.module_or_class)}::#{name}" if type
79
79
  else
80
80
  method_doc.call(type)
81
81
  end
@@ -97,9 +97,50 @@ module KatakataIrb::Completor
97
97
  end
98
98
  end
99
99
  }
100
+ setup_type_dialog
100
101
  end
101
102
 
102
- def self.analyze(code, binding = Kernel.binding)
103
+ def self.setup_type_dialog
104
+ type_dialog_proc = -> {
105
+ return if just_cursor_moving && completion_journey_data
106
+ cursor_pos_to_render, _result, pointer, autocomplete_dialog = context.last(4)
107
+ return unless cursor_pos_to_render && autocomplete_dialog&.width && pointer.nil?
108
+ receiver_type = (
109
+ case KatakataIrb::Completor.prev_analyze_result
110
+ in [:call_or_const, type, name, _self_call] if name.empty?
111
+ type
112
+ in [:call, type, name, _self_call] if name.empty?
113
+ type
114
+ else
115
+ return
116
+ end
117
+ )
118
+ return unless receiver_type
119
+ types = type.types
120
+ contents = types.filter_map do |type|
121
+ case type
122
+ when KatakataIrb::Types::InstanceType
123
+ KatakataIrb::Types.class_name_of type.klass
124
+ when KatakataIrb::Types::SingletonType
125
+ module_name = KatakataIrb::Types.class_name_of type.module_or_class
126
+ "#{module_name}.itself" if module_name
127
+ end
128
+ end.uniq
129
+ return if contents.empty?
130
+
131
+ width = contents.map { Reline::Unicode.calculate_width _1 }.max
132
+ x = cursor_pos_to_render.x + autocomplete_dialog.width
133
+ y = cursor_pos_to_render.y
134
+ Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: 44, fg_color: 37)
135
+ }
136
+ Reline.add_dialog_proc(:show_type, type_dialog_proc, Reline::DEFAULT_DIALOG_CONTEXT)
137
+ end
138
+
139
+ def self.empty_binding()
140
+ Kernel.binding
141
+ end
142
+
143
+ def self.analyze(code, binding = empty_binding)
103
144
  lvars_code = binding.local_variables.map do |name|
104
145
  "#{name}="
105
146
  end.join + "nil;\n"
@@ -124,10 +165,20 @@ module KatakataIrb::Completor
124
165
  t.tok
125
166
  when /\A<<[~-]?(?:"(?<s>.+)"|'(?<s>.+)'|(?<s>.+))/
126
167
  $/ + ($1 || $2 || $3) + $/
168
+ when ':"', ":'", ':'
169
+ t.tok[1]
170
+ when '?'
171
+ # ternary operator
172
+ ' : value'
173
+ when '|'
174
+ # block args
175
+ '|'
127
176
  else
128
177
  $/ + 'end'
129
178
  end
130
179
  end
180
+ # remove error tokens
181
+ tokens.pop while tokens&.last&.tok&.empty?
131
182
 
132
183
  case tokens.last
133
184
  in { event: :on_ignored_by_ripper, tok: '.' }
@@ -136,6 +187,9 @@ module KatakataIrb::Completor
136
187
  in { dot: true }
137
188
  suffix = 'method'
138
189
  name = ''
190
+ in { event: :on_symbeg }
191
+ suffix = 'symbol'
192
+ name = ''
139
193
  in { event: :on_ident | :on_kw, tok: }
140
194
  return unless code.delete_suffix! tok
141
195
  suffix = 'method'
@@ -148,10 +202,21 @@ module KatakataIrb::Completor
148
202
  return unless code.delete_suffix! tok
149
203
  suffix = 'string'
150
204
  name = tok.rstrip
205
+ in { event: :on_gvar, tok: }
206
+ return unless code.delete_suffix! tok
207
+ suffix = '$gvar'
208
+ name = tok
209
+ in { event: :on_ivar, tok: }
210
+ return unless code.delete_suffix! tok
211
+ suffix = '@ivar'
212
+ name = tok
213
+ in { event: :on_cvar, tok: }
214
+ return unless code.delete_suffix! tok
215
+ suffix = '@@cvar'
216
+ name = tok
151
217
  else
152
218
  return
153
219
  end
154
-
155
220
  sexp = Ripper.sexp code + suffix + closings.reverse.join
156
221
  lines = code.lines
157
222
  line_no = lines.size
@@ -175,16 +240,26 @@ module KatakataIrb::Completor
175
240
  return [:cvar, name] if icvar_available
176
241
  end
177
242
  return unless expression
243
+ calculate_scope = -> { KatakataIrb::TypeSimulator.calculate_binding_scope binding, parents, expression }
244
+ calculate_receiver = -> receiver { KatakataIrb::TypeSimulator.calculate_receiver binding, parents, receiver }
245
+
178
246
  if (target in [:@tstring_content,]) && (parents[-4] in [:command, [:@ident, 'require' | 'require_relative' => require_method,],])
247
+ # `require 'target'`
179
248
  return [require_method.to_sym, name.rstrip]
180
249
  end
181
- calculate_scope = -> { KatakataIrb::TypeSimulator.calculate_binding_scope binding, parents, expression }
182
- calculate_receiver = -> receiver { KatakataIrb::TypeSimulator.calculate_receiver binding, parents, receiver }
250
+ if (target in [:@ident,]) && (expression in [:symbol,]) && (parents[-2] in [:args_add_block, Array => args, [:symbol_literal, ^expression]])
251
+ # `method(&:target)`
252
+ receiver_ref = [:var_ref, [:@ident, '_1', [0, 0]]]
253
+ block_statements = [receiver_ref]
254
+ parents[-1] = parents[-2][-1] = [:brace_block, nil, block_statements]
255
+ parents << block_statements
256
+ return [:call, calculate_receiver.call(receiver_ref), name, false]
257
+ end
183
258
  case expression
184
259
  in [:vcall | :var_ref, [:@ident,]]
185
260
  [:lvar_or_method, name, calculate_scope.call]
186
261
  in [:symbol, [:@ident | :@const | :@op | :@kw,]]
187
- [:symbol, name]
262
+ [:symbol, name] unless name.empty?
188
263
  in [:var_ref | :const_ref, [:@const,]]
189
264
  # TODO
190
265
  [:const, KatakataIrb::Types::SingletonType.new(Object), name]
@@ -26,6 +26,8 @@ module KatakataIrb::NestingParser
26
26
  interpolated
27
27
  end
28
28
 
29
+ IGNOREABLE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
30
+
29
31
  def self.parse(tokens)
30
32
  opens = []
31
33
  pending_heredocs = []
@@ -42,7 +44,7 @@ module KatakataIrb::NestingParser
42
44
  when :in_lambda_head
43
45
  opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
44
46
  when :in_method_head
45
- unless %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end].include?(t.event)
47
+ unless IGNOREABLE_TOKENS.include?(t.event)
46
48
  next_args = []
47
49
  body = nil
48
50
  if args.include?(:receiver)
@@ -127,13 +129,27 @@ module KatakataIrb::NestingParser
127
129
  skip = true if t.event == :on_kw && t.tok == 'do'
128
130
  opens[-1] = [last_tok, nil]
129
131
  end
132
+ when :in_block_head
133
+ if t.event == :on_op && t.tok == '|'
134
+ opens[-1] = [last_tok, nil]
135
+ opens << [t, :in_block_args]
136
+ elsif !IGNOREABLE_TOKENS.include?(t.event)
137
+ opens[-1] = [last_tok, nil]
138
+ end
139
+ when :in_block_args
140
+ if t.event == :on_op && t.tok == '|' && t.state.allbits?(Ripper::EXPR_BEG)
141
+ opens.pop
142
+ skip = true
143
+ end
130
144
  end
131
145
 
132
146
  unless skip
133
147
  case t.event
134
148
  when :on_kw
135
149
  case t.tok
136
- when 'begin', 'class', 'module', 'do', 'case'
150
+ when 'do'
151
+ opens << [t, :in_block_head]
152
+ when 'begin', 'class', 'module', 'case'
137
153
  opens << [t, nil]
138
154
  when 'end'
139
155
  opens.pop
@@ -163,9 +179,15 @@ module KatakataIrb::NestingParser
163
179
  opens << [t, nil]
164
180
  end
165
181
  end
182
+ when :on_lbrace
183
+ if t.state.allbits?(Ripper::EXPR_LABEL)
184
+ opens << [t, nil]
185
+ else
186
+ opens << [t, :in_block_head]
187
+ end
166
188
  when :on_tlambda
167
189
  opens << [t, :in_lambda_head]
168
- when :on_lparen, :on_lbracket, :on_lbrace, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
190
+ when :on_lparen, :on_lbracket, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
169
191
  opens << [t, nil]
170
192
  when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
171
193
  opens.pop
@@ -179,6 +201,15 @@ module KatakataIrb::NestingParser
179
201
  opens << [t, nil]
180
202
  when :on_tstring_end, :on_regexp_end, :on_label_end
181
203
  opens.pop
204
+ when :on_op
205
+ case t.tok
206
+ when '?'
207
+ # opening of `cond ? value : value``
208
+ opens << [t, nil]
209
+ when ':'
210
+ # closing of `cond ? value : value``
211
+ opens.pop
212
+ end
182
213
  when :on_symbeg
183
214
  if t.tok == ':'
184
215
  opens << [t, :in_unquoted_symbol]
@@ -0,0 +1,248 @@
1
+ require 'set'
2
+ require_relative 'types'
3
+
4
+ module KatakataIrb
5
+ class BaseScope
6
+ SELF = '%self'
7
+ BREAK_RESULT = '%break'
8
+ NEXT_RESULT = '%next'
9
+ RETURN_RESULT = '%return'
10
+ PATTERNMATCH_BREAK = '%match'
11
+ RAISE_BREAK = '%raise'
12
+
13
+ def initialize(binding, self_object)
14
+ @binding, @self_object = binding, self_object
15
+ @cache = { SELF => KatakataIrb::Types.type_from_object(self_object) }
16
+ @local_variables = binding.local_variables.map(&:to_s).to_set
17
+ end
18
+
19
+ def level() = 0
20
+
21
+ def level_of(name)
22
+ has?(name) ? 0 : nil
23
+ end
24
+
25
+ def mutable?() = false
26
+
27
+ def [](name)
28
+ @cache[name] ||= (
29
+ fallback = KatakataIrb::Types::NIL
30
+ case BaseScope.type_by_name name
31
+ when :cvar
32
+ BaseScope.type_of(fallback: fallback) { @self_object.class_variable_get name }
33
+ when :ivar
34
+ BaseScope.type_of(fallback: fallback) { @self_object.instance_variable_get name }
35
+ when :lvar
36
+ BaseScope.type_of(fallback: fallback) { @binding.local_variable_get(name) }
37
+ when :const
38
+ BaseScope.type_of(fallback: fallback) { @binding.eval name }
39
+ end
40
+ )
41
+ end
42
+
43
+ def self_type
44
+ self[SELF]
45
+ end
46
+
47
+ def local_variables
48
+ @local_variables.to_a
49
+ end
50
+
51
+ def self.type_of(fallback: KatakataIrb::Types::OBJECT)
52
+ begin
53
+ KatakataIrb::Types.type_from_object yield
54
+ rescue
55
+ fallback
56
+ end
57
+ end
58
+
59
+ def self.type_by_name(name)
60
+ if name.start_with? '@@'
61
+ :cvar
62
+ elsif name.start_with? '@'
63
+ :ivar
64
+ elsif name.start_with? '$'
65
+ :gvar
66
+ elsif name.start_with? '%'
67
+ :internal
68
+ elsif name[0].downcase != name[0]
69
+ :const
70
+ else
71
+ :lvar
72
+ end
73
+ end
74
+
75
+ def has?(name)
76
+ case BaseScope.type_by_name name
77
+ when :lvar
78
+ @local_variables.include? name
79
+ when :const
80
+ @binding.eval("#{name};true") rescue false
81
+ when :gvar, :cvar, :ivar
82
+ true
83
+ when :internal
84
+ true
85
+ end
86
+ end
87
+ end
88
+
89
+ class Scope < BaseScope
90
+ attr_reader :parent, :jump_branches, :mergeable_changes, :level
91
+
92
+ def self.from_binding(binding) = new(BaseScope.new(binding, binding.eval('self')))
93
+
94
+ def initialize(parent, table = {}, trace_cvar: true, trace_ivar: true, trace_lvar: true, passthrough: false)
95
+ @table = table
96
+ @parent = parent
97
+ @level = parent.level + (passthrough ? 0 : 1)
98
+ @trace_cvar = trace_cvar
99
+ @trace_ivar = trace_ivar
100
+ @trace_lvar = trace_lvar
101
+ @passthrough = passthrough
102
+ @terminated = false
103
+ @jump_branches = []
104
+ @mergeable_changes = @changes = table.transform_values { [level, _1] }
105
+ end
106
+
107
+ def mutable? = true
108
+
109
+ def terminated?
110
+ @terminated
111
+ end
112
+
113
+ def terminate_with(type, value)
114
+ return if terminated?
115
+ store_jump type, value, @mergeable_changes
116
+ terminate
117
+ end
118
+
119
+ def store_jump(type, value, changes)
120
+ return if terminated?
121
+ if has_own?(type)
122
+ changes[type] = [level, value]
123
+ @jump_branches << changes
124
+ elsif @parent.mutable?
125
+ @parent.store_jump(type, value, changes)
126
+ end
127
+ end
128
+
129
+ def terminate
130
+ return if terminated?
131
+ @terminated = true
132
+ @changes = @mergeable_changes.dup
133
+ end
134
+
135
+ def branch_table_clone() = @tables.last.dup
136
+
137
+ def trace?(name)
138
+ return false unless @parent
139
+ type = BaseScope.type_by_name(name)
140
+ type == :cvar ? @trace_cvar : type == :ivar ? @trace_ivar : type == :lvar ? @trace_lvar : true
141
+ end
142
+
143
+ def level_of(name)
144
+ variable_level, = @changes[name]
145
+ variable_level || parent.level_of(name)
146
+ end
147
+
148
+ def [](name)
149
+ level, value = @changes[name]
150
+ if level
151
+ value
152
+ elsif trace? name
153
+ @parent[name] if trace? name
154
+ end
155
+ end
156
+
157
+ def []=(name, value)
158
+ variable_level = level_of(name) || level
159
+ @changes[name] = [variable_level, value]
160
+ end
161
+
162
+ def self_type
163
+ self[SELF]
164
+ end
165
+
166
+ def local_variables
167
+ lvar_keys = @changes.keys.select do |name|
168
+ BaseScope.type_by_name(name) == :lvar
169
+ end
170
+ lvar_keys |= @parent.local_variables if @trace_lvar
171
+ lvar_keys
172
+ end
173
+
174
+ def merge_jumps
175
+ if terminated?
176
+ @terminated = false
177
+ @changes = @mergeable_changes
178
+ merge @jump_branches
179
+ @terminated = true
180
+ else
181
+ merge [*@jump_branches, {}]
182
+ end
183
+ end
184
+
185
+ def conditional(&block)
186
+ run_branches(block, ->(_s) {}).first || KatakataIrb::Types::NIL
187
+ end
188
+
189
+ def never(&block)
190
+ block.call Scope.new(self, { BREAK_RESULT => nil, NEXT_RESULT => nil, PATTERNMATCH_BREAK => nil, RETURN_RESULT => nil, RAISE_BREAK => nil }, passthrough: true)
191
+ end
192
+
193
+ def run(*args, **option)
194
+ scope = Scope.new(self, *args, **option)
195
+ yield scope
196
+ merge_jumps
197
+ update scope
198
+ end
199
+
200
+ def run_branches(*blocks)
201
+ results = []
202
+ branches = []
203
+ blocks.each do |block|
204
+ scope = Scope.new self, passthrough: true
205
+ result = block.call scope
206
+ next if scope.terminated?
207
+ results << result
208
+ branches << scope.mergeable_changes
209
+ end
210
+ terminate if branches.empty?
211
+ merge branches
212
+ results
213
+ end
214
+
215
+ def has?(name)
216
+ has_own?(name) || (trace?(name) && @parent.has?(name))
217
+ end
218
+
219
+ def has_own?(name)
220
+ @changes.key? name
221
+ end
222
+
223
+ def update(child_scope)
224
+ current_level = level
225
+ child_scope.mergeable_changes.each do |name, (level, value)|
226
+ self[name] = value if level <= current_level
227
+ end
228
+ end
229
+
230
+ protected
231
+
232
+ def merge(branches)
233
+ current_level = level
234
+ merge = {}
235
+ branches.each do |changes|
236
+ changes.each do |name, (level, value)|
237
+ next if current_level < level
238
+ (merge[name] ||= []) << value
239
+ end
240
+ end
241
+ merge.each do |name, values|
242
+ values << self[name] unless values.size == branches.size
243
+ values.compact!
244
+ self[name] = KatakataIrb::Types::UnionType[*values.compact] unless values.empty?
245
+ end
246
+ end
247
+ end
248
+ end