rbs-inline 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.
@@ -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