rbi 0.0.16 → 0.1.0
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 -1
- data/lib/rbi/formatter.rb +15 -9
- data/lib/rbi/index.rb +19 -5
- data/lib/rbi/loc.rb +18 -3
- data/lib/rbi/model.rb +52 -42
- data/lib/rbi/parser.rb +632 -539
- data/lib/rbi/printer.rb +5 -3
- data/lib/rbi/rewriters/add_sig_templates.rb +2 -2
- data/lib/rbi/rewriters/annotate.rb +2 -1
- data/lib/rbi/rewriters/deannotate.rb +1 -0
- data/lib/rbi/rewriters/merge_trees.rb +23 -12
- data/lib/rbi/rewriters/nest_non_public_methods.rb +1 -0
- data/lib/rbi/rewriters/nest_singleton_methods.rb +1 -0
- data/lib/rbi/rewriters/remove_known_definitions.rb +16 -12
- data/lib/rbi/rewriters/sort_nodes.rb +21 -9
- data/lib/rbi/version.rb +1 -1
- data/lib/rbi.rb +0 -5
- metadata +7 -35
data/lib/rbi/parser.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "
|
4
|
+
require "yarp"
|
5
5
|
|
6
6
|
module RBI
|
7
7
|
class ParseError < StandardError
|
@@ -53,33 +53,30 @@ module RBI
|
|
53
53
|
class Parser
|
54
54
|
extend T::Sig
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
::Parser::Builders::Default.emit_procarg0 = true
|
59
|
-
::Parser::Builders::Default.emit_encoding = true
|
60
|
-
::Parser::Builders::Default.emit_index = true
|
61
|
-
::Parser::Builders::Default.emit_arg_inside_procarg0 = true
|
62
|
-
|
63
|
-
sig { void }
|
64
|
-
def initialize
|
65
|
-
# Delay load unparser and only if it has not been loaded already.
|
66
|
-
require "unparser" unless defined?(::Unparser)
|
67
|
-
end
|
56
|
+
class << self
|
57
|
+
extend T::Sig
|
68
58
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
59
|
+
sig { params(string: String).returns(Tree) }
|
60
|
+
def parse_string(string)
|
61
|
+
Parser.new.parse_string(string)
|
62
|
+
end
|
73
63
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
64
|
+
sig { params(path: String).returns(Tree) }
|
65
|
+
def parse_file(path)
|
66
|
+
Parser.new.parse_file(path)
|
67
|
+
end
|
68
|
+
|
69
|
+
sig { params(paths: T::Array[String]).returns(T::Array[Tree]) }
|
70
|
+
def parse_files(paths)
|
71
|
+
parser = Parser.new
|
72
|
+
paths.map { |path| parser.parse_file(path) }
|
73
|
+
end
|
78
74
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
75
|
+
sig { params(strings: T::Array[String]).returns(T::Array[Tree]) }
|
76
|
+
def parse_strings(strings)
|
77
|
+
parser = Parser.new
|
78
|
+
strings.map { |string| parser.parse_string(string) }
|
79
|
+
end
|
83
80
|
end
|
84
81
|
|
85
82
|
sig { params(string: String).returns(Tree) }
|
@@ -87,12 +84,6 @@ module RBI
|
|
87
84
|
parse(string, file: "-")
|
88
85
|
end
|
89
86
|
|
90
|
-
sig { params(strings: T::Array[String]).returns(T::Array[Tree]) }
|
91
|
-
def self.parse_strings(strings)
|
92
|
-
parser = Parser.new
|
93
|
-
strings.map { |string| parser.parse_string(string) }
|
94
|
-
end
|
95
|
-
|
96
87
|
sig { params(path: String).returns(Tree) }
|
97
88
|
def parse_file(path)
|
98
89
|
parse(::File.read(path), file: path)
|
@@ -100,22 +91,24 @@ module RBI
|
|
100
91
|
|
101
92
|
private
|
102
93
|
|
103
|
-
sig { params(
|
104
|
-
def parse(
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
94
|
+
sig { params(source: String, file: String).returns(Tree) }
|
95
|
+
def parse(source, file:)
|
96
|
+
result = YARP.parse(source)
|
97
|
+
unless result.success?
|
98
|
+
raise ParseError.new(result.errors.map(&:message).join(" "), Loc.from_yarp(file, result.errors.first.location))
|
99
|
+
end
|
100
|
+
|
101
|
+
visitor = TreeBuilder.new(source, comments: result.comments, file: file)
|
102
|
+
visitor.visit(result.value)
|
103
|
+
visitor.tree
|
104
|
+
rescue YARP::ParseError => e
|
105
|
+
raise ParseError.new(e.message, Loc.from_yarp(file, e.location))
|
113
106
|
rescue ParseError => e
|
114
107
|
raise e
|
115
108
|
rescue => e
|
116
|
-
last_node =
|
109
|
+
last_node = visitor&.last_node
|
117
110
|
last_location = if last_node
|
118
|
-
Loc.
|
111
|
+
Loc.from_yarp(file, last_node.location)
|
119
112
|
else
|
120
113
|
Loc.new(file: file)
|
121
114
|
end
|
@@ -124,594 +117,694 @@ module RBI
|
|
124
117
|
exception.print_debug
|
125
118
|
raise exception
|
126
119
|
end
|
127
|
-
end
|
128
120
|
|
129
|
-
|
130
|
-
|
131
|
-
extend T::Sig
|
121
|
+
class Visitor < YARP::Visitor
|
122
|
+
extend T::Sig
|
132
123
|
|
133
|
-
|
124
|
+
sig { params(source: String, file: String).void }
|
125
|
+
def initialize(source, file:)
|
126
|
+
super()
|
134
127
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
128
|
+
@source = source
|
129
|
+
@file = file
|
130
|
+
end
|
139
131
|
|
140
|
-
|
141
|
-
def visit(node); end
|
132
|
+
private
|
142
133
|
|
143
|
-
|
134
|
+
sig { params(node: YARP::Node).returns(Loc) }
|
135
|
+
def node_loc(node)
|
136
|
+
Loc.from_yarp(@file, node.location)
|
137
|
+
end
|
144
138
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
end
|
139
|
+
sig { params(node: T.nilable(YARP::Node)).returns(T.nilable(String)) }
|
140
|
+
def node_string(node)
|
141
|
+
return unless node
|
149
142
|
|
150
|
-
|
151
|
-
|
152
|
-
|
143
|
+
node.slice
|
144
|
+
end
|
145
|
+
|
146
|
+
sig { params(node: YARP::Node).returns(String) }
|
147
|
+
def node_string!(node)
|
148
|
+
T.must(node_string(node))
|
149
|
+
end
|
153
150
|
end
|
154
|
-
end
|
155
151
|
|
156
|
-
|
157
|
-
|
152
|
+
class TreeBuilder < Visitor
|
153
|
+
extend T::Sig
|
158
154
|
|
159
|
-
|
160
|
-
|
155
|
+
sig { returns(Tree) }
|
156
|
+
attr_reader :tree
|
161
157
|
|
162
|
-
|
163
|
-
|
158
|
+
sig { returns(T.nilable(YARP::Node)) }
|
159
|
+
attr_reader :last_node
|
164
160
|
|
165
|
-
|
166
|
-
|
167
|
-
file:
|
168
|
-
comments: T::Array[::Parser::Source::Comment],
|
169
|
-
nodes_comments_assoc: T::Hash[::Parser::Source::Map, T::Array[::Parser::Source::Comment]]
|
170
|
-
).void
|
171
|
-
end
|
172
|
-
def initialize(file:, comments: [], nodes_comments_assoc: {})
|
173
|
-
super()
|
174
|
-
@file = file
|
175
|
-
@comments = comments
|
176
|
-
@nodes_comments_assoc = nodes_comments_assoc
|
177
|
-
@tree = T.let(Tree.new, Tree)
|
178
|
-
@scopes_stack = T.let([@tree], T::Array[Tree])
|
179
|
-
@last_node = T.let(nil, T.nilable(::AST::Node))
|
180
|
-
@last_sigs = T.let([], T::Array[RBI::Sig])
|
181
|
-
@last_sigs_comments = T.let([], T::Array[Comment])
|
182
|
-
|
183
|
-
separate_header_comments
|
184
|
-
end
|
161
|
+
sig { params(source: String, comments: T::Array[YARP::Comment], file: String).void }
|
162
|
+
def initialize(source, comments:, file:)
|
163
|
+
super(source, file: file)
|
185
164
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
165
|
+
@comments_by_line = T.let(comments.to_h { |c| [c.location.start_line, c] }, T::Hash[Integer, YARP::Comment])
|
166
|
+
@tree = T.let(Tree.new, Tree)
|
167
|
+
|
168
|
+
@scopes_stack = T.let([@tree], T::Array[Tree])
|
169
|
+
@last_node = T.let(nil, T.nilable(YARP::Node))
|
170
|
+
@last_sigs = T.let([], T::Array[RBI::Sig])
|
171
|
+
@last_sigs_comments = T.let([], T::Array[Comment])
|
172
|
+
end
|
191
173
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
174
|
+
sig { override.params(node: T.nilable(YARP::Node)).void }
|
175
|
+
def visit(node)
|
176
|
+
return unless node
|
177
|
+
|
178
|
+
@last_node = node
|
179
|
+
super
|
180
|
+
end
|
181
|
+
|
182
|
+
sig { override.params(node: YARP::ClassNode).void }
|
183
|
+
def visit_class_node(node)
|
184
|
+
scope = Class.new(
|
185
|
+
node_string!(node.constant_path),
|
186
|
+
superclass_name: node_string(node.superclass),
|
187
|
+
loc: node_loc(node),
|
188
|
+
comments: node_comments(node),
|
189
|
+
)
|
196
190
|
|
197
|
-
case node.type
|
198
|
-
when :module, :class, :sclass
|
199
|
-
scope = parse_scope(node)
|
200
191
|
current_scope << scope
|
201
192
|
@scopes_stack << scope
|
202
|
-
|
193
|
+
visit(node.body)
|
194
|
+
collect_dangling_comments(node)
|
203
195
|
@scopes_stack.pop
|
204
|
-
when :casgn
|
205
|
-
current_scope << parse_const_assign(node)
|
206
|
-
when :def, :defs
|
207
|
-
current_scope << parse_def(node)
|
208
|
-
when :send
|
209
|
-
node = parse_send(node)
|
210
|
-
current_scope << node if node
|
211
|
-
when :block
|
212
|
-
rbi_node = parse_block(node)
|
213
|
-
if rbi_node.is_a?(Sig)
|
214
|
-
@last_sigs << rbi_node
|
215
|
-
@last_sigs_comments.concat(node_comments(node))
|
216
|
-
elsif rbi_node
|
217
|
-
current_scope << rbi_node
|
218
|
-
end
|
219
|
-
else
|
220
|
-
visit_all(node.children)
|
221
196
|
end
|
222
197
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
private
|
227
|
-
|
228
|
-
sig { params(node: AST::Node).returns(Scope) }
|
229
|
-
def parse_scope(node)
|
230
|
-
loc = node_loc(node)
|
231
|
-
comments = node_comments(node)
|
232
|
-
|
233
|
-
case node.type
|
234
|
-
when :module
|
235
|
-
name = parse_name(node.children[0])
|
236
|
-
Module.new(name, loc: loc, comments: comments)
|
237
|
-
when :class
|
238
|
-
name = parse_name(node.children[0])
|
239
|
-
superclass_name = ConstBuilder.visit(node.children[1])
|
240
|
-
Class.new(name, superclass_name: superclass_name, loc: loc, comments: comments)
|
241
|
-
when :sclass
|
242
|
-
SingletonClass.new(loc: loc, comments: comments)
|
243
|
-
else
|
244
|
-
raise ParseError.new("Unsupported scope node type `#{node.type}`", loc)
|
198
|
+
sig { override.params(node: YARP::ConstantWriteNode).void }
|
199
|
+
def visit_constant_write_node(node)
|
200
|
+
visit_constant_assign(node)
|
245
201
|
end
|
246
|
-
end
|
247
202
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
if struct_definition?(node_value)
|
252
|
-
parse_struct(node)
|
253
|
-
else
|
254
|
-
name = parse_name(node)
|
255
|
-
value = parse_expr(node_value)
|
256
|
-
loc = node_loc(node)
|
257
|
-
comments = node_comments(node)
|
258
|
-
Const.new(name, value, loc: loc, comments: comments)
|
203
|
+
sig { override.params(node: YARP::ConstantPathWriteNode).void }
|
204
|
+
def visit_constant_path_write_node(node)
|
205
|
+
visit_constant_assign(node)
|
259
206
|
end
|
260
|
-
end
|
261
207
|
|
262
|
-
|
263
|
-
|
264
|
-
|
208
|
+
sig { params(node: T.any(YARP::ConstantWriteNode, YARP::ConstantPathWriteNode)).void }
|
209
|
+
def visit_constant_assign(node)
|
210
|
+
struct = parse_struct(node)
|
211
|
+
|
212
|
+
current_scope << if struct
|
213
|
+
struct
|
214
|
+
elsif type_variable_definition?(node.value)
|
215
|
+
TypeMember.new(
|
216
|
+
case node
|
217
|
+
when YARP::ConstantWriteNode
|
218
|
+
node.name
|
219
|
+
when YARP::ConstantPathWriteNode
|
220
|
+
node_string!(node.target)
|
221
|
+
end,
|
222
|
+
node_string!(node.value),
|
223
|
+
loc: node_loc(node),
|
224
|
+
comments: node_comments(node),
|
225
|
+
)
|
226
|
+
else
|
227
|
+
Const.new(
|
228
|
+
case node
|
229
|
+
when YARP::ConstantWriteNode
|
230
|
+
node.name
|
231
|
+
when YARP::ConstantPathWriteNode
|
232
|
+
node_string!(node.target)
|
233
|
+
end,
|
234
|
+
node_string!(node.value),
|
235
|
+
loc: node_loc(node),
|
236
|
+
comments: node_comments(node),
|
237
|
+
)
|
238
|
+
end
|
239
|
+
end
|
265
240
|
|
266
|
-
|
267
|
-
|
268
|
-
Method.new(
|
269
|
-
node.
|
270
|
-
params: node.
|
241
|
+
sig { override.params(node: YARP::DefNode).void }
|
242
|
+
def visit_def_node(node)
|
243
|
+
current_scope << Method.new(
|
244
|
+
node.name,
|
245
|
+
params: parse_params(node.parameters),
|
271
246
|
sigs: current_sigs,
|
272
|
-
loc:
|
273
|
-
comments: current_sigs_comments + node_comments(node)
|
247
|
+
loc: node_loc(node),
|
248
|
+
comments: current_sigs_comments + node_comments(node),
|
249
|
+
is_singleton: !!node.receiver,
|
274
250
|
)
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
loc:
|
282
|
-
comments:
|
251
|
+
end
|
252
|
+
|
253
|
+
sig { override.params(node: YARP::ModuleNode).void }
|
254
|
+
def visit_module_node(node)
|
255
|
+
scope = Module.new(
|
256
|
+
node_string!(node.constant_path),
|
257
|
+
loc: node_loc(node),
|
258
|
+
comments: node_comments(node),
|
283
259
|
)
|
284
|
-
|
285
|
-
|
260
|
+
|
261
|
+
current_scope << scope
|
262
|
+
@scopes_stack << scope
|
263
|
+
visit(node.body)
|
264
|
+
collect_dangling_comments(node)
|
265
|
+
@scopes_stack.pop
|
286
266
|
end
|
287
|
-
end
|
288
267
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
when :arg
|
297
|
-
ReqParam.new(name, loc: loc, comments: comments)
|
298
|
-
when :optarg
|
299
|
-
value = parse_expr(node.children[1])
|
300
|
-
OptParam.new(name, value, loc: loc, comments: comments)
|
301
|
-
when :restarg
|
302
|
-
RestParam.new(name, loc: loc, comments: comments)
|
303
|
-
when :kwarg
|
304
|
-
KwParam.new(name, loc: loc, comments: comments)
|
305
|
-
when :kwoptarg
|
306
|
-
value = parse_expr(node.children[1])
|
307
|
-
KwOptParam.new(name, value, loc: loc, comments: comments)
|
308
|
-
when :kwrestarg
|
309
|
-
KwRestParam.new(name, loc: loc, comments: comments)
|
310
|
-
when :blockarg
|
311
|
-
BlockParam.new(name, loc: loc, comments: comments)
|
312
|
-
else
|
313
|
-
raise ParseError.new("Unsupported param node type `#{node.type}`", loc)
|
268
|
+
sig { override.params(node: YARP::ProgramNode).void }
|
269
|
+
def visit_program_node(node)
|
270
|
+
super
|
271
|
+
|
272
|
+
collect_orphan_comments
|
273
|
+
separate_header_comments
|
274
|
+
set_root_tree_loc
|
314
275
|
end
|
315
|
-
end
|
316
276
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
AttrReader.new(*symbols, sigs: current_sigs, loc: loc, comments: current_sigs_comments + comments)
|
330
|
-
when :attr_writer
|
331
|
-
symbols = node.children[2..-1].map { |child| child.children[0] }
|
332
|
-
AttrWriter.new(*symbols, sigs: current_sigs, loc: loc, comments: current_sigs_comments + comments)
|
333
|
-
when :attr_accessor
|
334
|
-
symbols = node.children[2..-1].map { |child| child.children[0] }
|
335
|
-
AttrAccessor.new(*symbols, sigs: current_sigs, loc: loc, comments: current_sigs_comments + comments)
|
336
|
-
when :include
|
337
|
-
names = node.children[2..-1].map { |child| parse_expr(child) }
|
338
|
-
Include.new(*names, loc: loc, comments: comments)
|
339
|
-
when :extend
|
340
|
-
names = node.children[2..-1].map { |child| parse_expr(child) }
|
341
|
-
Extend.new(*names, loc: loc, comments: comments)
|
342
|
-
when :abstract!, :sealed!, :interface!
|
343
|
-
Helper.new(method_name.to_s.delete_suffix("!"), loc: loc, comments: comments)
|
344
|
-
when :mixes_in_class_methods
|
345
|
-
names = node.children[2..-1].map { |child| parse_name(child) }
|
346
|
-
MixesInClassMethods.new(*names, loc: loc, comments: comments)
|
347
|
-
when :public, :protected, :private
|
348
|
-
visibility = case method_name
|
349
|
-
when :protected
|
350
|
-
Protected.new(loc: loc)
|
351
|
-
when :private
|
352
|
-
Private.new(loc: loc)
|
353
|
-
else
|
354
|
-
Public.new(loc: loc)
|
355
|
-
end
|
356
|
-
nested_node = node.children[2]
|
357
|
-
case nested_node&.type
|
358
|
-
when :def, :defs
|
359
|
-
method = parse_def(nested_node)
|
360
|
-
method.visibility = visibility
|
361
|
-
method
|
362
|
-
when :send
|
363
|
-
snode = parse_send(nested_node)
|
364
|
-
raise ParseError.new("Unexpected token `private` before `#{nested_node.type}`", loc) unless snode.is_a?(Attr)
|
365
|
-
snode.visibility = visibility
|
366
|
-
snode
|
367
|
-
when nil
|
368
|
-
visibility
|
369
|
-
else
|
370
|
-
raise ParseError.new("Unexpected token `private` before `#{nested_node.type}`", loc)
|
371
|
-
end
|
372
|
-
when :prop
|
373
|
-
name, type, default_value = parse_tstruct_prop(node)
|
374
|
-
TStructProp.new(name, type, default: default_value, loc: loc, comments: comments)
|
375
|
-
when :const
|
376
|
-
name, type, default_value = parse_tstruct_prop(node)
|
377
|
-
TStructConst.new(name, type, default: default_value, loc: loc, comments: comments)
|
378
|
-
else
|
379
|
-
args = parse_send_args(node)
|
380
|
-
Send.new(method_name.to_s, args, loc: loc, comments: comments)
|
277
|
+
sig { override.params(node: YARP::SingletonClassNode).void }
|
278
|
+
def visit_singleton_class_node(node)
|
279
|
+
scope = SingletonClass.new(
|
280
|
+
loc: node_loc(node),
|
281
|
+
comments: node_comments(node),
|
282
|
+
)
|
283
|
+
|
284
|
+
current_scope << scope
|
285
|
+
@scopes_stack << scope
|
286
|
+
visit(node.body)
|
287
|
+
collect_dangling_comments(node)
|
288
|
+
@scopes_stack.pop
|
381
289
|
end
|
382
|
-
end
|
383
290
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
291
|
+
sig { params(node: YARP::CallNode).void }
|
292
|
+
def visit_call_node(node)
|
293
|
+
message = node.name
|
294
|
+
case message
|
295
|
+
when "abstract!", "sealed!", "interface!"
|
296
|
+
current_scope << Helper.new(
|
297
|
+
message.delete_suffix("!"),
|
298
|
+
loc: node_loc(node),
|
299
|
+
comments: node_comments(node),
|
300
|
+
)
|
301
|
+
when "attr_reader"
|
302
|
+
args = node.arguments
|
303
|
+
return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
304
|
+
|
305
|
+
current_scope << AttrReader.new(
|
306
|
+
*T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }),
|
307
|
+
sigs: current_sigs,
|
308
|
+
loc: node_loc(node),
|
309
|
+
comments: current_sigs_comments + node_comments(node),
|
310
|
+
)
|
311
|
+
when "attr_writer"
|
312
|
+
args = node.arguments
|
313
|
+
return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
314
|
+
|
315
|
+
current_scope << AttrWriter.new(
|
316
|
+
*T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }),
|
317
|
+
sigs: current_sigs,
|
318
|
+
loc: node_loc(node),
|
319
|
+
comments: current_sigs_comments + node_comments(node),
|
320
|
+
)
|
321
|
+
when "attr_accessor"
|
322
|
+
args = node.arguments
|
323
|
+
return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
324
|
+
|
325
|
+
current_scope << AttrAccessor.new(
|
326
|
+
*T.unsafe(args.arguments.map { |arg| node_string!(arg).delete_prefix(":").to_sym }),
|
327
|
+
sigs: current_sigs,
|
328
|
+
loc: node_loc(node),
|
329
|
+
comments: current_sigs_comments + node_comments(node),
|
330
|
+
)
|
331
|
+
when "enums"
|
332
|
+
block = node.block
|
333
|
+
return unless block.is_a?(YARP::BlockNode)
|
334
|
+
|
335
|
+
body = block.body
|
336
|
+
return unless body.is_a?(YARP::StatementsNode)
|
337
|
+
|
338
|
+
current_scope << TEnumBlock.new(
|
339
|
+
body.body.map { |stmt| T.cast(stmt, YARP::ConstantWriteNode).name },
|
340
|
+
loc: node_loc(node),
|
341
|
+
comments: node_comments(node),
|
342
|
+
)
|
343
|
+
when "extend"
|
344
|
+
args = node.arguments
|
345
|
+
return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
346
|
+
|
347
|
+
current_scope << Extend.new(
|
348
|
+
*T.unsafe(args.arguments.map { |arg| node_string!(arg) }),
|
349
|
+
loc: node_loc(node),
|
350
|
+
comments: node_comments(node),
|
351
|
+
)
|
352
|
+
when "include"
|
353
|
+
args = node.arguments
|
354
|
+
return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
355
|
+
|
356
|
+
current_scope << Include.new(
|
357
|
+
*T.unsafe(args.arguments.map { |arg| node_string!(arg) }),
|
358
|
+
loc: node_loc(node),
|
359
|
+
comments: node_comments(node),
|
360
|
+
)
|
361
|
+
when "mixes_in_class_methods"
|
362
|
+
args = node.arguments
|
363
|
+
return unless args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
364
|
+
|
365
|
+
current_scope << MixesInClassMethods.new(
|
366
|
+
*T.unsafe(args.arguments.map { |arg| node_string!(arg) }),
|
367
|
+
loc: node_loc(node),
|
368
|
+
comments: node_comments(node),
|
369
|
+
)
|
370
|
+
when "private", "protected", "public"
|
371
|
+
args = node.arguments
|
372
|
+
if args.is_a?(YARP::ArgumentsNode) && args.arguments.any?
|
373
|
+
visit(node.arguments)
|
374
|
+
last_node = @scopes_stack.last&.nodes&.last
|
375
|
+
case last_node
|
376
|
+
when Method, Attr
|
377
|
+
last_node.visibility = parse_visibility(node.name, node)
|
378
|
+
else
|
379
|
+
raise ParseError.new(
|
380
|
+
"Unexpected token `#{node.message}` before `#{last_node&.string&.strip}`",
|
381
|
+
node_loc(node),
|
382
|
+
)
|
383
|
+
end
|
384
|
+
else
|
385
|
+
current_scope << parse_visibility(node.name, node)
|
393
386
|
end
|
387
|
+
when "prop", "const"
|
388
|
+
parse_tstruct_field(node)
|
389
|
+
when "requires_ancestor"
|
390
|
+
block = node.block
|
391
|
+
return unless block.is_a?(YARP::BlockNode)
|
392
|
+
|
393
|
+
body = block.body
|
394
|
+
return unless body.is_a?(YARP::StatementsNode)
|
395
|
+
|
396
|
+
current_scope << RequiresAncestor.new(
|
397
|
+
node_string!(body),
|
398
|
+
loc: node_loc(node),
|
399
|
+
comments: node_comments(node),
|
400
|
+
)
|
401
|
+
when "sig"
|
402
|
+
@last_sigs << parse_sig(node)
|
394
403
|
else
|
395
|
-
|
404
|
+
current_scope << Send.new(
|
405
|
+
message,
|
406
|
+
parse_send_args(node.arguments),
|
407
|
+
loc: node_loc(node),
|
408
|
+
comments: node_comments(node),
|
409
|
+
)
|
396
410
|
end
|
397
411
|
end
|
398
|
-
args
|
399
|
-
end
|
400
412
|
|
401
|
-
|
402
|
-
def parse_block(node)
|
403
|
-
name = node.children[0].children[1]
|
404
|
-
|
405
|
-
case name
|
406
|
-
when :sig
|
407
|
-
parse_sig(node)
|
408
|
-
when :enums
|
409
|
-
parse_enum(node)
|
410
|
-
when :requires_ancestor
|
411
|
-
parse_requires_ancestor(node)
|
412
|
-
else
|
413
|
-
raise ParseError.new("Unsupported block node type `#{name}`", node_loc(node))
|
414
|
-
end
|
415
|
-
end
|
413
|
+
private
|
416
414
|
|
417
|
-
|
418
|
-
|
419
|
-
(node
|
420
|
-
|
421
|
-
|
415
|
+
# Collect all the remaining comments within a node
|
416
|
+
sig { params(node: YARP::Node).void }
|
417
|
+
def collect_dangling_comments(node)
|
418
|
+
first_line = node.location.start_line
|
419
|
+
last_line = node.location.end_line
|
422
420
|
|
423
|
-
|
424
|
-
def parse_struct(node)
|
425
|
-
name = parse_name(node)
|
426
|
-
loc = node_loc(node)
|
427
|
-
comments = node_comments(node)
|
421
|
+
last_node_last_line = node.child_nodes.last&.location&.end_line
|
428
422
|
|
429
|
-
|
430
|
-
|
423
|
+
last_line.downto(first_line) do |line|
|
424
|
+
comment = @comments_by_line[line]
|
425
|
+
next unless comment
|
426
|
+
break if last_node_last_line && line <= last_node_last_line
|
431
427
|
|
432
|
-
|
433
|
-
|
434
|
-
body = send.children[2].children
|
435
|
-
else
|
436
|
-
body << send.children[2]
|
428
|
+
current_scope << parse_comment(comment)
|
429
|
+
@comments_by_line.delete(line)
|
437
430
|
end
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
if
|
449
|
-
|
431
|
+
end
|
432
|
+
|
433
|
+
# Collect all the remaining comments after visiting the tree
|
434
|
+
sig { void }
|
435
|
+
def collect_orphan_comments
|
436
|
+
last_line = T.let(nil, T.nilable(Integer))
|
437
|
+
last_node_end = @tree.nodes.last&.loc&.end_line
|
438
|
+
|
439
|
+
@comments_by_line.each do |line, comment|
|
440
|
+
# Associate the comment either with the header or the file or as a dangling comment at the end
|
441
|
+
recv = if last_node_end && line >= last_node_end
|
442
|
+
@tree
|
443
|
+
else
|
444
|
+
@tree.comments
|
450
445
|
end
|
446
|
+
|
447
|
+
# Preserve blank lines in comments
|
448
|
+
if last_line && line > last_line + 1
|
449
|
+
recv << BlankLine.new(loc: Loc.from_yarp(@file, comment.location))
|
450
|
+
end
|
451
|
+
|
452
|
+
recv << parse_comment(comment)
|
453
|
+
last_line = line
|
451
454
|
end
|
452
455
|
end
|
453
456
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
457
|
+
sig { returns(Tree) }
|
458
|
+
def current_scope
|
459
|
+
T.must(@scopes_stack.last) # Should never be nil since we create a Tree as the root
|
460
|
+
end
|
458
461
|
|
459
|
-
|
460
|
-
|
462
|
+
sig { returns(T::Array[Sig]) }
|
463
|
+
def current_sigs
|
464
|
+
sigs = @last_sigs.dup
|
465
|
+
@last_sigs.clear
|
466
|
+
sigs
|
467
|
+
end
|
461
468
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
&.children&.fetch(0, nil)
|
469
|
-
&.children&.fetch(0, nil) == :default
|
470
|
-
default_value = if has_default
|
471
|
-
parse_expr(node.children.fetch(4, nil)
|
472
|
-
&.children&.fetch(0, nil)
|
473
|
-
&.children&.fetch(1, nil))
|
474
|
-
end
|
475
|
-
[name, type, default_value]
|
476
|
-
end
|
469
|
+
sig { returns(T::Array[Comment]) }
|
470
|
+
def current_sigs_comments
|
471
|
+
comments = @last_sigs_comments.dup
|
472
|
+
@last_sigs_comments.clear
|
473
|
+
comments
|
474
|
+
end
|
477
475
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
sig.loc = node_loc(node)
|
482
|
-
sig
|
483
|
-
end
|
476
|
+
sig { params(node: YARP::Node).returns(T::Array[Comment]) }
|
477
|
+
def node_comments(node)
|
478
|
+
comments = []
|
484
479
|
|
485
|
-
|
486
|
-
|
487
|
-
enum = TEnumBlock.new
|
480
|
+
start_line = node.location.start_line
|
481
|
+
start_line -= 1 unless @comments_by_line.key?(start_line)
|
488
482
|
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
[node.children[2]]
|
493
|
-
end
|
483
|
+
start_line.downto(1) do |line|
|
484
|
+
comment = @comments_by_line[line]
|
485
|
+
break unless comment
|
494
486
|
|
495
|
-
|
496
|
-
|
487
|
+
comments.unshift(parse_comment(comment))
|
488
|
+
@comments_by_line.delete(line)
|
489
|
+
end
|
490
|
+
|
491
|
+
comments
|
497
492
|
end
|
498
|
-
enum.loc = node_loc(node)
|
499
|
-
enum
|
500
|
-
end
|
501
493
|
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
ra.loc = node_loc(node)
|
507
|
-
ra
|
508
|
-
end
|
494
|
+
sig { params(node: YARP::Comment).returns(Comment) }
|
495
|
+
def parse_comment(node)
|
496
|
+
Comment.new(node.location.slice.gsub(/^# ?/, "").rstrip, loc: Loc.from_yarp(@file, node.location))
|
497
|
+
end
|
509
498
|
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
499
|
+
sig { params(node: T.nilable(YARP::Node)).returns(T::Array[Arg]) }
|
500
|
+
def parse_send_args(node)
|
501
|
+
args = T.let([], T::Array[Arg])
|
502
|
+
return args unless node.is_a?(YARP::ArgumentsNode)
|
503
|
+
|
504
|
+
node.arguments.each do |arg|
|
505
|
+
case arg
|
506
|
+
when YARP::KeywordHashNode
|
507
|
+
arg.elements.each do |assoc|
|
508
|
+
next unless assoc.is_a?(YARP::AssocNode)
|
509
|
+
|
510
|
+
args << KwArg.new(
|
511
|
+
node_string!(assoc.key).delete_suffix(":"),
|
512
|
+
T.must(node_string(assoc.value)),
|
513
|
+
)
|
514
|
+
end
|
515
|
+
else
|
516
|
+
args << Arg.new(T.must(node_string(arg)))
|
517
|
+
end
|
518
|
+
end
|
514
519
|
|
515
|
-
|
516
|
-
def node_comments(node)
|
517
|
-
comments = @nodes_comments_assoc[node.location]
|
518
|
-
return [] unless comments
|
519
|
-
comments.map do |comment|
|
520
|
-
text = comment.text[1..-1].strip
|
521
|
-
loc = Loc.from_ast_loc(@file, comment.location)
|
522
|
-
Comment.new(text, loc: loc)
|
520
|
+
args
|
523
521
|
end
|
524
|
-
end
|
525
522
|
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
523
|
+
sig { params(node: T.nilable(YARP::Node)).returns(T::Array[Param]) }
|
524
|
+
def parse_params(node)
|
525
|
+
params = []
|
526
|
+
return params unless node.is_a?(YARP::ParametersNode)
|
530
527
|
|
531
|
-
|
532
|
-
|
533
|
-
sigs = @last_sigs.dup
|
534
|
-
@last_sigs.clear
|
535
|
-
sigs
|
536
|
-
end
|
528
|
+
node.requireds.each do |param|
|
529
|
+
next unless param.is_a?(YARP::RequiredParameterNode)
|
537
530
|
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
531
|
+
params << ReqParam.new(
|
532
|
+
param.name.to_s,
|
533
|
+
loc: node_loc(param),
|
534
|
+
comments: node_comments(param),
|
535
|
+
)
|
536
|
+
end
|
537
|
+
|
538
|
+
node.optionals.each do |param|
|
539
|
+
next unless param.is_a?(YARP::OptionalParameterNode)
|
540
|
+
|
541
|
+
params << OptParam.new(
|
542
|
+
param.name.to_s,
|
543
|
+
node_string!(param.value),
|
544
|
+
loc: node_loc(param),
|
545
|
+
comments: node_comments(param),
|
546
|
+
)
|
547
|
+
end
|
548
|
+
|
549
|
+
rest = node.rest
|
550
|
+
if rest.is_a?(YARP::RestParameterNode)
|
551
|
+
params << RestParam.new(
|
552
|
+
rest.name || "*args",
|
553
|
+
loc: node_loc(rest),
|
554
|
+
comments: node_comments(rest),
|
555
|
+
)
|
556
|
+
end
|
557
|
+
|
558
|
+
node.keywords.each do |param|
|
559
|
+
next unless param.is_a?(YARP::KeywordParameterNode)
|
560
|
+
|
561
|
+
value = param.value
|
562
|
+
params << if value
|
563
|
+
KwOptParam.new(
|
564
|
+
param.name.delete_suffix(":"),
|
565
|
+
node_string!(value),
|
566
|
+
loc: node_loc(param),
|
567
|
+
comments: node_comments(param),
|
568
|
+
)
|
569
|
+
else
|
570
|
+
KwParam.new(
|
571
|
+
param.name.delete_suffix(":"),
|
572
|
+
loc: node_loc(param),
|
573
|
+
comments: node_comments(param),
|
574
|
+
)
|
575
|
+
end
|
576
|
+
end
|
544
577
|
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
if last_line && comment_line > last_line + 1
|
554
|
-
# Preserve empty lines in file headers
|
555
|
-
tree.comments << BlankLine.new(loc: loc)
|
578
|
+
rest_kw = node.keyword_rest
|
579
|
+
if rest_kw.is_a?(YARP::KeywordRestParameterNode)
|
580
|
+
params << KwRestParam.new(
|
581
|
+
rest_kw.name || "**kwargs",
|
582
|
+
loc: node_loc(rest_kw),
|
583
|
+
comments: node_comments(rest_kw),
|
584
|
+
)
|
556
585
|
end
|
557
586
|
|
558
|
-
|
559
|
-
|
587
|
+
block = node.block
|
588
|
+
if block.is_a?(YARP::BlockParameterNode)
|
589
|
+
params << BlockParam.new(
|
590
|
+
block.name || "&block",
|
591
|
+
loc: node_loc(block),
|
592
|
+
comments: node_comments(block),
|
593
|
+
)
|
594
|
+
end
|
595
|
+
|
596
|
+
params
|
560
597
|
end
|
561
|
-
end
|
562
598
|
|
563
|
-
|
564
|
-
|
565
|
-
|
599
|
+
sig { params(node: YARP::CallNode).returns(Sig) }
|
600
|
+
def parse_sig(node)
|
601
|
+
@last_sigs_comments = node_comments(node)
|
566
602
|
|
567
|
-
|
568
|
-
|
569
|
-
|
603
|
+
builder = SigBuilder.new(@source, file: @file)
|
604
|
+
builder.current.loc = node_loc(node)
|
605
|
+
builder.visit_call_node(node)
|
606
|
+
builder.current
|
607
|
+
end
|
570
608
|
|
571
|
-
|
572
|
-
|
573
|
-
|
609
|
+
sig { params(node: T.any(YARP::ConstantWriteNode, YARP::ConstantPathWriteNode)).returns(T.nilable(Struct)) }
|
610
|
+
def parse_struct(node)
|
611
|
+
send = node.value
|
612
|
+
return unless send.is_a?(YARP::CallNode)
|
613
|
+
return unless send.message == "new"
|
614
|
+
|
615
|
+
recv = send.receiver
|
616
|
+
return unless recv
|
617
|
+
return unless node_string(recv) =~ /(::)?Struct/
|
618
|
+
|
619
|
+
members = []
|
620
|
+
keyword_init = T.let(false, T::Boolean)
|
621
|
+
|
622
|
+
args = send.arguments
|
623
|
+
if args.is_a?(YARP::ArgumentsNode)
|
624
|
+
args.arguments.each do |arg|
|
625
|
+
case arg
|
626
|
+
when YARP::SymbolNode
|
627
|
+
members << arg.value
|
628
|
+
when YARP::KeywordHashNode
|
629
|
+
arg.elements.each do |assoc|
|
630
|
+
next unless assoc.is_a?(YARP::AssocNode)
|
631
|
+
|
632
|
+
key = node_string!(assoc.key)
|
633
|
+
val = node_string(assoc.value)
|
634
|
+
|
635
|
+
keyword_init = val == "true" if key == "keyword_init:"
|
636
|
+
end
|
637
|
+
else
|
638
|
+
raise ParseError.new("Unexpected node type `#{arg.class}`", node_loc(arg))
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|
574
642
|
|
575
|
-
|
576
|
-
|
643
|
+
name = case node
|
644
|
+
when YARP::ConstantWriteNode
|
645
|
+
node.name
|
646
|
+
when YARP::ConstantPathWriteNode
|
647
|
+
node_string!(node.target)
|
648
|
+
end
|
577
649
|
|
578
|
-
|
579
|
-
|
650
|
+
loc = node_loc(node)
|
651
|
+
comments = node_comments(node)
|
652
|
+
struct = Struct.new(name, members: members, keyword_init: keyword_init, loc: loc, comments: comments)
|
653
|
+
@scopes_stack << struct
|
654
|
+
visit(send.block)
|
655
|
+
@scopes_stack.pop
|
656
|
+
struct
|
580
657
|
end
|
581
658
|
|
582
|
-
|
583
|
-
|
659
|
+
sig { params(send: YARP::CallNode).void }
|
660
|
+
def parse_tstruct_field(send)
|
661
|
+
args = send.arguments
|
662
|
+
return unless args.is_a?(YARP::ArgumentsNode)
|
584
663
|
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
last_loc = tree.nodes.last&.loc
|
589
|
-
|
590
|
-
@tree.loc = Loc.new(
|
591
|
-
file: @file,
|
592
|
-
begin_line: first_loc&.begin_line || 0,
|
593
|
-
begin_column: first_loc&.begin_column || 0,
|
594
|
-
end_line: last_loc&.end_line || 0,
|
595
|
-
end_column: last_loc&.end_column || 0
|
596
|
-
)
|
597
|
-
end
|
598
|
-
end
|
664
|
+
name_arg, type_arg, *rest = args.arguments
|
665
|
+
return unless name_arg
|
666
|
+
return unless type_arg
|
599
667
|
|
600
|
-
|
601
|
-
|
668
|
+
name = node_string!(name_arg).delete_prefix(":")
|
669
|
+
type = node_string!(type_arg)
|
670
|
+
loc = node_loc(send)
|
671
|
+
comments = node_comments(send)
|
672
|
+
default_value = T.let(nil, T.nilable(String))
|
602
673
|
|
603
|
-
|
604
|
-
|
605
|
-
v = ConstBuilder.new
|
606
|
-
v.visit(node)
|
607
|
-
return nil if v.names.empty?
|
608
|
-
v.names.join("::")
|
609
|
-
end
|
674
|
+
rest&.each do |arg|
|
675
|
+
next unless arg.is_a?(YARP::KeywordHashNode)
|
610
676
|
|
611
|
-
|
612
|
-
|
677
|
+
arg.elements.each do |assoc|
|
678
|
+
next unless assoc.is_a?(YARP::AssocNode)
|
613
679
|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
680
|
+
if node_string(assoc.key) == "default:"
|
681
|
+
default_value = node_string(assoc.value)
|
682
|
+
end
|
683
|
+
end
|
684
|
+
end
|
619
685
|
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
@names << ""
|
629
|
-
when :sym
|
630
|
-
@names << ":#{node.children[0]}"
|
686
|
+
current_scope << case send.message
|
687
|
+
when "const"
|
688
|
+
TStructConst.new(name, type, default: default_value, loc: loc, comments: comments)
|
689
|
+
when "prop"
|
690
|
+
TStructProp.new(name, type, default: default_value, loc: loc, comments: comments)
|
691
|
+
else
|
692
|
+
raise ParseError.new("Unexpected message `#{send.message}`", loc)
|
693
|
+
end
|
631
694
|
end
|
632
|
-
end
|
633
|
-
end
|
634
695
|
|
635
|
-
|
636
|
-
|
696
|
+
sig { params(name: String, node: YARP::Node).returns(Visibility) }
|
697
|
+
def parse_visibility(name, node)
|
698
|
+
case name
|
699
|
+
when "public"
|
700
|
+
Public.new(loc: node_loc(node))
|
701
|
+
when "protected"
|
702
|
+
Protected.new(loc: node_loc(node))
|
703
|
+
when "private"
|
704
|
+
Private.new(loc: node_loc(node))
|
705
|
+
else
|
706
|
+
raise ParseError.new("Unexpected visibility `#{name}`", node_loc(node))
|
707
|
+
end
|
708
|
+
end
|
637
709
|
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
v.current
|
643
|
-
end
|
710
|
+
sig { void }
|
711
|
+
def separate_header_comments
|
712
|
+
current_scope.nodes.dup.each do |child_node|
|
713
|
+
break unless child_node.is_a?(Comment) || child_node.is_a?(BlankLine)
|
644
714
|
|
645
|
-
|
646
|
-
|
715
|
+
current_scope.comments << child_node
|
716
|
+
child_node.detach
|
717
|
+
end
|
718
|
+
end
|
647
719
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
720
|
+
sig { void }
|
721
|
+
def set_root_tree_loc
|
722
|
+
first_loc = tree.nodes.first&.loc
|
723
|
+
last_loc = tree.nodes.last&.loc
|
724
|
+
|
725
|
+
@tree.loc = Loc.new(
|
726
|
+
file: @file,
|
727
|
+
begin_line: first_loc&.begin_line || 0,
|
728
|
+
begin_column: first_loc&.begin_column || 0,
|
729
|
+
end_line: last_loc&.end_line || 0,
|
730
|
+
end_column: last_loc&.end_column || 0,
|
731
|
+
)
|
732
|
+
end
|
733
|
+
|
734
|
+
sig { params(node: T.nilable(YARP::Node)).returns(T::Boolean) }
|
735
|
+
def type_variable_definition?(node)
|
736
|
+
return false unless node.is_a?(YARP::CallNode)
|
737
|
+
return false unless node.block
|
653
738
|
|
654
|
-
|
655
|
-
def visit(node)
|
656
|
-
return unless node
|
657
|
-
case node.type
|
658
|
-
when :send
|
659
|
-
visit_send(node)
|
739
|
+
node.message == "type_member" || node.message == "type_template"
|
660
740
|
end
|
661
741
|
end
|
662
742
|
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
when :params
|
686
|
-
if node.children.length >= 3
|
687
|
-
node.children[2].children.each do |child|
|
688
|
-
name = child.children[0].children[0].to_s
|
689
|
-
type = parse_expr(child.children[1])
|
690
|
-
@current << SigParam.new(name, type)
|
743
|
+
class SigBuilder < Visitor
|
744
|
+
extend T::Sig
|
745
|
+
|
746
|
+
sig { returns(Sig) }
|
747
|
+
attr_accessor :current
|
748
|
+
|
749
|
+
sig { params(content: String, file: String).void }
|
750
|
+
def initialize(content, file:)
|
751
|
+
super
|
752
|
+
|
753
|
+
@current = T.let(Sig.new, Sig)
|
754
|
+
end
|
755
|
+
|
756
|
+
sig { override.params(node: YARP::CallNode).void }
|
757
|
+
def visit_call_node(node)
|
758
|
+
case node.message
|
759
|
+
when "sig"
|
760
|
+
args = node.arguments
|
761
|
+
if args.is_a?(YARP::ArgumentsNode)
|
762
|
+
args.arguments.each do |arg|
|
763
|
+
@current.is_final = node_string(arg) == ":final"
|
764
|
+
end
|
691
765
|
end
|
766
|
+
when "abstract"
|
767
|
+
@current.is_abstract = true
|
768
|
+
when "checked"
|
769
|
+
args = node.arguments
|
770
|
+
if args.is_a?(YARP::ArgumentsNode)
|
771
|
+
arg = node_string(args.arguments.first)
|
772
|
+
@current.checked = arg&.delete_prefix(":")&.to_sym
|
773
|
+
end
|
774
|
+
when "override"
|
775
|
+
@current.is_override = true
|
776
|
+
when "overridable"
|
777
|
+
@current.is_overridable = true
|
778
|
+
when "params"
|
779
|
+
visit(node.arguments)
|
780
|
+
when "returns"
|
781
|
+
args = node.arguments
|
782
|
+
if args.is_a?(YARP::ArgumentsNode)
|
783
|
+
first = args.arguments.first
|
784
|
+
@current.return_type = node_string!(first) if first
|
785
|
+
end
|
786
|
+
when "type_parameters"
|
787
|
+
args = node.arguments
|
788
|
+
if args.is_a?(YARP::ArgumentsNode)
|
789
|
+
args.arguments.each do |arg|
|
790
|
+
@current.type_params << node_string!(arg).delete_prefix(":")
|
791
|
+
end
|
792
|
+
end
|
793
|
+
when "void"
|
794
|
+
@current.return_type = nil
|
692
795
|
end
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
end
|
697
|
-
when :void
|
698
|
-
@current.return_type = nil
|
699
|
-
else
|
700
|
-
raise "#{node.location.line}: Unhandled #{name}"
|
796
|
+
|
797
|
+
visit(node.receiver)
|
798
|
+
visit(node.block)
|
701
799
|
end
|
702
|
-
end
|
703
|
-
end
|
704
800
|
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
end_line: ast_loc.last_line,
|
713
|
-
end_column: ast_loc.last_column
|
714
|
-
)
|
801
|
+
sig { override.params(node: YARP::AssocNode).void }
|
802
|
+
def visit_assoc_node(node)
|
803
|
+
@current.params << SigParam.new(
|
804
|
+
node_string!(node.key).delete_suffix(":"),
|
805
|
+
node_string!(T.must(node.value)),
|
806
|
+
)
|
807
|
+
end
|
715
808
|
end
|
716
809
|
end
|
717
810
|
end
|