rbi 0.0.1 → 0.0.2
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 +8 -5
- data/README.md +38 -10
- data/Rakefile +2 -0
- data/lib/rbi.rb +16 -5
- data/lib/rbi/index.rb +186 -0
- data/lib/rbi/loc.rb +36 -0
- data/lib/rbi/model.rb +879 -0
- data/lib/rbi/parser.rb +449 -0
- data/lib/rbi/printer.rb +643 -0
- data/lib/rbi/rewriters/group_nodes.rb +104 -0
- data/lib/rbi/rewriters/merge_trees.rb +587 -0
- data/lib/rbi/rewriters/nest_non_public_methods.rb +63 -0
- data/lib/rbi/rewriters/nest_singleton_methods.rb +40 -0
- data/lib/rbi/rewriters/sort_nodes.rb +84 -0
- data/lib/rbi/version.rb +5 -1
- data/lib/rbi/visitor.rb +19 -0
- metadata +36 -56
- data/exe/rbi +0 -7
- data/lib/rbi/cli.rb +0 -19
data/lib/rbi/parser.rb
ADDED
@@ -0,0 +1,449 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "unparser"
|
5
|
+
|
6
|
+
module RBI
|
7
|
+
class Parser
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
# opt-in to most recent AST format
|
13
|
+
::Parser::Builders::Default.emit_lambda = true
|
14
|
+
::Parser::Builders::Default.emit_procarg0 = true
|
15
|
+
::Parser::Builders::Default.emit_encoding = true
|
16
|
+
::Parser::Builders::Default.emit_index = true
|
17
|
+
::Parser::Builders::Default.emit_arg_inside_procarg0 = true
|
18
|
+
|
19
|
+
sig { params(string: String).returns(Tree) }
|
20
|
+
def self.parse_string(string)
|
21
|
+
Parser.new.parse_string(string)
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { params(path: String).returns(Tree) }
|
25
|
+
def self.parse_file(path)
|
26
|
+
Parser.new.parse_file(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { params(string: String).returns(Tree) }
|
30
|
+
def parse_string(string)
|
31
|
+
parse(string, file: "-")
|
32
|
+
rescue ::Parser::SyntaxError => e
|
33
|
+
raise Error, e.message
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(path: String).returns(Tree) }
|
37
|
+
def parse_file(path)
|
38
|
+
parse(::File.read(path), file: path)
|
39
|
+
rescue ::Parser::SyntaxError => e
|
40
|
+
raise Error, e.message
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
sig { params(content: String, file: String).returns(Tree) }
|
46
|
+
def parse(content, file:)
|
47
|
+
node, comments = Unparser.parse_with_comments(content)
|
48
|
+
assoc = ::Parser::Source::Comment.associate_locations(node, comments)
|
49
|
+
builder = TreeBuilder.new(file: file, comments: assoc)
|
50
|
+
builder.visit(node)
|
51
|
+
builder.assoc_dangling_comments(comments)
|
52
|
+
builder.tree
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class ASTVisitor
|
57
|
+
extend T::Helpers
|
58
|
+
extend T::Sig
|
59
|
+
|
60
|
+
abstract!
|
61
|
+
|
62
|
+
sig { params(nodes: T::Array[AST::Node]).void }
|
63
|
+
def visit_all(nodes)
|
64
|
+
nodes.each { |node| visit(node) }
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { abstract.params(node: T.nilable(AST::Node)).void }
|
68
|
+
def visit(node); end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
sig { params(node: AST::Node).returns(String) }
|
73
|
+
def visit_name(node)
|
74
|
+
T.must(ConstBuilder.visit(node))
|
75
|
+
end
|
76
|
+
|
77
|
+
sig { params(node: AST::Node).returns(String) }
|
78
|
+
def visit_expr(node)
|
79
|
+
Unparser.unparse(node)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class TreeBuilder < ASTVisitor
|
84
|
+
extend T::Sig
|
85
|
+
|
86
|
+
sig { returns(Tree) }
|
87
|
+
attr_reader :tree
|
88
|
+
|
89
|
+
sig do
|
90
|
+
params(
|
91
|
+
file: String,
|
92
|
+
comments: T.nilable(T::Hash[::Parser::Source::Map, T::Array[::Parser::Source::Comment]])
|
93
|
+
).void
|
94
|
+
end
|
95
|
+
def initialize(file:, comments: nil)
|
96
|
+
super()
|
97
|
+
@file = file
|
98
|
+
@comments = comments
|
99
|
+
@tree = T.let(Tree.new, Tree)
|
100
|
+
@scopes_stack = T.let([@tree], T::Array[Tree])
|
101
|
+
@last_sigs = T.let([], T::Array[RBI::Sig])
|
102
|
+
end
|
103
|
+
|
104
|
+
sig { override.params(node: T.nilable(Object)).void }
|
105
|
+
def visit(node)
|
106
|
+
return unless node.is_a?(AST::Node)
|
107
|
+
case node.type
|
108
|
+
when :module, :class, :sclass
|
109
|
+
visit_scope(node)
|
110
|
+
when :casgn
|
111
|
+
visit_const_assign(node)
|
112
|
+
when :def, :defs
|
113
|
+
visit_def(node)
|
114
|
+
when :send
|
115
|
+
visit_send(node)
|
116
|
+
when :block
|
117
|
+
visit_block(node)
|
118
|
+
else
|
119
|
+
visit_all(node.children)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
sig { params(comments: T::Array[::Parser::Source::Comment]).void }
|
124
|
+
def assoc_dangling_comments(comments)
|
125
|
+
return unless tree.empty?
|
126
|
+
comments.each do |comment|
|
127
|
+
text = comment.text[1..-1].strip
|
128
|
+
loc = ast_to_rbi_loc(comment.location)
|
129
|
+
tree.comments << Comment.new(text, loc: loc)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
sig { params(node: AST::Node).void }
|
136
|
+
def visit_scope(node)
|
137
|
+
loc = node_loc(node)
|
138
|
+
comments = node_comments(node)
|
139
|
+
|
140
|
+
scope = case node.type
|
141
|
+
when :module
|
142
|
+
name = visit_name(node.children[0])
|
143
|
+
Module.new(name, loc: loc, comments: comments)
|
144
|
+
when :class
|
145
|
+
name = visit_name(node.children[0])
|
146
|
+
superclass_name = ConstBuilder.visit(node.children[1])
|
147
|
+
Class.new(name, superclass_name: superclass_name, loc: loc, comments: comments)
|
148
|
+
when :sclass
|
149
|
+
SingletonClass.new(loc: loc, comments: comments)
|
150
|
+
else
|
151
|
+
raise "Unsupported node #{node.type}"
|
152
|
+
end
|
153
|
+
current_scope << scope
|
154
|
+
|
155
|
+
@scopes_stack << scope
|
156
|
+
visit_all(node.children)
|
157
|
+
@scopes_stack.pop
|
158
|
+
end
|
159
|
+
|
160
|
+
sig { params(node: AST::Node).void }
|
161
|
+
def visit_const_assign(node)
|
162
|
+
name = visit_name(node)
|
163
|
+
value = visit_expr(node.children[2])
|
164
|
+
loc = node_loc(node)
|
165
|
+
comments = node_comments(node)
|
166
|
+
|
167
|
+
current_scope << Const.new(name, value, loc: loc, comments: comments)
|
168
|
+
end
|
169
|
+
|
170
|
+
sig { params(node: AST::Node).void }
|
171
|
+
def visit_def(node)
|
172
|
+
current_scope << case node.type
|
173
|
+
when :def
|
174
|
+
Method.new(
|
175
|
+
node.children[0].to_s,
|
176
|
+
params: node.children[1].children.map { |child| visit_param(child) },
|
177
|
+
sigs: current_sigs,
|
178
|
+
loc: node_loc(node),
|
179
|
+
comments: node_comments(node)
|
180
|
+
)
|
181
|
+
when :defs
|
182
|
+
Method.new(
|
183
|
+
node.children[1].to_s,
|
184
|
+
params: node.children[2].children.map { |child| visit_param(child) },
|
185
|
+
is_singleton: true,
|
186
|
+
sigs: current_sigs,
|
187
|
+
loc: node_loc(node),
|
188
|
+
comments: node_comments(node)
|
189
|
+
)
|
190
|
+
else
|
191
|
+
raise "Unsupported node #{node.type}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
sig { params(node: AST::Node).returns(Param) }
|
196
|
+
def visit_param(node)
|
197
|
+
name = node.children[0].to_s
|
198
|
+
loc = node_loc(node)
|
199
|
+
comments = node_comments(node)
|
200
|
+
|
201
|
+
case node.type
|
202
|
+
when :arg
|
203
|
+
Param.new(name, loc: loc, comments: comments)
|
204
|
+
when :optarg
|
205
|
+
value = visit_expr(node.children[1])
|
206
|
+
OptParam.new(name, value, loc: loc, comments: comments)
|
207
|
+
when :restarg
|
208
|
+
RestParam.new(name, loc: loc, comments: comments)
|
209
|
+
when :kwarg
|
210
|
+
KwParam.new(name, loc: loc, comments: comments)
|
211
|
+
when :kwoptarg
|
212
|
+
value = visit_expr(node.children[1])
|
213
|
+
KwOptParam.new(name, value, loc: loc, comments: comments)
|
214
|
+
when :kwrestarg
|
215
|
+
KwRestParam.new(name, loc: loc, comments: comments)
|
216
|
+
when :blockarg
|
217
|
+
BlockParam.new(name, loc: loc, comments: comments)
|
218
|
+
else
|
219
|
+
raise "Unsupported node #{node.type}"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
sig { params(node: AST::Node).void }
|
224
|
+
def visit_send(node)
|
225
|
+
recv = node.children[0]
|
226
|
+
return if recv && recv != :self
|
227
|
+
|
228
|
+
method_name = node.children[1]
|
229
|
+
loc = node_loc(node)
|
230
|
+
comments = node_comments(node)
|
231
|
+
|
232
|
+
current_scope << case method_name
|
233
|
+
when :attr_reader
|
234
|
+
symbols = node.children[2..-1].map { |child| child.children[0] }
|
235
|
+
AttrReader.new(*symbols, sigs: current_sigs, loc: loc, comments: comments)
|
236
|
+
when :attr_writer
|
237
|
+
symbols = node.children[2..-1].map { |child| child.children[0] }
|
238
|
+
AttrWriter.new(*symbols, sigs: current_sigs, loc: loc, comments: comments)
|
239
|
+
when :attr_accessor
|
240
|
+
symbols = node.children[2..-1].map { |child| child.children[0] }
|
241
|
+
AttrAccessor.new(*symbols, sigs: current_sigs, loc: loc, comments: comments)
|
242
|
+
when :include
|
243
|
+
names = node.children[2..-1].map { |child| visit_name(child) }
|
244
|
+
Include.new(*names, loc: loc, comments: comments)
|
245
|
+
when :extend
|
246
|
+
names = node.children[2..-1].map { |child| visit_name(child) }
|
247
|
+
Extend.new(*names, loc: loc, comments: comments)
|
248
|
+
when :abstract!, :sealed!, :interface!
|
249
|
+
Helper.new(method_name.to_s.delete_suffix("!"), loc: loc, comments: comments)
|
250
|
+
when :mixes_in_class_methods
|
251
|
+
names = node.children[2..-1].map { |child| visit_name(child) }
|
252
|
+
MixesInClassMethods.new(*names, loc: loc, comments: comments)
|
253
|
+
when :public, :protected, :private
|
254
|
+
Visibility.new(method_name, loc: loc)
|
255
|
+
when :prop
|
256
|
+
name, type, default_value = visit_struct_prop(node)
|
257
|
+
TStructProp.new(name, type, default: default_value, loc: loc, comments: comments)
|
258
|
+
when :const
|
259
|
+
name, type, default_value = visit_struct_prop(node)
|
260
|
+
TStructConst.new(name, type, default: default_value, loc: loc, comments: comments)
|
261
|
+
else
|
262
|
+
raise "Unsupported node #{node.type} with name #{method_name}"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
sig { params(node: AST::Node).void }
|
267
|
+
def visit_block(node)
|
268
|
+
name = node.children[0].children[1]
|
269
|
+
|
270
|
+
case name
|
271
|
+
when :sig
|
272
|
+
@last_sigs << visit_sig(node)
|
273
|
+
when :enums
|
274
|
+
current_scope << visit_enum(node)
|
275
|
+
else
|
276
|
+
raise "Unsupported node #{node.type} with name #{name}"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
sig { params(node: AST::Node).returns([String, String, T.nilable(String)]) }
|
281
|
+
def visit_struct_prop(node)
|
282
|
+
name = node.children[2].children[0].to_s
|
283
|
+
type = visit_expr(node.children[3])
|
284
|
+
has_default = node.children[4]
|
285
|
+
&.children&.fetch(0, nil)
|
286
|
+
&.children&.fetch(0, nil)
|
287
|
+
&.children&.fetch(0, nil) == :default
|
288
|
+
default_value = if has_default
|
289
|
+
visit_expr(node.children.fetch(4, nil)
|
290
|
+
&.children&.fetch(0, nil)
|
291
|
+
&.children&.fetch(1, nil))
|
292
|
+
end
|
293
|
+
[name, type, default_value]
|
294
|
+
end
|
295
|
+
|
296
|
+
sig { params(node: AST::Node).returns(Sig) }
|
297
|
+
def visit_sig(node)
|
298
|
+
sig = SigBuilder.build(node)
|
299
|
+
sig.loc = node_loc(node)
|
300
|
+
sig
|
301
|
+
end
|
302
|
+
|
303
|
+
sig { params(node: AST::Node).returns(TEnumBlock) }
|
304
|
+
def visit_enum(node)
|
305
|
+
enum = TEnumBlock.new
|
306
|
+
node.children[2].children.each do |child|
|
307
|
+
enum << visit_name(child)
|
308
|
+
end
|
309
|
+
enum.loc = node_loc(node)
|
310
|
+
enum
|
311
|
+
end
|
312
|
+
|
313
|
+
sig { params(node: AST::Node).returns(Loc) }
|
314
|
+
def node_loc(node)
|
315
|
+
ast_to_rbi_loc(node.location)
|
316
|
+
end
|
317
|
+
|
318
|
+
sig { params(ast_loc: ::Parser::Source::Map).returns(Loc) }
|
319
|
+
def ast_to_rbi_loc(ast_loc)
|
320
|
+
Loc.new(
|
321
|
+
file: @file,
|
322
|
+
begin_line: ast_loc.line,
|
323
|
+
begin_column: ast_loc.column,
|
324
|
+
end_line: ast_loc.last_line,
|
325
|
+
end_column: ast_loc.last_column
|
326
|
+
)
|
327
|
+
end
|
328
|
+
|
329
|
+
sig { params(node: AST::Node).returns(T::Array[Comment]) }
|
330
|
+
def node_comments(node)
|
331
|
+
return [] unless @comments
|
332
|
+
comments = @comments[node.location]
|
333
|
+
return [] unless comments
|
334
|
+
comments.map do |comment|
|
335
|
+
text = comment.text[1..-1].strip
|
336
|
+
loc = ast_to_rbi_loc(comment.location)
|
337
|
+
Comment.new(text, loc: loc)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
sig { returns(Tree) }
|
342
|
+
def current_scope
|
343
|
+
T.must(@scopes_stack.last) # Should never be nil since we create a Tree as the root
|
344
|
+
end
|
345
|
+
|
346
|
+
sig { returns(T::Array[Sig]) }
|
347
|
+
def current_sigs
|
348
|
+
sigs = @last_sigs.dup
|
349
|
+
@last_sigs.clear
|
350
|
+
sigs
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
class ConstBuilder < ASTVisitor
|
355
|
+
extend T::Sig
|
356
|
+
|
357
|
+
sig { params(node: T.nilable(AST::Node)).returns(T.nilable(String)) }
|
358
|
+
def self.visit(node)
|
359
|
+
v = ConstBuilder.new
|
360
|
+
v.visit(node)
|
361
|
+
return nil if v.names.empty?
|
362
|
+
v.names.join("::")
|
363
|
+
end
|
364
|
+
|
365
|
+
sig { returns(T::Array[String]) }
|
366
|
+
attr_accessor :names
|
367
|
+
|
368
|
+
sig { void }
|
369
|
+
def initialize
|
370
|
+
super
|
371
|
+
@names = T.let([], T::Array[String])
|
372
|
+
end
|
373
|
+
|
374
|
+
sig { override.params(node: T.nilable(AST::Node)).void }
|
375
|
+
def visit(node)
|
376
|
+
return unless node
|
377
|
+
case node.type
|
378
|
+
when :const, :casgn
|
379
|
+
visit(node.children[0])
|
380
|
+
@names << node.children[1].to_s
|
381
|
+
when :cbase
|
382
|
+
@names << ""
|
383
|
+
when :sym
|
384
|
+
@names << ":#{node.children[0]}"
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
class SigBuilder < ASTVisitor
|
390
|
+
extend T::Sig
|
391
|
+
|
392
|
+
sig { params(node: AST::Node).returns(Sig) }
|
393
|
+
def self.build(node)
|
394
|
+
v = SigBuilder.new
|
395
|
+
v.visit_all(node.children[2..-1])
|
396
|
+
v.current
|
397
|
+
end
|
398
|
+
|
399
|
+
sig { returns(Sig) }
|
400
|
+
attr_accessor :current
|
401
|
+
|
402
|
+
sig { void }
|
403
|
+
def initialize
|
404
|
+
super
|
405
|
+
@current = T.let(Sig.new, Sig)
|
406
|
+
end
|
407
|
+
|
408
|
+
sig { override.params(node: T.nilable(AST::Node)).void }
|
409
|
+
def visit(node)
|
410
|
+
return unless node
|
411
|
+
case node.type
|
412
|
+
when :send
|
413
|
+
visit_send(node)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
sig { params(node: AST::Node).void }
|
418
|
+
def visit_send(node)
|
419
|
+
visit(node.children[0]) if node.children[0]
|
420
|
+
name = node.children[1]
|
421
|
+
case name
|
422
|
+
when :abstract
|
423
|
+
@current.is_abstract = true
|
424
|
+
when :override
|
425
|
+
@current.is_override = true
|
426
|
+
when :overridable
|
427
|
+
@current.is_overridable = true
|
428
|
+
when :checked
|
429
|
+
@current.checked = node.children[2].children[0]
|
430
|
+
when :type_parameters
|
431
|
+
node.children[2..-1].each do |child|
|
432
|
+
@current.type_params << child.children[0].to_s
|
433
|
+
end
|
434
|
+
when :params
|
435
|
+
node.children[2].children.each do |child|
|
436
|
+
name = child.children[0].children[0].to_s
|
437
|
+
type = visit_expr(child.children[1])
|
438
|
+
@current << SigParam.new(name, type)
|
439
|
+
end
|
440
|
+
when :returns
|
441
|
+
@current.return_type = visit_expr(node.children[2])
|
442
|
+
when :void
|
443
|
+
@current.return_type = nil
|
444
|
+
else
|
445
|
+
raise "#{node.location.line}: Unhandled #{name}"
|
446
|
+
end
|
447
|
+
end
|
448
|
+
end
|
449
|
+
end
|
data/lib/rbi/printer.rb
ADDED
@@ -0,0 +1,643 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RBI
|
5
|
+
class Printer < Visitor
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { returns(T::Boolean) }
|
9
|
+
attr_accessor :print_locs, :in_visibility_group
|
10
|
+
|
11
|
+
sig { returns(T.nilable(Node)) }
|
12
|
+
attr_reader :previous_node
|
13
|
+
|
14
|
+
sig { params(out: T.any(IO, StringIO), indent: Integer, print_locs: T::Boolean).void }
|
15
|
+
def initialize(out: $stdout, indent: 0, print_locs: false)
|
16
|
+
super()
|
17
|
+
@out = out
|
18
|
+
@current_indent = indent
|
19
|
+
@print_locs = print_locs
|
20
|
+
@in_visibility_group = T.let(false, T::Boolean)
|
21
|
+
@previous_node = T.let(nil, T.nilable(Node))
|
22
|
+
end
|
23
|
+
|
24
|
+
# Printing
|
25
|
+
|
26
|
+
sig { void }
|
27
|
+
def indent
|
28
|
+
@current_indent += 2
|
29
|
+
end
|
30
|
+
|
31
|
+
sig { void }
|
32
|
+
def dedent
|
33
|
+
@current_indent -= 2
|
34
|
+
end
|
35
|
+
|
36
|
+
# Print a string without indentation nor `\n` at the end.
|
37
|
+
sig { params(string: String).void }
|
38
|
+
def print(string)
|
39
|
+
@out.print(string)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Print a string without indentation but with a `\n` at the end.
|
43
|
+
sig { params(string: T.nilable(String)).void }
|
44
|
+
def printn(string = nil)
|
45
|
+
print(string) if string
|
46
|
+
print("\n")
|
47
|
+
end
|
48
|
+
|
49
|
+
# Print a string with indentation but without a `\n` at the end.
|
50
|
+
sig { params(string: T.nilable(String)).void }
|
51
|
+
def printt(string = nil)
|
52
|
+
print(" " * @current_indent)
|
53
|
+
print(string) if string
|
54
|
+
end
|
55
|
+
|
56
|
+
# Print a string with indentation and `\n` at the end.
|
57
|
+
sig { params(string: String).void }
|
58
|
+
def printl(string)
|
59
|
+
printt
|
60
|
+
printn(string)
|
61
|
+
end
|
62
|
+
|
63
|
+
sig { params(file: File).void }
|
64
|
+
def visit_file(file)
|
65
|
+
file.accept_printer(self)
|
66
|
+
end
|
67
|
+
|
68
|
+
sig { override.params(node: T.nilable(Node)).void }
|
69
|
+
def visit(node)
|
70
|
+
return unless node
|
71
|
+
node.accept_printer(self)
|
72
|
+
end
|
73
|
+
|
74
|
+
sig { override.params(nodes: T::Array[Node]).void }
|
75
|
+
def visit_all(nodes)
|
76
|
+
previous_node = @previous_node
|
77
|
+
@previous_node = nil
|
78
|
+
nodes.each do |node|
|
79
|
+
visit(node)
|
80
|
+
@previous_node = node
|
81
|
+
end
|
82
|
+
@previous_node = previous_node
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class File
|
87
|
+
extend T::Sig
|
88
|
+
|
89
|
+
sig { params(v: Printer).void }
|
90
|
+
def accept_printer(v)
|
91
|
+
strictness = self.strictness
|
92
|
+
if strictness
|
93
|
+
v.printl("# typed: #{strictness}")
|
94
|
+
end
|
95
|
+
unless comments.empty?
|
96
|
+
v.printn if strictness
|
97
|
+
v.visit_all(comments)
|
98
|
+
end
|
99
|
+
|
100
|
+
unless root.empty?
|
101
|
+
v.printn if strictness || !comments.empty?
|
102
|
+
v.visit(root)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
sig { params(out: T.any(IO, StringIO), indent: Integer, print_locs: T::Boolean).void }
|
107
|
+
def print(out: $stdout, indent: 0, print_locs: false)
|
108
|
+
p = Printer.new(out: out, indent: indent, print_locs: print_locs)
|
109
|
+
p.visit_file(self)
|
110
|
+
end
|
111
|
+
|
112
|
+
sig { params(indent: Integer, print_locs: T::Boolean).returns(String) }
|
113
|
+
def string(indent: 0, print_locs: false)
|
114
|
+
out = StringIO.new
|
115
|
+
print(out: out, indent: indent, print_locs: print_locs)
|
116
|
+
out.string
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Node
|
121
|
+
extend T::Sig
|
122
|
+
|
123
|
+
sig { abstract.params(v: Printer).void }
|
124
|
+
def accept_printer(v); end
|
125
|
+
|
126
|
+
sig { params(out: T.any(IO, StringIO), indent: Integer, print_locs: T::Boolean).void }
|
127
|
+
def print(out: $stdout, indent: 0, print_locs: false)
|
128
|
+
p = Printer.new(out: out, indent: indent, print_locs: print_locs)
|
129
|
+
p.visit(self)
|
130
|
+
end
|
131
|
+
|
132
|
+
sig { params(indent: Integer, print_locs: T::Boolean).returns(String) }
|
133
|
+
def string(indent: 0, print_locs: false)
|
134
|
+
out = StringIO.new
|
135
|
+
print(out: out, indent: indent, print_locs: print_locs)
|
136
|
+
out.string
|
137
|
+
end
|
138
|
+
|
139
|
+
sig { returns(T::Boolean) }
|
140
|
+
def oneline?
|
141
|
+
true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class NodeWithComments
|
146
|
+
extend T::Sig
|
147
|
+
|
148
|
+
sig { override.returns(T::Boolean) }
|
149
|
+
def oneline?
|
150
|
+
comments.empty?
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class Comment
|
155
|
+
extend T::Sig
|
156
|
+
|
157
|
+
sig { override.params(v: Printer).void }
|
158
|
+
def accept_printer(v)
|
159
|
+
text = self.text.strip
|
160
|
+
v.printt("#")
|
161
|
+
v.print(" #{text}") unless text.empty?
|
162
|
+
v.printn
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class Tree
|
167
|
+
extend T::Sig
|
168
|
+
|
169
|
+
sig { override.params(v: Printer).void }
|
170
|
+
def accept_printer(v)
|
171
|
+
v.visit_all(comments)
|
172
|
+
v.printn if !comments.empty? && !empty?
|
173
|
+
v.visit_all(nodes)
|
174
|
+
end
|
175
|
+
|
176
|
+
sig { override.returns(T::Boolean) }
|
177
|
+
def oneline?
|
178
|
+
comments.empty? && empty?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class Scope
|
183
|
+
extend T::Sig
|
184
|
+
|
185
|
+
sig { override.params(v: Printer).void }
|
186
|
+
def accept_printer(v)
|
187
|
+
previous_node = v.previous_node
|
188
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
189
|
+
|
190
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
191
|
+
v.visit_all(comments)
|
192
|
+
|
193
|
+
print_header(v)
|
194
|
+
print_body(v)
|
195
|
+
end
|
196
|
+
|
197
|
+
sig { abstract.params(v: Printer).void }
|
198
|
+
def print_header(v); end
|
199
|
+
|
200
|
+
sig { params(v: Printer).void }
|
201
|
+
def print_body(v)
|
202
|
+
unless empty?
|
203
|
+
v.indent
|
204
|
+
v.visit_all(nodes)
|
205
|
+
v.dedent
|
206
|
+
v.printl("end")
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
class Module
|
212
|
+
extend T::Sig
|
213
|
+
|
214
|
+
sig { override.params(v: Printer).void }
|
215
|
+
def print_header(v)
|
216
|
+
v.printt("module #{name}")
|
217
|
+
if empty?
|
218
|
+
v.printn("; end")
|
219
|
+
else
|
220
|
+
v.printn
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
class Class
|
226
|
+
extend T::Sig
|
227
|
+
|
228
|
+
sig { override.params(v: Printer).void }
|
229
|
+
def print_header(v)
|
230
|
+
v.printt("class #{name}")
|
231
|
+
superclass = superclass_name
|
232
|
+
v.print(" < #{superclass}") if superclass
|
233
|
+
if empty?
|
234
|
+
v.printn("; end")
|
235
|
+
else
|
236
|
+
v.printn
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
class SingletonClass
|
242
|
+
extend T::Sig
|
243
|
+
|
244
|
+
sig { override.params(v: Printer).void }
|
245
|
+
def print_header(v)
|
246
|
+
v.printt("class << self")
|
247
|
+
if empty?
|
248
|
+
v.printn("; end")
|
249
|
+
else
|
250
|
+
v.printn
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
class Const
|
256
|
+
extend T::Sig
|
257
|
+
|
258
|
+
sig { override.params(v: Printer).void }
|
259
|
+
def accept_printer(v)
|
260
|
+
previous_node = v.previous_node
|
261
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
262
|
+
|
263
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
264
|
+
v.visit_all(comments)
|
265
|
+
v.printl("#{name} = #{value}")
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
class Attr
|
270
|
+
extend T::Sig
|
271
|
+
|
272
|
+
sig { override.params(v: Printer).void }
|
273
|
+
def accept_printer(v)
|
274
|
+
previous_node = v.previous_node
|
275
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
276
|
+
|
277
|
+
v.visit_all(comments)
|
278
|
+
sigs.each { |sig| v.visit(sig) }
|
279
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
280
|
+
v.printt
|
281
|
+
unless v.in_visibility_group || visibility == Visibility::Public
|
282
|
+
v.print(visibility.visibility.to_s)
|
283
|
+
v.print(" ")
|
284
|
+
end
|
285
|
+
case self
|
286
|
+
when AttrAccessor
|
287
|
+
v.print("attr_accessor")
|
288
|
+
when AttrReader
|
289
|
+
v.print("attr_reader")
|
290
|
+
when AttrWriter
|
291
|
+
v.print("attr_writer")
|
292
|
+
end
|
293
|
+
unless names.empty?
|
294
|
+
v.print(" ")
|
295
|
+
v.print(names.map { |name| ":#{name}" }.join(", "))
|
296
|
+
end
|
297
|
+
v.printn
|
298
|
+
end
|
299
|
+
|
300
|
+
sig { override.returns(T::Boolean) }
|
301
|
+
def oneline?
|
302
|
+
comments.empty? && sigs.empty?
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
class Method
|
307
|
+
extend T::Sig
|
308
|
+
|
309
|
+
sig { override.params(v: Printer).void }
|
310
|
+
def accept_printer(v)
|
311
|
+
previous_node = v.previous_node
|
312
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
313
|
+
|
314
|
+
v.visit_all(comments)
|
315
|
+
v.visit_all(sigs)
|
316
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
317
|
+
v.printt
|
318
|
+
unless v.in_visibility_group || visibility == Visibility::Public
|
319
|
+
v.print(visibility.visibility.to_s)
|
320
|
+
v.print(" ")
|
321
|
+
end
|
322
|
+
v.print("def ")
|
323
|
+
v.print("self.") if is_singleton
|
324
|
+
v.print(name)
|
325
|
+
unless params.empty?
|
326
|
+
v.print("(")
|
327
|
+
if inline_params?
|
328
|
+
params.each_with_index do |param, index|
|
329
|
+
v.print(", ") if index > 0
|
330
|
+
v.visit(param)
|
331
|
+
end
|
332
|
+
else
|
333
|
+
v.printn
|
334
|
+
v.indent
|
335
|
+
params.each_with_index do |param, pindex|
|
336
|
+
v.printt
|
337
|
+
v.visit(param)
|
338
|
+
v.print(",") if pindex < params.size - 1
|
339
|
+
param.comments.each_with_index do |comment, cindex|
|
340
|
+
if cindex > 0
|
341
|
+
param.print_comment_leading_space(v)
|
342
|
+
else
|
343
|
+
v.print(" ")
|
344
|
+
end
|
345
|
+
v.print("# #{comment.text.strip}")
|
346
|
+
end
|
347
|
+
v.printn
|
348
|
+
end
|
349
|
+
v.dedent
|
350
|
+
end
|
351
|
+
v.print(")")
|
352
|
+
end
|
353
|
+
v.print("; end")
|
354
|
+
v.printn
|
355
|
+
end
|
356
|
+
|
357
|
+
sig { override.returns(T::Boolean) }
|
358
|
+
def oneline?
|
359
|
+
comments.empty? && sigs.empty? && inline_params?
|
360
|
+
end
|
361
|
+
|
362
|
+
sig { returns(T::Boolean) }
|
363
|
+
def inline_params?
|
364
|
+
params.all? { |p| p.comments.empty? }
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
class Param
|
369
|
+
extend T::Sig
|
370
|
+
|
371
|
+
sig { override.params(v: Printer).void }
|
372
|
+
def accept_printer(v)
|
373
|
+
v.print(name.to_s)
|
374
|
+
end
|
375
|
+
|
376
|
+
sig { params(v: Printer).void }
|
377
|
+
def print_comment_leading_space(v)
|
378
|
+
v.printn
|
379
|
+
v.printt
|
380
|
+
v.print(" " * (name.size + 2))
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
class OptParam
|
385
|
+
extend T::Sig
|
386
|
+
|
387
|
+
sig { override.params(v: Printer).void }
|
388
|
+
def accept_printer(v)
|
389
|
+
v.print("#{name} = #{value}")
|
390
|
+
end
|
391
|
+
|
392
|
+
sig { override.params(v: Printer).void }
|
393
|
+
def print_comment_leading_space(v)
|
394
|
+
super
|
395
|
+
v.print(" " * (value.size + 3))
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
class RestParam
|
400
|
+
extend T::Sig
|
401
|
+
|
402
|
+
sig { override.params(v: Printer).void }
|
403
|
+
def accept_printer(v)
|
404
|
+
v.print("*#{name}")
|
405
|
+
end
|
406
|
+
|
407
|
+
sig { override.params(v: Printer).void }
|
408
|
+
def print_comment_leading_space(v)
|
409
|
+
super
|
410
|
+
v.print(" ")
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
class KwParam
|
415
|
+
extend T::Sig
|
416
|
+
|
417
|
+
sig { override.params(v: Printer).void }
|
418
|
+
def accept_printer(v)
|
419
|
+
v.print("#{name}:")
|
420
|
+
end
|
421
|
+
|
422
|
+
sig { override.params(v: Printer).void }
|
423
|
+
def print_comment_leading_space(v)
|
424
|
+
super
|
425
|
+
v.print(" ")
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
class KwOptParam
|
430
|
+
extend T::Sig
|
431
|
+
|
432
|
+
sig { override.params(v: Printer).void }
|
433
|
+
def accept_printer(v)
|
434
|
+
v.print("#{name}: #{value}")
|
435
|
+
end
|
436
|
+
|
437
|
+
sig { override.params(v: Printer).void }
|
438
|
+
def print_comment_leading_space(v)
|
439
|
+
v.printn
|
440
|
+
v.printt
|
441
|
+
v.print(" " * (name.size + 2))
|
442
|
+
v.print(" " * (value.size + 2))
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
class KwRestParam
|
447
|
+
extend T::Sig
|
448
|
+
|
449
|
+
sig { override.params(v: Printer).void }
|
450
|
+
def accept_printer(v)
|
451
|
+
v.print("**#{name}")
|
452
|
+
end
|
453
|
+
|
454
|
+
sig { override.params(v: Printer).void }
|
455
|
+
def print_comment_leading_space(v)
|
456
|
+
super
|
457
|
+
v.print(" ")
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
class BlockParam
|
462
|
+
extend T::Sig
|
463
|
+
|
464
|
+
sig { override.params(v: Printer).void }
|
465
|
+
def accept_printer(v)
|
466
|
+
v.print("&#{name}")
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
class Mixin
|
471
|
+
extend T::Sig
|
472
|
+
|
473
|
+
sig { override.params(v: Printer).void }
|
474
|
+
def accept_printer(v)
|
475
|
+
previous_node = v.previous_node
|
476
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
477
|
+
|
478
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
479
|
+
v.visit_all(comments)
|
480
|
+
case self
|
481
|
+
when Include
|
482
|
+
v.printt("include")
|
483
|
+
when Extend
|
484
|
+
v.printt("extend")
|
485
|
+
when MixesInClassMethods
|
486
|
+
v.printt("mixes_in_class_methods")
|
487
|
+
end
|
488
|
+
v.printn(" #{names.join(", ")}")
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
class Visibility
|
493
|
+
extend T::Sig
|
494
|
+
|
495
|
+
sig { override.params(v: Printer).void }
|
496
|
+
def accept_printer(v)
|
497
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
498
|
+
v.printl(visibility.to_s)
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
class Sig
|
503
|
+
extend T::Sig
|
504
|
+
|
505
|
+
sig { override.params(v: Printer).void }
|
506
|
+
def accept_printer(v)
|
507
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
508
|
+
v.printt("sig { ")
|
509
|
+
v.print("abstract.") if is_abstract
|
510
|
+
v.print("override.") if is_override
|
511
|
+
v.print("overridable.") if is_overridable
|
512
|
+
unless type_params.empty?
|
513
|
+
v.print("type_parameters(")
|
514
|
+
type_params.each_with_index do |param, index|
|
515
|
+
v.print(":#{param}")
|
516
|
+
v.print(", ") if index < type_params.length - 1
|
517
|
+
end
|
518
|
+
v.print(").")
|
519
|
+
end
|
520
|
+
unless params.empty?
|
521
|
+
v.print("params(")
|
522
|
+
params.each_with_index do |param, index|
|
523
|
+
v.visit(param)
|
524
|
+
v.print(", ") if index < params.length - 1
|
525
|
+
end
|
526
|
+
v.print(").")
|
527
|
+
end
|
528
|
+
if return_type && return_type != "void"
|
529
|
+
v.print("returns(#{return_type})")
|
530
|
+
else
|
531
|
+
v.print("void")
|
532
|
+
end
|
533
|
+
if checked
|
534
|
+
v.print(".checked(:#{checked})")
|
535
|
+
end
|
536
|
+
v.printn(" }")
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
class SigParam
|
541
|
+
extend T::Sig
|
542
|
+
|
543
|
+
sig { override.params(v: Printer).void }
|
544
|
+
def accept_printer(v)
|
545
|
+
v.print("#{name}: #{type}")
|
546
|
+
end
|
547
|
+
end
|
548
|
+
|
549
|
+
class TStructField
|
550
|
+
extend T::Sig
|
551
|
+
|
552
|
+
sig { override.params(v: Printer).void }
|
553
|
+
def accept_printer(v)
|
554
|
+
previous_node = v.previous_node
|
555
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
556
|
+
|
557
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
558
|
+
v.visit_all(comments)
|
559
|
+
case self
|
560
|
+
when TStructProp
|
561
|
+
v.printt("prop")
|
562
|
+
when TStructConst
|
563
|
+
v.printt("const")
|
564
|
+
end
|
565
|
+
v.print(" :#{name}, #{type}")
|
566
|
+
default = self.default
|
567
|
+
v.print(", default: #{default}") if default
|
568
|
+
v.printn
|
569
|
+
end
|
570
|
+
end
|
571
|
+
|
572
|
+
class TEnumBlock
|
573
|
+
extend T::Sig
|
574
|
+
|
575
|
+
sig { override.params(v: Printer).void }
|
576
|
+
def accept_printer(v)
|
577
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
578
|
+
v.visit_all(comments)
|
579
|
+
v.printl("enums do")
|
580
|
+
v.indent
|
581
|
+
names.each do |name|
|
582
|
+
v.printl("#{name} = new")
|
583
|
+
end
|
584
|
+
v.dedent
|
585
|
+
v.printl("end")
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
class TypeMember
|
590
|
+
extend T::Sig
|
591
|
+
|
592
|
+
sig { override.params(v: Printer).void }
|
593
|
+
def accept_printer(v)
|
594
|
+
previous_node = v.previous_node
|
595
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
596
|
+
|
597
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
598
|
+
v.visit_all(comments)
|
599
|
+
v.printl("#{name} = #{value}")
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
class Helper
|
604
|
+
extend T::Sig
|
605
|
+
|
606
|
+
sig { override.params(v: Printer).void }
|
607
|
+
def accept_printer(v)
|
608
|
+
previous_node = v.previous_node
|
609
|
+
v.printn if previous_node && (!previous_node.oneline? || !oneline?)
|
610
|
+
|
611
|
+
v.printl("# #{loc}") if loc && v.print_locs
|
612
|
+
v.visit_all(comments)
|
613
|
+
v.printl("#{name}!")
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
class Group
|
618
|
+
extend T::Sig
|
619
|
+
|
620
|
+
sig { override.params(v: Printer).void }
|
621
|
+
def accept_printer(v)
|
622
|
+
v.printn unless v.previous_node.nil?
|
623
|
+
v.visit_all(nodes)
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
627
|
+
class VisibilityGroup
|
628
|
+
extend T::Sig
|
629
|
+
|
630
|
+
sig { override.params(v: Printer).void }
|
631
|
+
def accept_printer(v)
|
632
|
+
v.in_visibility_group = true
|
633
|
+
v.printn unless v.previous_node.nil?
|
634
|
+
case visibility
|
635
|
+
when Visibility::Protected, Visibility::Private
|
636
|
+
v.visit(visibility)
|
637
|
+
v.printn
|
638
|
+
end
|
639
|
+
v.visit_all(nodes)
|
640
|
+
v.in_visibility_group = false
|
641
|
+
end
|
642
|
+
end
|
643
|
+
end
|