rbs-inline 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,599 @@
1
+ # rbs_inline: enabled
2
+
3
+ module RBS
4
+ module Inline
5
+ module AST
6
+ module Members
7
+ class Base
8
+ attr_reader :location #:: Prism::Location
9
+
10
+ # @rbs location: Prism::Location
11
+ def initialize(location) #:: void
12
+ @location = location
13
+ end
14
+
15
+ def start_line #:: Integer
16
+ location.start_line
17
+ end
18
+ end
19
+
20
+ class RubyBase < Base
21
+ end
22
+
23
+ class RubyDef < RubyBase
24
+ attr_reader :node #:: Prism::DefNode
25
+ attr_reader :comments #:: AnnotationParser::ParsingResult?
26
+
27
+ # The visibility directly attached to the `def` node
28
+ #
29
+ # `nil` when the `def` node is not passed to `private`/`public` calls.
30
+ #
31
+ # ```rb
32
+ # def foo() end # <= nil
33
+ # private def foo() end # <= :private
34
+ # ```
35
+ attr_reader :visibility #:: RBS::AST::Members::visibility?
36
+
37
+ attr_reader :assertion #:: Annotations::Assertion?
38
+
39
+ # @rbs node: Prism::DefNode
40
+ # @rbs comments: AnnotationParser::ParsingResult?
41
+ # @rbs visibility: RBS::AST::Members::visibility?
42
+ # @rbs assertion: Annotations::Assertion?
43
+ def initialize(node, comments, visibility, assertion) #:: void
44
+ @node = node
45
+ @comments = comments
46
+ @visibility = visibility
47
+ @assertion = assertion
48
+
49
+ super(node.location)
50
+ end
51
+
52
+ # Returns the name of the method
53
+ def method_name #:: Symbol
54
+ node.name
55
+ end
56
+
57
+ def method_type_annotations #:: Array[Annotations::Assertion]
58
+ if comments
59
+ comments.annotations.select do |annotation|
60
+ annotation.is_a?(Annotations::Assertion) && annotation.type.is_a?(MethodType)
61
+ end #: Array[Annotations::Assertion]
62
+ else
63
+ []
64
+ end
65
+ end
66
+
67
+ # Returns the `kind` of the method definition
68
+ #
69
+ # [FIXME] It only supports `self` receiver.
70
+ #
71
+ # ```rb
72
+ # def self.foo = () # :sigleton
73
+ # def object.foo = () # Not supported (returns :instance)
74
+ # ```
75
+ #
76
+ def method_kind #:: RBS::AST::Members::MethodDefinition::kind
77
+ # FIXME: really hacky implementation
78
+ case node.receiver
79
+ when Prism::SelfNode
80
+ :singleton
81
+ when nil
82
+ :instance
83
+ else
84
+ :instance
85
+ end
86
+ end
87
+
88
+ def return_type #:: Types::t?
89
+ if assertion
90
+ if assertion.type?
91
+ return assertion.type?
92
+ end
93
+ end
94
+ if comments
95
+ annot = comments.annotations.find {|annot| annot.is_a?(Annotations::ReturnType ) } #: Annotations::ReturnType?
96
+ if annot
97
+ annot.type
98
+ end
99
+ end
100
+ end
101
+
102
+ def var_type_hash #:: Hash[Symbol, Types::t?]
103
+ types = {} #: Hash[Symbol, Types::t?]
104
+
105
+ if comments
106
+ comments.annotations.each do |annotation|
107
+ if annotation.is_a?(Annotations::VarType)
108
+ name = annotation.name
109
+ type = annotation.type
110
+
111
+ if name
112
+ types[name] = type
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ types
119
+ end
120
+
121
+ def method_overloads #:: Array[RBS::AST::Members::MethodDefinition::Overload]
122
+ if !(annots = method_type_annotations).empty?
123
+ annots.map do
124
+ method_type = _1.type #: MethodType
125
+
126
+ RBS::AST::Members::MethodDefinition::Overload.new(
127
+ method_type: method_type,
128
+ annotations: []
129
+ )
130
+ end
131
+ else
132
+ required_positionals = [] #: Array[Types::Function::Param]
133
+ optional_positionals = [] #: Array[Types::Function::Param]
134
+ rest_positionals = nil #: Types::Function::Param?
135
+ required_keywords = {} #: Hash[Symbol, Types::Function::Param]
136
+ optional_keywords = {} #: Hash[Symbol, Types::Function::Param]
137
+ rest_keywords = nil #: Types::Function::Param?
138
+
139
+ if node.parameters
140
+ node.parameters.requireds.each do |param|
141
+ case param
142
+ when Prism::RequiredParameterNode
143
+ required_positionals << Types::Function::Param.new(
144
+ name: param.name,
145
+ type: var_type_hash[param.name] || Types::Bases::Any.new(location: nil),
146
+ location: nil
147
+ )
148
+ end
149
+ end
150
+
151
+ node.parameters.optionals.each do |param|
152
+ case param
153
+ when Prism::OptionalParameterNode
154
+ optional_positionals << Types::Function::Param.new(
155
+ name: param.name,
156
+ type: var_type_hash[param.name] || Types::Bases::Any.new(location: nil),
157
+ location: nil
158
+ )
159
+ end
160
+ end
161
+
162
+ if (rest = node.parameters.rest).is_a?(Prism::RestParameterNode)
163
+ rest_type =
164
+ if rest.name
165
+ var_type_hash[rest.name]
166
+ end
167
+
168
+ if rest_type
169
+ if rest_type.is_a?(Types::ClassInstance)
170
+ if rest_type.name.name == :Array && rest_type.name.namespace.empty?
171
+ rest_type = rest_type.args[0]
172
+ end
173
+ end
174
+ end
175
+
176
+ rest_positionals = Types::Function::Param.new(
177
+ name: rest.name,
178
+ type: rest_type || Types::Bases::Any.new(location: nil),
179
+ location: nil
180
+ )
181
+ end
182
+
183
+ node.parameters.keywords.each do |node|
184
+ if node.is_a?(Prism::RequiredKeywordParameterNode)
185
+ required_keywords[node.name] = Types::Function::Param.new(
186
+ name: nil,
187
+ type: var_type_hash[node.name] || Types::Bases::Any.new(location: nil),
188
+ location: nil
189
+ )
190
+ end
191
+
192
+ if node.is_a?(Prism::OptionalKeywordParameterNode)
193
+ optional_keywords[node.name] = Types::Function::Param.new(
194
+ name: nil,
195
+ type: var_type_hash[node.name] || Types::Bases::Any.new(location: nil),
196
+ location: nil
197
+ )
198
+ end
199
+ end
200
+
201
+ if (kw_rest = node.parameters.keyword_rest).is_a?(Prism::KeywordRestParameterNode)
202
+ rest_type =
203
+ if kw_rest.name
204
+ var_type_hash[kw_rest.name]
205
+ end
206
+
207
+ if rest_type
208
+ if rest_type.is_a?(Types::ClassInstance)
209
+ if rest_type.name.name == :Hash && rest_type.name.namespace.empty?
210
+ rest_type = rest_type.args[1]
211
+ end
212
+ end
213
+ end
214
+
215
+ rest_keywords = Types::Function::Param.new(
216
+ name: kw_rest.name,
217
+ type: rest_type || Types::Bases::Any.new(location: nil),
218
+ location: nil)
219
+ end
220
+
221
+ if node.parameters.block
222
+ if (block_name = node.parameters.block.name) && (var_type = var_type_hash[block_name])
223
+ if var_type.is_a?(Types::Optional)
224
+ optional = true
225
+ var_type = var_type.type
226
+ else
227
+ optional = false
228
+ end
229
+
230
+ if var_type.is_a?(Types::Proc)
231
+ block = Types::Block.new(type: var_type.type, self_type: var_type.self_type, required: !optional)
232
+ end
233
+ else
234
+ block = Types::Block.new(
235
+ type: Types::UntypedFunction.new(return_type: Types::Bases::Any.new(location: nil)),
236
+ required: false,
237
+ self_type: nil
238
+ )
239
+ end
240
+ end
241
+ end
242
+
243
+ if annotation = yields_annotation
244
+ case annotation.block_type
245
+ when Types::Block
246
+ block = annotation.block_type
247
+ else
248
+ block = Types::Block.new(
249
+ type: Types::UntypedFunction.new(return_type: Types::Bases::Any.new(location: nil)),
250
+ required: !annotation.optional,
251
+ self_type: nil
252
+ )
253
+ end
254
+ end
255
+
256
+ [
257
+ RBS::AST::Members::MethodDefinition::Overload.new(
258
+ method_type: RBS::MethodType.new(
259
+ type_params: [],
260
+ type: Types::Function.new(
261
+ required_positionals: required_positionals,
262
+ optional_positionals: optional_positionals,
263
+ rest_positionals: rest_positionals,
264
+ trailing_positionals: [],
265
+ required_keywords: required_keywords,
266
+ optional_keywords: optional_keywords,
267
+ rest_keywords: rest_keywords,
268
+ return_type: return_type || Types::Bases::Any.new(location: nil)
269
+ ),
270
+ block: block,
271
+ location: nil
272
+ ),
273
+ annotations: []
274
+ )
275
+ ]
276
+ end
277
+ end
278
+
279
+ def method_annotations #:: Array[RBS::AST::Annotation]
280
+ if comments
281
+ comments.annotations.flat_map do |annotation|
282
+ if annotation.is_a?(AST::Annotations::RBSAnnotation)
283
+ annotation.contents.map do |string|
284
+ RBS::AST::Annotation.new(
285
+ string: string[3...-1] || "",
286
+ location: nil
287
+ )
288
+ end
289
+ else
290
+ []
291
+ end
292
+ end
293
+ else
294
+ []
295
+ end
296
+ end
297
+
298
+ def override_annotation #:: AST::Annotations::Override?
299
+ if comments
300
+ comments.annotations.find do |annotation|
301
+ annotation.is_a?(AST::Annotations::Override)
302
+ end #: AST::Annotations::Override?
303
+ end
304
+ end
305
+
306
+ def yields_annotation #:: AST::Annotations::Yields?
307
+ if comments
308
+ comments.annotations.find do |annotation|
309
+ annotation.is_a?(AST::Annotations::Yields)
310
+ end #: AST::Annotations::Yields?
311
+ end
312
+ end
313
+ end
314
+
315
+ class RubyAlias < RubyBase
316
+ attr_reader :node #:: Prism::AliasMethodNode
317
+ attr_reader :comments #:: AnnotationParser::ParsingResult?
318
+
319
+ # @rbs node: Prism::AliasMethodNode
320
+ # @rbs comments: AnnotationParser::ParsingResult?
321
+ def initialize(node, comments)
322
+ @node = node
323
+ @comments = comments
324
+
325
+ super(node.location)
326
+ end
327
+
328
+ # @rbs returns Symbol -- the name of *old* method
329
+ def old_name
330
+ raise unless node.old_name.is_a?(Prism::SymbolNode)
331
+ value = node.old_name.value or raise
332
+ value.to_sym
333
+ end
334
+
335
+ # @rbs returns Symbol -- the name of *new* method
336
+ def new_name
337
+ raise unless node.new_name.is_a?(Prism::SymbolNode)
338
+ value = node.new_name.value or raise
339
+ value.to_sym
340
+ end
341
+ end
342
+
343
+ class RubyMixin < RubyBase
344
+ # CallNode that calls `include`, `prepend`, and `extend` method
345
+ attr_reader :node #:: Prism::CallNode
346
+
347
+ # Comments attached to the call node
348
+ attr_reader :comments #:: AnnotationParser::ParsingResult?
349
+
350
+ # Possible following type application annotation
351
+ attr_reader :application #:: Annotations::Application?
352
+
353
+ # @rbs node: Prism::CallNode
354
+ # @rbs comments: AnnotationParser::ParsingResult?
355
+ # @rbs application: Annotations::Application?
356
+ # @rbs returns void
357
+ def initialize(node, comments, application)
358
+ super(node.location)
359
+
360
+ @node = node
361
+ @comments = comments
362
+ @application = application
363
+ end
364
+
365
+ # @rbs returns ::RBS::AST::Members::Include
366
+ # | ::RBS::AST::Members::Extend
367
+ # | ::RBS::AST::Members::Prepend
368
+ # | nil
369
+ def rbs
370
+ return unless node.arguments
371
+ return unless node.arguments.arguments.size == 1
372
+
373
+ arg = node.arguments.arguments[0] || raise
374
+ if arg.is_a?(Prism::ConstantReadNode)
375
+ type_name = RBS::TypeName.new(name: arg.name, namespace: RBS::Namespace.empty)
376
+ else
377
+ raise
378
+ end
379
+
380
+ args = [] #: Array[Types::t]
381
+ if application
382
+ if application.types
383
+ args.concat(application.types)
384
+ end
385
+ end
386
+
387
+ case node.name
388
+ when :include
389
+ RBS::AST::Members::Include.new(
390
+ name: type_name,
391
+ args: args,
392
+ annotations: [],
393
+ location: nil,
394
+ comment: nil
395
+ )
396
+ when :extend
397
+ RBS::AST::Members::Extend.new(
398
+ name: type_name,
399
+ args: args,
400
+ annotations: [],
401
+ location: nil,
402
+ comment: nil
403
+ )
404
+ when :prepend
405
+ RBS::AST::Members::Prepend.new(
406
+ name: type_name,
407
+ args: args,
408
+ annotations: [],
409
+ location: nil,
410
+ comment: nil
411
+ )
412
+ end
413
+ end
414
+ end
415
+
416
+ class RubyAttr < RubyBase
417
+ attr_reader :node #:: Prism::CallNode
418
+ attr_reader :comments #:: AnnotationParser::ParsingResult?
419
+ attr_reader :assertion #:: Annotations::Assertion?
420
+
421
+ # @rbs node: Prism::CallNode
422
+ # @rbs comments: AnnotationParser::ParsingResult?
423
+ # @rbs assertion: Annotations::Assertion?
424
+ # @rbs returns void
425
+ def initialize(node, comments, assertion)
426
+ super(node.location)
427
+
428
+ @node = node
429
+ @comments = comments
430
+ @assertion = assertion
431
+ end
432
+
433
+ # @rbs return Array[RBS::AST::Members::AttrReader | RBS::AST::Members::AttrWriter | RBS::AST::Members::AttrAccessor]?
434
+ def rbs
435
+ if comments
436
+ comment = RBS::AST::Comment.new(string: comments.content, location: nil)
437
+ end
438
+
439
+ klass =
440
+ case node.name
441
+ when :attr_reader
442
+ RBS::AST::Members::AttrReader
443
+ when :attr_writer
444
+ RBS::AST::Members::AttrWriter
445
+ when :attr_accessor
446
+ RBS::AST::Members::AttrAccessor
447
+ else
448
+ raise
449
+ end
450
+
451
+ args = [] #: Array[Symbol]
452
+ if node.arguments
453
+ node.arguments.arguments.each do |arg|
454
+ if arg.is_a?(Prism::SymbolNode)
455
+ value = arg.value or raise
456
+ args << value.to_sym
457
+ end
458
+ end
459
+ end
460
+
461
+ unless args.empty?
462
+ args.map do |arg|
463
+ klass.new(
464
+ name: arg,
465
+ type: attribute_type,
466
+ ivar_name: nil,
467
+ kind: :instance,
468
+ annotations: [],
469
+ location: nil,
470
+ comment: comment,
471
+ visibility: nil
472
+ )
473
+ end
474
+ end
475
+ end
476
+
477
+ # Returns the type of the attribute
478
+ #
479
+ # Returns `untyped` when not annotated.
480
+ #
481
+ def attribute_type #:: Types::t
482
+ type = assertion&.type
483
+ raise if type.is_a?(MethodType)
484
+
485
+ type || Types::Bases::Any.new(location: nil)
486
+ end
487
+ end
488
+
489
+ # `private` call without arguments
490
+ #
491
+ class RubyPrivate < RubyBase
492
+ attr_reader :node #:: Prism::CallNode
493
+
494
+ # @rbs node: Prism::CallNode
495
+ def initialize(node) #:: void
496
+ super(node.location)
497
+ @node = node
498
+ end
499
+ end
500
+
501
+ # `public` call without arguments
502
+ #
503
+ class RubyPublic < RubyBase
504
+ attr_reader :node #:: Prism::CallNode
505
+
506
+ # @rbs node: Prism::CallNode
507
+ def initialize(node) #:: void
508
+ super(node.location)
509
+ @node = node
510
+ end
511
+ end
512
+
513
+ class RBSBase < Base
514
+ end
515
+
516
+ class RBSIvar < RBSBase
517
+ attr_reader :annotation #:: Annotations::IvarType
518
+
519
+ attr_reader :comment #:: AnnotationParser::ParsingResult
520
+
521
+ # @rbs comment: AnnotationParser::ParsingResult
522
+ # @rbs annotation: Annotations::IvarType
523
+ def initialize(comment, annotation) #:: void
524
+ @comment = comment
525
+ @annotation = annotation
526
+
527
+ super(comment.comments[0].location)
528
+ end
529
+
530
+ def rbs #:: RBS::AST::Members::InstanceVariable | RBS::AST::Members::ClassInstanceVariable | nil
531
+ if annotation.type
532
+ if annotation.comment
533
+ string = annotation.comment.delete_prefix("--").lstrip
534
+ comment = RBS::AST::Comment.new(string: string, location: nil)
535
+ end
536
+
537
+ if annotation.class_instance
538
+ RBS::AST::Members::ClassInstanceVariable.new(
539
+ name: annotation.name,
540
+ type: annotation.type,
541
+ location: nil,
542
+ comment: comment
543
+ )
544
+ else
545
+ RBS::AST::Members::InstanceVariable.new(
546
+ name: annotation.name,
547
+ type: annotation.type,
548
+ location: nil,
549
+ comment: comment
550
+ )
551
+ end
552
+ end
553
+ end
554
+ end
555
+
556
+ class RBSEmbedded < RBSBase
557
+ attr_reader :annotation #:: Annotations::Embedded
558
+
559
+ attr_reader :comment #:: AnnotationParser::ParsingResult
560
+
561
+ # @rbs comment: AnnotationParser::ParsingResult
562
+ # @rbs annotation: Annotations::Embedded
563
+ def initialize(comment, annotation) #:: void
564
+ @comment = comment
565
+ @annotation = annotation
566
+
567
+ super(comment.comments[0].location)
568
+ end
569
+
570
+ # Returns the array of `RBS::AST` members
571
+ #
572
+ # Returns `RBS::ParsingError` when the `content` has syntax error.
573
+ #
574
+ def members #:: Array[RBS::AST::Members::t | RBS::AST::Declarations::t] | RBS::ParsingError
575
+ source = <<~RBS
576
+ module EmbeddedModuleTest
577
+ #{annotation.content}
578
+ end
579
+ RBS
580
+
581
+ _, dirs, decls = RBS::Parser.parse_signature(source)
582
+
583
+ mod = decls[0]
584
+ mod.is_a?(RBS::AST::Declarations::Module) or raise
585
+
586
+ mod.members.each do |member|
587
+ # Clear `@location` of each member so that new lines are inserted between members.
588
+ # See `RBS::Writer#preserve_empty_line`.
589
+ member.instance_variable_set(:@location, nil)
590
+ end
591
+
592
+ rescue RBS::ParsingError => exn
593
+ exn
594
+ end
595
+ end
596
+ end
597
+ end
598
+ end
599
+ end