rbi 0.1.13 → 0.2.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,320 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Type
6
+ class Error < RBI::Error; end
7
+
8
+ class << self
9
+ sig { params(string: String).returns(Type) }
10
+ def parse_string(string)
11
+ result = Prism.parse(string)
12
+ unless result.success?
13
+ raise Error, result.errors.map { |e| "#{e.message}." }.join(" ")
14
+ end
15
+
16
+ node = result.value
17
+ raise Error, "Expected a type expression, got `#{node.class}`" unless node.is_a?(Prism::ProgramNode)
18
+ raise Error, "Expected a type expression, got nothing" if node.statements.body.empty?
19
+ raise Error, "Expected a single type expression, got `#{node.slice}`" if node.statements.body.size > 1
20
+
21
+ node = T.must(node.statements.body.first)
22
+ parse_node(node)
23
+ end
24
+
25
+ sig { params(node: Prism::Node).returns(Type) }
26
+ def parse_node(node)
27
+ case node
28
+ when Prism::ConstantReadNode, Prism::ConstantPathNode
29
+ parse_constant(node)
30
+ when Prism::CallNode
31
+ parse_call(node)
32
+ when Prism::ArrayNode
33
+ parse_tuple(node)
34
+ when Prism::HashNode, Prism::KeywordHashNode
35
+ parse_shape(node)
36
+ when Prism::ParenthesesNode
37
+ body = node.body
38
+ raise Error, "Expected exactly 1 child, got 0" unless body.is_a?(Prism::StatementsNode)
39
+
40
+ children = body.body
41
+ raise Error, "Expected exactly 1 child, got #{children.size}" unless children.size == 1
42
+
43
+ parse_node(T.must(children.first))
44
+ else
45
+ raise Error, "Unexpected node `#{node}`"
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ sig { params(node: T.any(Prism::ConstantReadNode, Prism::ConstantPathNode)).returns(Type) }
52
+ def parse_constant(node)
53
+ case node
54
+ when Prism::ConstantReadNode
55
+ # `Foo`
56
+ Type::Simple.new(node.slice)
57
+ when Prism::ConstantPathNode
58
+ if t_boolean?(node)
59
+ # `T::Boolean` or `::T::Boolean`
60
+ Type::Boolean.new
61
+ else
62
+ # `::Foo` or `::Foo::Bar`
63
+ Type::Simple.new(node.slice)
64
+ end
65
+ end
66
+ end
67
+
68
+ sig { params(node: Prism::CallNode).returns(Type) }
69
+ def parse_call(node)
70
+ recv = node.receiver
71
+
72
+ case node.name
73
+ when :void
74
+ # `void`
75
+ check_arguments_exactly!(node, 0)
76
+ return Type::Void.new if recv.nil?
77
+ when :[]
78
+ case recv
79
+ when Prism::ConstantReadNode
80
+ # `Foo[Bar]` or `Foo[Bar, Baz]`
81
+ args = check_arguments_at_least!(node, 1)
82
+ return T.unsafe(Type::Generic).new(recv.slice, *args.map { |arg| parse_node(arg) })
83
+ when Prism::ConstantPathNode
84
+ if t_class?(recv)
85
+ # `T::Class[Foo]` or `::T::Class[Foo]`
86
+ args = check_arguments_exactly!(node, 1)
87
+ return Type::Class.new(parse_node(T.must(args.first)))
88
+ else
89
+ # `::Foo[Bar]` or `::Foo[Bar, Baz]`
90
+ args = check_arguments_at_least!(node, 1)
91
+ return T.unsafe(Type::Generic).new(recv.slice, *args.map { |arg| parse_node(arg) })
92
+ end
93
+ when Prism::CallNode
94
+ # `T.class_of(Foo)[Bar]`
95
+ if t_class_of?(recv)
96
+ type_args = check_arguments_exactly!(recv, 1)
97
+ type = parse_node(T.must(type_args.first))
98
+ raise Error, "Expected a simple type, got `#{type}`" unless type.is_a?(Type::Simple)
99
+
100
+ type_param_args = check_arguments_exactly!(node, 1)
101
+ type_param = parse_node(T.must(type_param_args.first))
102
+ return Type::ClassOf.new(type, type_param)
103
+ end
104
+ end
105
+
106
+ # `something[]`
107
+ raise Error, "Unexpected expression `#{node.slice}`"
108
+ end
109
+
110
+ # `T.proc`
111
+ return parse_proc(node) if t_proc?(node)
112
+
113
+ # `Foo.nilable` or anything called on a constant that is not `::T`
114
+ raise Error, "Unexpected expression `#{node.slice}`" unless t?(recv)
115
+
116
+ case node.name
117
+ when :nilable
118
+ # `T.nilable(Foo)`
119
+ args = check_arguments_exactly!(node, 1)
120
+ type = parse_node(T.must(args.first))
121
+ Type::Nilable.new(type)
122
+ when :anything
123
+ # `T.anything`
124
+ check_arguments_exactly!(node, 0)
125
+ Type::Anything.new
126
+ when :untyped
127
+ # `T.untyped`
128
+ check_arguments_exactly!(node, 0)
129
+ Type::Untyped.new
130
+ when :noreturn
131
+ # `T.noreturn`
132
+ check_arguments_exactly!(node, 0)
133
+ Type::NoReturn.new
134
+ when :self_type
135
+ # `T.self_type`
136
+ check_arguments_exactly!(node, 0)
137
+ Type::SelfType.new
138
+ when :attached_class
139
+ # `T.attached_class`
140
+ check_arguments_exactly!(node, 0)
141
+ Type::AttachedClass.new
142
+ when :class_of
143
+ # `T.class_of(Foo)`
144
+ args = check_arguments_exactly!(node, 1)
145
+ type = parse_node(T.must(args.first))
146
+ raise Error, "Expected a simple type, got `#{type}`" unless type.is_a?(Type::Simple)
147
+
148
+ Type::ClassOf.new(type)
149
+ when :all
150
+ # `T.all(Foo, Bar)`
151
+ args = check_arguments_at_least!(node, 2)
152
+ Type::All.new(args.map { |arg| parse_node(arg) })
153
+ when :any
154
+ # `T.any(Foo, Bar)`
155
+ args = check_arguments_at_least!(node, 2)
156
+ Type::Any.new(args.map { |arg| parse_node(arg) })
157
+ when :type_parameter
158
+ # `T.type_parameter(:T)`
159
+ args = check_arguments_exactly!(node, 1)
160
+ symbol = args.first
161
+ raise Error, "Expected a symbol, got `#{symbol&.slice || "nil"}`" unless symbol.is_a?(Prism::SymbolNode)
162
+
163
+ Type::TypeParameter.new(symbol.slice.delete_prefix(":").to_sym)
164
+ else
165
+ # `T.something`
166
+ raise Error, "Unexpected expression `#{node.slice}`"
167
+ end
168
+ end
169
+
170
+ sig { params(node: Prism::ArrayNode).returns(Type) }
171
+ def parse_tuple(node)
172
+ T.unsafe(Type).tuple(*node.elements.map { |elem| parse_node(elem) })
173
+ end
174
+
175
+ sig { params(node: T.any(Prism::HashNode, Prism::KeywordHashNode)).returns(Type) }
176
+ def parse_shape(node)
177
+ hash = node.elements.map do |elem|
178
+ raise Error, "Expected key-value pair, got `#{elem.slice}`" unless elem.is_a?(Prism::AssocNode)
179
+
180
+ elem_key = elem.key
181
+ key = case elem_key
182
+ when Prism::SymbolNode
183
+ T.must(elem_key.value).to_sym
184
+ when Prism::StringNode
185
+ elem_key.content
186
+ else
187
+ raise Error, "Expected symbol or string, got `#{elem_key.slice}`"
188
+ end
189
+ [key, parse_node(elem.value)]
190
+ end.to_h
191
+ T.unsafe(Type).shape(**hash)
192
+ end
193
+
194
+ sig { params(node: Prism::CallNode).returns(Type) }
195
+ def parse_proc(node)
196
+ calls = call_chain(node).reverse
197
+ calls.pop # remove `T.`
198
+
199
+ raise Error, "Unexpected expression `#{node.slice}`" if calls.empty?
200
+
201
+ type = Type::Proc.new
202
+ calls.each do |call|
203
+ raise Error, "Unexpected expression `#{node.slice}`..." unless call.is_a?(Prism::CallNode)
204
+
205
+ case call.name
206
+ when :params
207
+ args = call.arguments&.arguments || []
208
+ hash = args.first
209
+ raise Error, "Expected hash, got `#{hash.class}`" unless hash.is_a?(Prism::KeywordHashNode)
210
+
211
+ params = hash.elements.map do |elem|
212
+ raise Error, "Expected key-value pair, got `#{elem.slice}`" unless elem.is_a?(Prism::AssocNode)
213
+
214
+ [elem.key.slice.delete_suffix(":").to_sym, parse_node(elem.value)]
215
+ end.to_h
216
+ T.unsafe(type).params(**params)
217
+ when :returns
218
+ args = check_arguments_exactly!(call, 1)
219
+ type.returns(parse_node(T.must(args.first)))
220
+ when :void
221
+ type.void
222
+ when :proc
223
+ return type
224
+ when :bind
225
+ args = check_arguments_exactly!(call, 1)
226
+ type.bind(parse_node(T.must(args.first)))
227
+ else
228
+ raise Error, "Unexpected expression `#{node.slice}`"
229
+ end
230
+ end
231
+ type
232
+ end
233
+
234
+ sig { params(node: Prism::CallNode, count: Integer).returns(T::Array[Prism::Node]) }
235
+ def check_arguments_exactly!(node, count)
236
+ args = node.arguments&.arguments || []
237
+ unless args.size == count
238
+ if count == 0
239
+ raise Error, "Expected no arguments, got #{args.size}"
240
+ elsif count == 1
241
+ raise Error, "Expected exactly 1 argument, got #{args.size}"
242
+ else
243
+ raise Error, "Expected exactly #{count} arguments, got #{args.size}"
244
+ end
245
+ end
246
+ args
247
+ end
248
+
249
+ sig { params(node: Prism::CallNode, count: Integer).returns(T::Array[Prism::Node]) }
250
+ def check_arguments_at_least!(node, count)
251
+ args = node.arguments&.arguments || []
252
+ if args.size < count
253
+ if count == 1
254
+ raise Error, "Expected at least 1 argument, got #{args.size}"
255
+ else
256
+ raise Error, "Expected at least #{count} arguments, got #{args.size}"
257
+ end
258
+ end
259
+ args
260
+ end
261
+
262
+ sig { params(node: Prism::CallNode).returns(T::Array[Prism::Node]) }
263
+ def call_chain(node)
264
+ call_chain = T.let([node], T::Array[Prism::Node])
265
+ receiver = T.let(node.receiver, T.nilable(Prism::Node))
266
+ while receiver
267
+ call_chain.prepend(receiver)
268
+ break unless receiver.is_a?(Prism::CallNode)
269
+
270
+ receiver = receiver.receiver
271
+ end
272
+ call_chain
273
+ end
274
+
275
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
276
+ def t?(node)
277
+ case node
278
+ when Prism::ConstantReadNode
279
+ return true if node.name == :T
280
+ when Prism::ConstantPathNode
281
+ return true if node.parent.nil? && node.name == :T
282
+ end
283
+
284
+ false
285
+ end
286
+
287
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
288
+ def t_boolean?(node)
289
+ return false unless node.is_a?(Prism::ConstantPathNode)
290
+
291
+ t?(node.parent) && node.name == :Boolean
292
+ end
293
+
294
+ sig { params(node: Prism::ConstantPathNode).returns(T::Boolean) }
295
+ def t_class?(node)
296
+ t?(node.parent) && node.name == :Class
297
+ end
298
+
299
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
300
+ def t_class_of?(node)
301
+ return false unless node.is_a?(Prism::CallNode)
302
+
303
+ t?(node.receiver) && node.name == :class_of
304
+ end
305
+
306
+ sig { params(node: Prism::CallNode).returns(T::Boolean) }
307
+ def t_proc?(node)
308
+ chain = call_chain(node)
309
+ return false if chain.size < 2
310
+ return false unless t?(chain[0])
311
+
312
+ second = chain[1]
313
+ return false unless second.is_a?(Prism::CallNode)
314
+ return false unless second.name == :proc
315
+
316
+ true
317
+ end
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,112 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Type
6
+ class Visitor
7
+ extend T::Sig
8
+
9
+ class Error < RBI::Error; end
10
+
11
+ sig { params(node: Type).void }
12
+ def visit(node)
13
+ case node
14
+ when Type::Simple
15
+ visit_simple(node)
16
+ when Type::Void
17
+ visit_void(node)
18
+ when Type::Boolean
19
+ visit_boolean(node)
20
+ when Type::Nilable
21
+ visit_nilable(node)
22
+ when Type::Untyped
23
+ visit_untyped(node)
24
+ when Type::Generic
25
+ visit_generic(node)
26
+ when Type::Anything
27
+ visit_anything(node)
28
+ when Type::NoReturn
29
+ visit_no_return(node)
30
+ when Type::SelfType
31
+ visit_self_type(node)
32
+ when Type::AttachedClass
33
+ visit_attached_class(node)
34
+ when Type::ClassOf
35
+ visit_class_of(node)
36
+ when Type::All
37
+ visit_all(node)
38
+ when Type::Any
39
+ visit_any(node)
40
+ when Type::Tuple
41
+ visit_tuple(node)
42
+ when Type::Shape
43
+ visit_shape(node)
44
+ when Type::Proc
45
+ visit_proc(node)
46
+ when Type::TypeParameter
47
+ visit_type_parameter(node)
48
+ when Type::Class
49
+ visit_class(node)
50
+ else
51
+ raise Error, "Unhandled node: #{node.class}"
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ sig { params(type: Type::All).void }
58
+ def visit_all(type); end
59
+
60
+ sig { params(type: Type::Any).void }
61
+ def visit_any(type); end
62
+
63
+ sig { params(type: Type::Anything).void }
64
+ def visit_anything(type); end
65
+
66
+ sig { params(type: Type::AttachedClass).void }
67
+ def visit_attached_class(type); end
68
+
69
+ sig { params(type: Type::Boolean).void }
70
+ def visit_boolean(type); end
71
+
72
+ sig { params(type: Type::Class).void }
73
+ def visit_class(type); end
74
+
75
+ sig { params(type: Type::ClassOf).void }
76
+ def visit_class_of(type); end
77
+
78
+ sig { params(type: Type::Generic).void }
79
+ def visit_generic(type); end
80
+
81
+ sig { params(type: Type::Nilable).void }
82
+ def visit_nilable(type); end
83
+
84
+ sig { params(type: Type::Simple).void }
85
+ def visit_simple(type); end
86
+
87
+ sig { params(type: Type::NoReturn).void }
88
+ def visit_no_return(type); end
89
+
90
+ sig { params(type: Type::Proc).void }
91
+ def visit_proc(type); end
92
+
93
+ sig { params(type: Type::SelfType).void }
94
+ def visit_self_type(type); end
95
+
96
+ sig { params(type: Type::Void).void }
97
+ def visit_void(type); end
98
+
99
+ sig { params(type: Type::Shape).void }
100
+ def visit_shape(type); end
101
+
102
+ sig { params(type: Type::Tuple).void }
103
+ def visit_tuple(type); end
104
+
105
+ sig { params(type: Type::TypeParameter).void }
106
+ def visit_type_parameter(type); end
107
+
108
+ sig { params(type: Type::Untyped).void }
109
+ def visit_untyped(type); end
110
+ end
111
+ end
112
+ end
data/lib/rbi/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RBI
5
- VERSION = "0.1.13"
5
+ VERSION = "0.2.0"
6
6
  end
