katakata_irb 0.1.12 → 0.2.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 +1 -0
- data/katakata_irb.gemspec +1 -0
- data/lib/katakata_irb/completor.rb +166 -218
- data/lib/katakata_irb/scope.rb +224 -81
- data/lib/katakata_irb/type_analyzer.rb +1168 -0
- data/lib/katakata_irb/types.rb +25 -11
- data/lib/katakata_irb/version.rb +1 -1
- data/lib/katakata_irb.rb +2 -0
- metadata +17 -4
- data/lib/katakata_irb/nesting_parser.rb +0 -257
- data/lib/katakata_irb/type_simulator.rb +0 -995
data/lib/katakata_irb/types.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'rbs/cli'
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module KatakataIrb; end
|
5
4
|
module KatakataIrb::Types
|
@@ -12,10 +11,12 @@ module KatakataIrb::Types
|
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.load_rbs_builder
|
14
|
+
require 'rbs'
|
15
|
+
require 'rbs/cli'
|
15
16
|
loader = RBS::CLI::LibraryOptions.new.loader
|
16
17
|
loader.add path: Pathname('sig')
|
17
18
|
RBS::DefinitionBuilder.new env: RBS::Environment.from_loader(loader).resolve_type_names
|
18
|
-
rescue => e
|
19
|
+
rescue LoadError, StandardError => e
|
19
20
|
@rbs_load_error = e
|
20
21
|
puts "\r\nKatakataIRB failed to initialize RBS::DefinitionBuilder: #{e.class}\r\n"
|
21
22
|
puts "See `KatakataIrb::Types.rbs_load_error` for more details.\r\n"
|
@@ -34,7 +35,7 @@ module KatakataIrb::Types
|
|
34
35
|
def self.rbs_search_method(klass, method_name, singleton)
|
35
36
|
klass.ancestors.each do |ancestor|
|
36
37
|
name = class_name_of ancestor
|
37
|
-
next unless name
|
38
|
+
next unless name && rbs_builder
|
38
39
|
type_name = RBS::TypeName(name).absolute!
|
39
40
|
definition = (singleton ? rbs_builder.build_singleton(type_name) : rbs_builder.build_instance(type_name)) rescue nil
|
40
41
|
method = definition.methods[method_name] if definition
|
@@ -77,7 +78,7 @@ module KatakataIrb::Types
|
|
77
78
|
[t, t.klass, false]
|
78
79
|
end
|
79
80
|
end
|
80
|
-
has_splat = args_types.any? { _1
|
81
|
+
has_splat = args_types.any? { _1.is_a? Splat }
|
81
82
|
methods_with_score = receivers.flat_map do |receiver_type, klass, singleton|
|
82
83
|
method = rbs_search_method klass, method_name, singleton
|
83
84
|
next [] unless method
|
@@ -91,9 +92,13 @@ module KatakataIrb::Types
|
|
91
92
|
keyreqs = method_type.type.required_keywords
|
92
93
|
keyopts = method_type.type.optional_keywords
|
93
94
|
keyrest = method_type.type.rest_keywords
|
94
|
-
args =
|
95
|
+
args = args_types
|
96
|
+
if kwargs_type&.any? && keyreqs.empty? && keyopts.empty? && keyrest.nil?
|
97
|
+
kw_value_type = UnionType[*kwargs_type.values]
|
98
|
+
args += [InstanceType.new(Hash, K: SYMBOL, V: kw_value_type)]
|
99
|
+
end
|
95
100
|
if has_splat
|
96
|
-
score += 1 if args.count { !(_1
|
101
|
+
score += 1 if args.count { !(_1.is_a? Splat) } <= reqs.size + opts.size + trailings.size
|
97
102
|
elsif reqs.size + trailings.size <= args.size && (rest || args.size <= reqs.size + opts.size + trailings.size)
|
98
103
|
score += 2
|
99
104
|
centers = args[reqs.size...-trailings.size]
|
@@ -202,7 +207,7 @@ module KatakataIrb::Types
|
|
202
207
|
def nonnillable() = self
|
203
208
|
def rbs_methods
|
204
209
|
name = KatakataIrb::Types.class_name_of(@klass)
|
205
|
-
return {} unless name
|
210
|
+
return {} unless name && KatakataIrb::Types.rbs_builder
|
206
211
|
|
207
212
|
type_name = RBS::TypeName(name).absolute!
|
208
213
|
KatakataIrb::Types.rbs_builder.build_instance(type_name).methods rescue {}
|
@@ -323,6 +328,11 @@ module KatakataIrb::Types
|
|
323
328
|
|
324
329
|
BOOLEAN = UnionType[TRUE, FALSE]
|
325
330
|
|
331
|
+
def self.array_of(*types)
|
332
|
+
type = types.size >= 2 ? UnionType[*types] : types.first || OBJECT
|
333
|
+
InstanceType.new Array, Elem: type
|
334
|
+
end
|
335
|
+
|
326
336
|
def self.from_rbs_type(return_type, self_type, extra_vars = {})
|
327
337
|
case return_type
|
328
338
|
when RBS::Types::Bases::Self
|
@@ -365,11 +375,11 @@ module KatakataIrb::Types
|
|
365
375
|
when RBS::Types::Variable
|
366
376
|
if extra_vars.key? return_type.name
|
367
377
|
extra_vars[return_type.name]
|
368
|
-
elsif self_type
|
378
|
+
elsif self_type.is_a? InstanceType
|
369
379
|
self_type.params[return_type.name] || OBJECT
|
370
|
-
elsif self_type
|
380
|
+
elsif self_type.is_a? UnionType
|
371
381
|
types = self_type.types.filter_map do |t|
|
372
|
-
t.params[return_type.name] if t
|
382
|
+
t.params[return_type.name] if t.is_a? InstanceType
|
373
383
|
end
|
374
384
|
UnionType[*types]
|
375
385
|
else
|
@@ -403,6 +413,10 @@ module KatakataIrb::Types
|
|
403
413
|
end
|
404
414
|
end
|
405
415
|
|
416
|
+
def self.method_return_bottom?(method)
|
417
|
+
method.type.return_type.is_a? RBS::Types::Bases::Bottom
|
418
|
+
end
|
419
|
+
|
406
420
|
def self.match_free_variables(vars, types, values)
|
407
421
|
accumulator = {}
|
408
422
|
types.zip values do |t, v|
|
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.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- tompng
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: irb
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.3.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: prism
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.14.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.14.0
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rbs
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,9 +82,8 @@ files:
|
|
68
82
|
- katakata_irb.gemspec
|
69
83
|
- lib/katakata_irb.rb
|
70
84
|
- lib/katakata_irb/completor.rb
|
71
|
-
- lib/katakata_irb/nesting_parser.rb
|
72
85
|
- lib/katakata_irb/scope.rb
|
73
|
-
- lib/katakata_irb/
|
86
|
+
- lib/katakata_irb/type_analyzer.rb
|
74
87
|
- lib/katakata_irb/types.rb
|
75
88
|
- lib/katakata_irb/version.rb
|
76
89
|
- sig/katakata_irb.rbs
|
@@ -1,257 +0,0 @@
|
|
1
|
-
module KatakataIrb::NestingParser
|
2
|
-
ERROR_TOKENS = %i[
|
3
|
-
on_parse_error
|
4
|
-
compile_error
|
5
|
-
on_assign_error
|
6
|
-
on_alias_error
|
7
|
-
on_class_name_error
|
8
|
-
on_param_error
|
9
|
-
]
|
10
|
-
|
11
|
-
def self.tokenize(code)
|
12
|
-
verbose, $VERBOSE = $VERBOSE, nil
|
13
|
-
tokens = Ripper::Lexer.new(code).scan.reject { ERROR_TOKENS.include? _1.event }
|
14
|
-
KatakataIrb::NestingParser.interpolate_ripper_ignored_tokens code, tokens
|
15
|
-
ensure
|
16
|
-
$VERBOSE = verbose
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.interpolate_ripper_ignored_tokens(code, tokens)
|
20
|
-
line_positions = code.lines.reduce([0]) { _1 << _1.last + _2.bytesize }
|
21
|
-
prev_byte_pos = 0
|
22
|
-
interpolated = []
|
23
|
-
prev_line = 1
|
24
|
-
event = :on_ignored_by_ripper
|
25
|
-
tokens.each do |t|
|
26
|
-
line, col = t.pos
|
27
|
-
byte_pos = line_positions[line - 1] + col
|
28
|
-
if prev_byte_pos < byte_pos
|
29
|
-
tok = code.byteslice(prev_byte_pos...byte_pos)
|
30
|
-
pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
|
31
|
-
interpolated << Ripper::Lexer::Elem.new(pos, event, tok, 0)
|
32
|
-
prev_line += tok.count("\n")
|
33
|
-
end
|
34
|
-
interpolated << t
|
35
|
-
prev_byte_pos = byte_pos + t.tok.bytesize
|
36
|
-
prev_line += t.tok.count("\n")
|
37
|
-
end
|
38
|
-
if prev_byte_pos < code.bytesize
|
39
|
-
tok = code.byteslice(prev_byte_pos..)
|
40
|
-
pos = [prev_line, prev_byte_pos - line_positions[prev_line - 1]]
|
41
|
-
interpolated << Ripper::Lexer::Elem.new(pos, event, tok, 0)
|
42
|
-
end
|
43
|
-
interpolated
|
44
|
-
end
|
45
|
-
|
46
|
-
IGNORE_TOKENS = %i[on_sp on_ignored_nl on_comment on_embdoc_beg on_embdoc on_embdoc_end]
|
47
|
-
|
48
|
-
# Scan each token and call the given block with array of token and other information for parsing
|
49
|
-
def self.scan_opens(tokens)
|
50
|
-
opens = []
|
51
|
-
pending_heredocs = []
|
52
|
-
first_token_on_line = true
|
53
|
-
tokens.each do |t|
|
54
|
-
skip = false
|
55
|
-
last_tok, state, args = opens.last
|
56
|
-
case state
|
57
|
-
when :in_unquoted_symbol
|
58
|
-
unless IGNORE_TOKENS.include?(t.event)
|
59
|
-
opens.pop
|
60
|
-
skip = true
|
61
|
-
end
|
62
|
-
when :in_lambda_head
|
63
|
-
opens.pop if t.event == :on_tlambeg || (t.event == :on_kw && t.tok == 'do')
|
64
|
-
when :in_method_head
|
65
|
-
unless IGNORE_TOKENS.include?(t.event)
|
66
|
-
next_args = []
|
67
|
-
body = nil
|
68
|
-
if args.include?(:receiver)
|
69
|
-
case t.event
|
70
|
-
when :on_lparen, :on_ivar, :on_gvar, :on_cvar
|
71
|
-
# def (receiver). | def @ivar. | def $gvar. | def @@cvar.
|
72
|
-
next_args << :dot
|
73
|
-
when :on_kw
|
74
|
-
case t.tok
|
75
|
-
when 'self', 'true', 'false', 'nil'
|
76
|
-
# def self(arg) | def self.
|
77
|
-
next_args.push(:arg, :dot)
|
78
|
-
else
|
79
|
-
# def if(arg)
|
80
|
-
skip = true
|
81
|
-
next_args << :arg
|
82
|
-
end
|
83
|
-
when :on_op, :on_backtick
|
84
|
-
# def +(arg)
|
85
|
-
skip = true
|
86
|
-
next_args << :arg
|
87
|
-
when :on_ident, :on_const
|
88
|
-
# def a(arg) | def a.
|
89
|
-
next_args.push(:arg, :dot)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
if args.include?(:dot)
|
93
|
-
# def receiver.name
|
94
|
-
next_args << :name if t.event == :on_period || (t.event == :on_op && t.tok == '::')
|
95
|
-
end
|
96
|
-
if args.include?(:name)
|
97
|
-
if %i[on_ident on_const on_op on_kw on_backtick].include?(t.event)
|
98
|
-
# def name(arg) | def receiver.name(arg)
|
99
|
-
next_args << :arg
|
100
|
-
skip = true
|
101
|
-
end
|
102
|
-
end
|
103
|
-
if args.include?(:arg)
|
104
|
-
case t.event
|
105
|
-
when :on_nl, :on_semicolon
|
106
|
-
# def recever.f;
|
107
|
-
body = :normal
|
108
|
-
when :on_lparen
|
109
|
-
# def recever.f()
|
110
|
-
next_args << :eq
|
111
|
-
else
|
112
|
-
if t.event == :on_op && t.tok == '='
|
113
|
-
# def receiver.f =
|
114
|
-
body = :oneliner
|
115
|
-
else
|
116
|
-
# def recever.f arg
|
117
|
-
next_args << :arg_without_paren
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
if args.include?(:eq)
|
122
|
-
if t.event == :on_op && t.tok == '='
|
123
|
-
body = :oneliner
|
124
|
-
else
|
125
|
-
body = :normal
|
126
|
-
end
|
127
|
-
end
|
128
|
-
if args.include?(:arg_without_paren)
|
129
|
-
if %i[on_semicolon on_nl].include?(t.event)
|
130
|
-
# def f a;
|
131
|
-
body = :normal
|
132
|
-
else
|
133
|
-
# def f a, b
|
134
|
-
next_args << :arg_without_paren
|
135
|
-
end
|
136
|
-
end
|
137
|
-
if body == :oneliner
|
138
|
-
opens.pop
|
139
|
-
elsif body
|
140
|
-
opens[-1] = [last_tok, nil]
|
141
|
-
else
|
142
|
-
opens[-1] = [last_tok, :in_method_head, next_args]
|
143
|
-
end
|
144
|
-
end
|
145
|
-
when :in_for_while_until_condition
|
146
|
-
if t.event == :on_semicolon || t.event == :on_nl || (t.event == :on_kw && t.tok == 'do')
|
147
|
-
skip = true if t.event == :on_kw && t.tok == 'do'
|
148
|
-
opens[-1] = [last_tok, nil]
|
149
|
-
end
|
150
|
-
when :in_block_head
|
151
|
-
if t.event == :on_op && t.tok == '|'
|
152
|
-
opens[-1] = [last_tok, nil]
|
153
|
-
opens << [t, :in_block_args]
|
154
|
-
elsif !IGNORE_TOKENS.include?(t.event)
|
155
|
-
opens[-1] = [last_tok, nil]
|
156
|
-
end
|
157
|
-
when :in_block_args
|
158
|
-
if t.event == :on_op && t.tok == '|' && t.state.allbits?(Ripper::EXPR_BEG)
|
159
|
-
opens.pop
|
160
|
-
skip = true
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
unless skip
|
165
|
-
case t.event
|
166
|
-
when :on_kw
|
167
|
-
case t.tok
|
168
|
-
when 'do'
|
169
|
-
opens << [t, :in_block_head]
|
170
|
-
when 'begin', 'class', 'module', 'case'
|
171
|
-
opens << [t, nil]
|
172
|
-
when 'end'
|
173
|
-
opens.pop
|
174
|
-
when 'def'
|
175
|
-
opens << [t, :in_method_head, [:receiver, :name]]
|
176
|
-
when 'if', 'unless'
|
177
|
-
unless t.state.allbits?(Ripper::EXPR_LABEL)
|
178
|
-
opens << [t, nil]
|
179
|
-
end
|
180
|
-
when 'while', 'until'
|
181
|
-
unless t.state.allbits?(Ripper::EXPR_LABEL)
|
182
|
-
opens << [t, :in_for_while_until_condition]
|
183
|
-
end
|
184
|
-
when 'ensure', 'rescue'
|
185
|
-
unless t.state.allbits?(Ripper::EXPR_LABEL)
|
186
|
-
opens.pop
|
187
|
-
opens << [t, nil]
|
188
|
-
end
|
189
|
-
when 'elsif', 'else', 'when'
|
190
|
-
opens.pop
|
191
|
-
opens << [t, nil]
|
192
|
-
when 'for'
|
193
|
-
opens << [t, :in_for_while_until_condition]
|
194
|
-
when 'in'
|
195
|
-
if last_tok&.event == :on_kw && %w[case in].include?(last_tok.tok) && first_token_on_line
|
196
|
-
opens.pop
|
197
|
-
opens << [t, nil]
|
198
|
-
end
|
199
|
-
end
|
200
|
-
when :on_lbrace
|
201
|
-
if t.state.allbits?(Ripper::EXPR_LABEL)
|
202
|
-
opens << [t, nil]
|
203
|
-
else
|
204
|
-
opens << [t, :in_block_head]
|
205
|
-
end
|
206
|
-
when :on_tlambda
|
207
|
-
opens << [t, :in_lambda_head]
|
208
|
-
when :on_lparen, :on_lbracket, :on_tlambeg, :on_embexpr_beg, :on_embdoc_beg
|
209
|
-
opens << [t, nil]
|
210
|
-
when :on_rparen, :on_rbracket, :on_rbrace, :on_embexpr_end, :on_embdoc_end
|
211
|
-
opens.pop
|
212
|
-
when :on_heredoc_beg
|
213
|
-
pending_heredocs << t
|
214
|
-
when :on_heredoc_end
|
215
|
-
opens.pop
|
216
|
-
when :on_backtick
|
217
|
-
opens << [t, nil] if t.state.allbits?(Ripper::EXPR_BEG)
|
218
|
-
when :on_tstring_beg, :on_words_beg, :on_qwords_beg, :on_symbols_beg, :on_qsymbols_beg, :on_regexp_beg
|
219
|
-
opens << [t, nil]
|
220
|
-
when :on_tstring_end, :on_regexp_end, :on_label_end
|
221
|
-
opens.pop
|
222
|
-
when :on_symbeg
|
223
|
-
if t.tok == ':'
|
224
|
-
opens << [t, :in_unquoted_symbol]
|
225
|
-
else
|
226
|
-
opens << [t, nil]
|
227
|
-
end
|
228
|
-
when :on_op
|
229
|
-
case t.tok
|
230
|
-
when '?'
|
231
|
-
# opening of `cond ? value : value``
|
232
|
-
opens << [t, nil]
|
233
|
-
when ':'
|
234
|
-
# closing of `cond ? value : value``
|
235
|
-
opens.pop
|
236
|
-
end
|
237
|
-
end
|
238
|
-
end
|
239
|
-
if t.event == :on_nl || t.event == :on_semicolon
|
240
|
-
first_token_on_line = true
|
241
|
-
elsif t.event != :on_sp
|
242
|
-
first_token_on_line = false
|
243
|
-
end
|
244
|
-
if pending_heredocs.any? && t.tok.include?("\n")
|
245
|
-
pending_heredocs.reverse_each { |t| opens << [t, nil] }
|
246
|
-
pending_heredocs = []
|
247
|
-
end
|
248
|
-
yield t, opens if block_given?
|
249
|
-
end
|
250
|
-
opens.map(&:first) + pending_heredocs.reverse
|
251
|
-
end
|
252
|
-
|
253
|
-
def self.open_tokens(tokens)
|
254
|
-
# scan_opens without block will return a list of open tokens at last token position
|
255
|
-
scan_opens(tokens)
|
256
|
-
end
|
257
|
-
end
|