Skip to content

Commit 2c0c5a6

Browse files
committed
Implement InlineParser
1 parent 725f093 commit 2c0c5a6

File tree

4 files changed

+346
-22
lines changed

4 files changed

+346
-22
lines changed

lib/rbs/ast/ruby/members.rb

Lines changed: 281 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,211 @@ def initialize(buffer)
1717
class MethodTypeAnnotation
1818
class DocStyle
1919
attr_accessor :return_type_annotation
20+
attr_reader :required_positionals
21+
attr_reader :optional_positionals
22+
attr_accessor :rest_positionals
23+
attr_reader :trailing_positionals
24+
attr_reader :required_keywords
25+
attr_reader :optional_keywords
26+
attr_accessor :rest_keywords
2027

2128
def initialize
2229
@return_type_annotation = nil
30+
@required_positionals = [] #: Array[Annotations::ParamTypeAnnotation?]
31+
@optional_positionals = [] #: Array[Annotations::ParamTypeAnnotation?]
32+
@rest_positionals = nil #: Annotations::ParamTypeAnnotation?
33+
@trailing_positionals = [] #: Array[Annotations::ParamTypeAnnotation?]
34+
@required_keywords = {} #: Hash[Symbol, Annotations::ParamTypeAnnotation]
35+
@optional_keywords = {} #: Hash[Symbol, Annotations::ParamTypeAnnotation]
36+
@rest_keywords = nil #: Annotations::ParamTypeAnnotation?
37+
end
38+
39+
def self.build(param_type_annotations, return_type_annotation, node)
40+
doc = DocStyle.new
41+
doc.return_type_annotation = return_type_annotation
42+
43+
unused = param_type_annotations.dup
44+
45+
if node.parameters
46+
params = node.parameters #: Prism::ParametersNode
47+
48+
params.requireds.each do |param|
49+
if param.is_a?(Prism::RequiredParameterNode)
50+
annotation = unused.find { _1.name_location.source.to_sym == param.name }
51+
if annotation
52+
unused.delete(annotation)
53+
doc.required_positionals << annotation
54+
else
55+
doc.required_positionals << param.name
56+
end
57+
end
58+
end
59+
60+
params.optionals.each do |param|
61+
if param.is_a?(Prism::OptionalParameterNode)
62+
annotation = unused.find { _1.name_location.source.to_sym == param.name }
63+
if annotation
64+
unused.delete(annotation)
65+
doc.optional_positionals << annotation
66+
else
67+
doc.optional_positionals << param.name
68+
end
69+
end
70+
end
71+
72+
if (rest = params.rest) && rest.is_a?(Prism::RestParameterNode) && rest.name
73+
annotation = unused.find { _1.name_location.source.to_sym == rest.name }
74+
if annotation
75+
unused.delete(annotation)
76+
doc.rest_positionals = annotation
77+
else
78+
doc.rest_positionals = rest.name
79+
end
80+
end
81+
82+
params.posts.each do |param|
83+
if param.is_a?(Prism::RequiredParameterNode)
84+
annotation = unused.find { _1.name_location.source.to_sym == param.name }
85+
if annotation
86+
unused.delete(annotation)
87+
doc.trailing_positionals << annotation
88+
else
89+
doc.trailing_positionals << param.name
90+
end
91+
end
92+
end
93+
94+
params.keywords.each do |param|
95+
case param
96+
when Prism::RequiredKeywordParameterNode
97+
annotation = unused.find { _1.name_location.source.to_sym == param.name }
98+
if annotation
99+
unused.delete(annotation)
100+
doc.required_keywords[param.name] = annotation
101+
else
102+
doc.required_keywords[param.name] = param.name
103+
end
104+
when Prism::OptionalKeywordParameterNode
105+
annotation = unused.find { _1.name_location.source.to_sym == param.name }
106+
if annotation
107+
unused.delete(annotation)
108+
doc.optional_keywords[param.name] = annotation
109+
else
110+
doc.optional_keywords[param.name] = param.name
111+
end
112+
end
113+
end
114+
115+
if (kw_rest = params.keyword_rest) && kw_rest.is_a?(Prism::KeywordRestParameterNode) && kw_rest.name
116+
annotation = unused.find { _1.name_location.source.to_sym == kw_rest.name }
117+
if annotation
118+
unused.delete(annotation)
119+
doc.rest_keywords = annotation
120+
else
121+
doc.rest_keywords = kw_rest.name
122+
end
123+
end
124+
end
125+
126+
[doc, unused]
127+
end
128+
129+
def all_param_annotations
130+
annotations = [] #: Array[param_type_annotation | Symbol | nil]
131+
#
132+
required_positionals.each { |a| annotations << a }
133+
optional_positionals.each { |a| annotations << a }
134+
annotations << rest_positionals
135+
trailing_positionals.each { |a| annotations << a }
136+
required_keywords.each_value { |a| annotations << a }
137+
optional_keywords.each_value { |a| annotations << a }
138+
annotations << rest_keywords
139+
140+
annotations
23141
end
24142