data/lib/rbi/visitor.rb CHANGED
@@ -2,18 +2,244 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RBI
5
+ class VisitorError < Error; end
6
+
5
7
  class Visitor
6
8
  extend T::Helpers
7
9
  extend T::Sig
8
10
 
9
11
  abstract!
10
12
 
11
- sig { abstract.params(node: T.nilable(Node)).void }
12
- def visit(node); end
13
+ sig { params(node: T.nilable(Node)).void }
14
+ def visit(node)
15
+ return unless node
16
+
17
+ case node
18
+ when BlankLine
19
+ visit_blank_line(node)
20
+ when Comment
21
+ visit_comment(node)
22
+ when TEnum
23
+ visit_tenum(node)
24
+ when TStruct
25
+ visit_tstruct(node)
26
+ when Module
27
+ visit_module(node)
28
+ when Class
29
+ visit_class(node)
30
+ when SingletonClass
31
+ visit_singleton_class(node)
32
+ when Struct
33
+ visit_struct(node)
34
+ when Group
35
+ visit_group(node)
36
+ when VisibilityGroup
37
+ visit_visibility_group(node)
38
+ when ConflictTree
39
+ visit_conflict_tree(node)
40
+ when ScopeConflict
41
+ visit_scope_conflict(node)
42
+ when TEnumBlock
43
+ visit_tenum_block(node)
44
+ when Tree
45
+ visit_tree(node)
46
+ when Const
47
+ visit_const(node)
48
+ when AttrAccessor
49
+ visit_attr_accessor(node)
50
+ when AttrReader
51
+ visit_attr_reader(node)
52
+ when AttrWriter
53
+ visit_attr_writer(node)
54
+ when Method
55
+ visit_method(node)
56
+ when ReqParam
57
+ visit_req_param(node)
58
+ when OptParam
59
+ visit_opt_param(node)
60
+ when RestParam
61
+ visit_rest_param(node)
62
+ when KwParam
63
+ visit_kw_param(node)
64
+ when KwOptParam
65
+ visit_kw_opt_param(node)
66
+ when KwRestParam
67
+ visit_kw_rest_param(node)
68
+ when BlockParam
69
+ visit_block_param(node)
70
+ when Include
71
+ visit_include(node)
72
+ when Extend
73
+ visit_extend(node)
74
+ when Public
75
+ visit_public(node)
76
+ when Protected
77
+ visit_protected(node)
78
+ when Private
79
+ visit_private(node)
80
+ when Send
81
+ visit_send(node)
82
+ when KwArg
83
+ visit_kw_arg(node)
84
+ when Arg
85
+ visit_arg(node)
86
+ when Sig
87
+ visit_sig(node)
88
+ when SigParam
89
+ visit_sig_param(node)
90
+ when TStructConst
91
+ visit_tstruct_const(node)
92
+ when TStructProp
93
+ visit_tstruct_prop(node)
94
+ when Helper
95
+ visit_helper(node)
96
+ when TypeMember
97
+ visit_type_member(node)
98
+ when MixesInClassMethods
99
+ visit_mixes_in_class_methods(node)
100
+ when RequiresAncestor
101
+ visit_requires_ancestor(node)
102
+ else
103
+ raise VisitorError, "Unhandled node: #{node.class}"
104
+ end
105
+ end
13
106
 
