rbi 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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