25143
def map_type_name(&block)
26144
DocStyle.new.tap do |new|
27145
new.return_type_annotation = return_type_annotation&.map_type_name(&block)
146+
new.required_positionals.replace(
147+
required_positionals.map do |a|
148+
case a
149+
when Annotations::ParamTypeAnnotation
150+
a.map_type_name(&block)
151+
else
152+
a
153+
end
154+
end
155+
)
156+
new.optional_positionals.replace(
157+
optional_positionals.map do |a|
158+
case a
159+
when Annotations::ParamTypeAnnotation
160+
a.map_type_name(&block)
161+
else
162+
a
163+
end
164+
end
165+
)
166+
new.rest_positionals =
167+
case rest_positionals
168+
when Annotations::ParamTypeAnnotation
169+
rest_positionals.map_type_name(&block)
170+
else
171+
rest_positionals
172+
end
173+
new.trailing_positionals.replace(
174+
trailing_positionals.map do |a|
175+
case a
176+
when Annotations::ParamTypeAnnotation
177+
a.map_type_name(&block)
178+
else
179+
a
180+
end
181+
end
182+
)
183+
new.required_keywords.replace(
184+
required_keywords.transform_values do |a|
185+
case a
186+
when Annotations::ParamTypeAnnotation
187+
a.map_type_name(&block)
188+
else
189+
a
190+
end
191+
end
192+
)
193+
new.optional_keywords.replace(
194+
optional_keywords.transform_values do |a|
195+
case a
196+
when Annotations::ParamTypeAnnotation
197+
a.map_type_name(&block)
198+
else
199+
a
200+
end
201+
end
202+
)
203+
new.rest_keywords =
204+
case rest_keywords
205+
when Annotations::ParamTypeAnnotation
206+
rest_keywords.map_type_name(&block)
207+
else
208+
rest_keywords
209+
end
28210
end #: self
29211
end
30212

31213
def type_fingerprint
32-
return_type_annotation&.type_fingerprint
214+
[
215+
return_type_annotation&.type_fingerprint,
216+
all_param_annotations.map do |param|
217+
case param
218+
when Annotations::ParamTypeAnnotation
219+
param.type_fingerprint
220+
else
221+
param
222+
end
223+
end
224+
]
33225
end
34226

35227
def method_type
@@ -43,14 +235,77 @@ def method_type
43235
Types::Bases::Any.new(location: nil)
44236
end
45237

238+
any = -> { Types::Bases::Any.new(location: nil) }
239+
240+
req_pos = required_positionals.map do |a|
241+
case a
242+
when Annotations::ParamTypeAnnotation
243+
Types::Function::Param.new(type: a.param_type, name: a.name_location.source.to_sym)
244+
else
245+
Types::Function::Param.new(type: any.call, name: a)
246+
end
247+
end
248+
opt_pos = optional_positionals.map do |a|
249+
case a
250+
when Annotations::ParamTypeAnnotation
251+
Types::Function::Param.new(type: a.param_type, name: a.name_location.source.to_sym)
252+
else
253+
Types::Function::Param.new(type: any.call, name: a)
254+
end
255+
end
256+
rest_pos =
257+
case rest_positionals
258+
when Annotations::ParamTypeAnnotation
259+
Types::Function::Param.new(type: rest_positionals.param_type, name: rest_positionals.name_location.source.to_sym)
260+
when Symbol
261+
Types::Function::Param.new(type: any.call, name: rest_positionals)
262+
else
263+
nil
264+
end
265+
trail_pos = trailing_positionals.map do |a|
266+
case a
267+
when Annotations::ParamTypeAnnotation
268+
Types::Function::Param.new(type: a.param_type, name: a.name_location.source.to_sym)
269+
else
270+
Types::Function::Param.new(type: any.call, name: a)
271+
end
272+
end
273+
274+
req_kw = required_keywords.transform_values do |a|
275+
case a
276+
when Annotations::ParamTypeAnnotation
277+
Types::Function::Param.new(type: a.param_type, name: nil)
278+
else
279+
Types::Function::Param.new(type: any.call, name: nil)
280+
end
281+
end
282+
opt_kw = optional_keywords.transform_values do |a|
283+
case a
284+
when Annotations::ParamTypeAnnotation
285+
Types::Function::Param.new(type: a.param_type, name: nil)
286+
else
287+
Types::Function::Param.new(type: any.call, name: nil)
288+
end
289+
end
290+
291+
rest_kw =
292+
case rest_keywords
293+
when Annotations::ParamTypeAnnotation
294+
Types::Function::Param.new(type: rest_keywords.param_type, name: nil)
295+
when Symbol
296+
Types::Function::Param.new(type: any.call, name: nil)
297+
else
298+
nil
299+
end
300+
46301
type = Types::Function.new(
47-
required_positionals: [],
48-
optional_positionals: [],
49-
rest_positionals: nil,
50-
trailing_positionals: [],
51-
required_keywords: {},
52-
optional_keywords: {},
53-
rest_keywords: nil,
302+
required_positionals: req_pos,
303+
optional_positionals: opt_pos,
304+
rest_positionals: rest_pos,
305+
trailing_positionals: trail_pos,
306+
required_keywords: req_kw,
307+
optional_keywords: opt_kw,
308+
rest_keywords: rest_kw,
54309
return_type: return_type
55310
)
56311

