rbi 0.1.13 → 0.2.0

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