14
107
  sig { params(nodes: T::Array[Node]).void }
15
108
  def visit_all(nodes)
16
109
  nodes.each { |node| visit(node) }
17
110
  end
111
+
112
+ sig { params(file: File).void }
113
+ def visit_file(file)
114
+ visit(file.root)
115
+ end
116
+
117
+ private
118
+
119
+ sig { params(node: Comment).void }
120
+ def visit_comment(node); end
121
+
122
+ sig { params(node: BlankLine).void }
123
+ def visit_blank_line(node); end
124
+
125
+ sig { params(node: Module).void }
126
+ def visit_module(node); end
127
+
128
+ sig { params(node: Class).void }
129
+ def visit_class(node); end
130
+
131
+ sig { params(node: SingletonClass).void }
132
+ def visit_singleton_class(node); end
133
+
134
+ sig { params(node: Struct).void }
135
+ def visit_struct(node); end
136
+
137
+ sig { params(node: Tree).void }
138
+ def visit_tree(node); end
139
+
140
+ sig { params(node: Const).void }
141
+ def visit_const(node); end
142
+
143
+ sig { params(node: AttrAccessor).void }
144
+ def visit_attr_accessor(node); end
145
+
146
+ sig { params(node: AttrReader).void }
147
+ def visit_attr_reader(node); end
148
+
149
+ sig { params(node: AttrWriter).void }
150
+ def visit_attr_writer(node); end
151
+
152
+ sig { params(node: Method).void }
153
+ def visit_method(node); end
154
+
155
+ sig { params(node: ReqParam).void }
156
+ def visit_req_param(node); end
157
+
158
+ sig { params(node: OptParam).void }
159
+ def visit_opt_param(node); end
160
+
161
+ sig { params(node: RestParam).void }
162
+ def visit_rest_param(node); end
163
+
164
+ sig { params(node: KwParam).void }
165
+ def visit_kw_param(node); end
166
+
167
+ sig { params(node: KwOptParam).void }
168
+ def visit_kw_opt_param(node); end
169
+
170
+ sig { params(node: KwRestParam).void }
171
+ def visit_kw_rest_param(node); end
172
+
173
+ sig { params(node: BlockParam).void }
174
+ def visit_block_param(node); end
175
+
176
+ sig { params(node: Include).void }
177
+ def visit_include(node); end
178
+
179
+ sig { params(node: Extend).void }
180
+ def visit_extend(node); end
181
+
182
+ sig { params(node: Public).void }
183
+ def visit_public(node); end
184
+
185
+ sig { params(node: Protected).void }
186
+ def visit_protected(node); end
187
+
188
+ sig { params(node: Private).void }
189
+ def visit_private(node); end
190
+
191
+ sig { params(node: Send).void }
192
+ def visit_send(node); end
193
+
194
+ sig { params(node: Arg).void }
195
+ def visit_arg(node); end
196
+
197
+ sig { params(node: KwArg).void }
198
+ def visit_kw_arg(node); end
199
+
200
+ sig { params(node: Sig).void }
201
+ def visit_sig(node); end
202
+
203
+ sig { params(node: SigParam).void }
204
+ def visit_sig_param(node); end
205
+
206
+ sig { params(node: TStruct).void }
207
+ def visit_tstruct(node); end
208
+
209
+ sig { params(node: TStructConst).void }
210
+ def visit_tstruct_const(node); end
211
+
212
+ sig { params(node: TStructProp).void }
213
+ def visit_tstruct_prop(node); end
214
+
215
+ sig { params(node: TEnum).void }
216
+ def visit_tenum(node); end
217
+
218
+ sig { params(node: TEnumBlock).void }
219
+ def visit_tenum_block(node); end
220
+
221
+ sig { params(node: Helper).void }
222
+ def visit_helper(node); end
223
+
224
+ sig { params(node: TypeMember).void }
225
+ def visit_type_member(node); end
226
+
227
+ sig { params(node: MixesInClassMethods).void }
228
+ def visit_mixes_in_class_methods(node); end
229
+
230
+ sig { params(node: RequiresAncestor).void }
231
+ def visit_requires_ancestor(node); end
232
+
233
+ sig { params(node: Group).void }
234
+ def visit_group(node); end
235
+
236
+ sig { params(node: VisibilityGroup).void }
237
+ def visit_visibility_group(node); end
238
+
239
+ sig { params(node: ConflictTree).void }
240
+ def visit_conflict_tree(node); end
241
+
242
+ sig { params(node: ScopeConflict).void }
243
+ def visit_scope_conflict(node); end
18
244
  end
19
245
  end