@@ -82,17 +337,18 @@ def map_type_name(&block)
82337
MethodTypeAnnotation.new(type_annotations: updated_annots) #: self
83338
end
84339

85-
def self.build(leading_block, trailing_block, variables)
340+
def self.build(leading_block, trailing_block, variables, node)
86341
unused_annotations = [] #: Array[Annotations::leading_annotation | CommentBlock::AnnotationSyntaxError]
87342
unused_trailing_annotation = nil #: Annotations::trailing_annotation | CommentBlock::AnnotationSyntaxError | nil
88343

89344
type_annotations = nil #: type_annotations
345+
return_annotation = nil #: Annotations::ReturnTypeAnnotation | Annotations::NodeTypeAssertion | nil
346+
param_annotations = [] #: Array[Annotations::ParamTypeAnnotation]
90347

91348
if trailing_block
92349
case annotation = trailing_block.trailing_annotation(variables)
93350
when Annotations::NodeTypeAssertion
94-
type_annotations = DocStyle.new()
95-
type_annotations.return_type_annotation = annotation
351+
return_annotation = annotation
96352
else
97353
unused_trailing_annotation = annotation
98354
end
@@ -116,25 +372,30 @@ def self.build(leading_block, trailing_block, variables)
116372
end
117373
when Annotations::ReturnTypeAnnotation
118374
unless type_annotations
119-
type_annotations = DocStyle.new()
120-
end
121-
122-
if type_annotations.is_a?(DocStyle)
123-
unless type_annotations.return_type_annotation
124-
type_annotations.return_type_annotation = paragraph
375+
unless return_annotation
376+
return_annotation = paragraph
125377
next
126378
end
127379
end
380+
when Annotations::ParamTypeAnnotation
381+
unless type_annotations
382+
param_annotations << paragraph
383+
next
384+
end
128385
end
129386

130387
unused_annotations << paragraph
131388
end
132389
end
133390

391+
if !type_annotations && (return_annotation || !param_annotations.empty?)
392+
doc_style, unused_params = DocStyle.build(param_annotations, return_annotation, node)
393+
type_annotations = doc_style
394+
unused_annotations.concat(unused_params)
395+
end
396+
134397
[
135-
MethodTypeAnnotation.new(
136-
type_annotations: type_annotations
137-
),
398+
MethodTypeAnnotation.new(type_annotations: type_annotations),
138399
unused_annotations,
139400
unused_trailing_annotation
140401
]

lib/rbs/inline_parser.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ def visit_def_node(node)
196196
trailing_block = comments.trailing_block!(end_loc)
197197
end
198198

199-
method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [])
199+
method_type, leading_unuseds, trailing_unused = AST::Ruby::Members::MethodTypeAnnotation.build(leading_block, trailing_block, [], node)
200200
report_unused_annotation(trailing_unused, *leading_unuseds)
201201

202202
defn = AST::Ruby::Members::DefMember.new(buffer, node.name, node, method_type, leading_block)

0 commit comments

Comments
 (0)