rbs-inline 0.3.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -7
- data/Rakefile +12 -0
- data/lib/rbs/inline/annotation_parser/tokenizer.rb +361 -0
- data/lib/rbs/inline/annotation_parser.rb +548 -326
- data/lib/rbs/inline/ast/annotations.rb +446 -136
- data/lib/rbs/inline/ast/comment_lines.rb +32 -18
- data/lib/rbs/inline/ast/declarations.rb +67 -28
- data/lib/rbs/inline/ast/members.rb +137 -140
- data/lib/rbs/inline/ast/tree.rb +104 -5
- data/lib/rbs/inline/cli.rb +12 -12
- data/lib/rbs/inline/node_utils.rb +4 -0
- data/lib/rbs/inline/parser.rb +140 -59
- data/lib/rbs/inline/version.rb +1 -1
- data/lib/rbs/inline/writer.rb +243 -94
- data/lib/rbs/inline.rb +4 -0
- data/rbs_collection.lock.yaml +3 -7
- data/rbs_collection.yaml +2 -0
- data/sig/generated/rbs/inline/annotation_parser/tokenizer.rbs +221 -0
- data/sig/generated/rbs/inline/annotation_parser.rbs +148 -92
- data/sig/generated/rbs/inline/ast/annotations.rbs +142 -36
- data/sig/generated/rbs/inline/ast/comment_lines.rbs +35 -0
- data/sig/generated/rbs/inline/ast/declarations.rbs +29 -10
- data/sig/generated/rbs/inline/ast/members.rbs +33 -24
- data/sig/generated/rbs/inline/ast/tree.rbs +132 -0
- data/sig/generated/rbs/inline/cli.rbs +3 -3
- data/sig/generated/rbs/inline/node_utils.rbs +11 -0
- data/sig/generated/rbs/inline/parser.rbs +38 -18
- data/sig/generated/rbs/inline/version.rbs +7 -0
- data/sig/generated/rbs/inline/writer.rbs +104 -0
- data/sig/generated/rbs/inline.rbs +7 -0
- metadata +14 -14
- data/sig/rbs/inline/annotation_parser.rbs +0 -0
- data/sig/rbs/inline/ast/comment_lines.rbs +0 -27
- data/sig/rbs/inline/ast/tree.rbs +0 -98
- data/sig/rbs/inline/node_utils.rbs +0 -7
- data/sig/rbs/inline/writer.rbs +0 -27
- data/sig/rbs/inline.rbs +0 -41
- data/yard-samples/hello.rb +0 -6
- data/yard-samples/sample1.rb +0 -26
@@ -3,13 +3,43 @@
|
|
3
3
|
module RBS
|
4
4
|
module Inline
|
5
5
|
class AnnotationParser
|
6
|
+
# ParsingResut groups consecutive comments, which may contain several annotations
|
7
|
+
#
|
8
|
+
# *Consecutive comments* are comments are defined in below.
|
9
|
+
# They are basically comments that follows from the previous line, but there are some more requirements.
|
10
|
+
#
|
11
|
+
# ```ruby
|
12
|
+
# # Line 1
|
13
|
+
# # Line 2 #=> Line 1 and Line 2 are consecutive
|
14
|
+
#
|
15
|
+
# # Line 3
|
16
|
+
# # Line4 #=> Line 3 and Line 4 are not consecutive, because the starting column are different
|
17
|
+
#
|
18
|
+
# # Line 5
|
19
|
+
# foo() # Line 6 #=> Line 5 and Line 6 are not consecutive, because Line 6 has leading code
|
20
|
+
# ```
|
21
|
+
#
|
6
22
|
class ParsingResult
|
7
|
-
attr_reader :comments
|
8
|
-
attr_reader :annotations
|
9
|
-
attr_reader :first_comment_offset
|
23
|
+
attr_reader :comments #: Array[Prism::Comment]
|
24
|
+
attr_reader :annotations #: Array[AST::Annotations::t | AST::CommentLines]
|
25
|
+
attr_reader :first_comment_offset #: Integer
|
26
|
+
|
27
|
+
#: () { (AST::Annotations::t) -> void } -> void
|
28
|
+
#: () -> Enumerator[AST::Annotations::t, void]
|
29
|
+
def each_annotation(&block)
|
30
|
+
if block
|
31
|
+
annotations.each do |annot|
|
32
|
+
if annot.is_a?(AST::Annotations::Base)
|
33
|
+
yield annot
|
34
|
+
end
|
35
|
+
end
|
36
|
+
else
|
37
|
+
enum_for :each_annotation
|
38
|
+
end
|
39
|
+
end
|
10
40
|
|
11
41
|
# @rbs first_comment: Prism::Comment
|
12
|
-
def initialize(first_comment)
|
42
|
+
def initialize(first_comment) #: void
|
13
43
|
@comments = [first_comment]
|
14
44
|
@annotations = []
|
15
45
|
content = first_comment.location.slice
|
@@ -17,7 +47,7 @@ module RBS
|
|
17
47
|
@first_comment_offset = index
|
18
48
|
end
|
19
49
|
|
20
|
-
# @rbs
|
50
|
+
# @rbs return: Range[Integer]
|
21
51
|
def line_range
|
22
52
|
first = comments.first or raise
|
23
53
|
last = comments.last or raise
|
@@ -25,13 +55,13 @@ module RBS
|
|
25
55
|
first.location.start_line .. last.location.end_line
|
26
56
|
end
|
27
57
|
|
28
|
-
# @rbs
|
58
|
+
# @rbs return: Prism::Comment
|
29
59
|
def last_comment
|
30
60
|
comments.last or raise
|
31
61
|
end
|
32
62
|
|
33
63
|
# @rbs comment: Prism::Comment
|
34
|
-
# @rbs
|
64
|
+
# @rbs return: self?
|
35
65
|
def add_comment(comment)
|
36
66
|
if last_comment.location.end_line + 1 == comment.location.start_line
|
37
67
|
if last_comment.location.start_column == comment.location.start_column
|
@@ -46,40 +76,46 @@ module RBS
|
|
46
76
|
end
|
47
77
|
end
|
48
78
|
|
49
|
-
# @rbs
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
79
|
+
# @rbs trim: bool -- `true` to trim the leading whitespaces
|
80
|
+
def content(trim: false) #: String
|
81
|
+
if trim
|
82
|
+
leading_spaces = lines[0][/\A\s*/]
|
83
|
+
offset = leading_spaces ? leading_spaces.length : 0
|
84
|
+
|
85
|
+
lines.map do |line|
|
86
|
+
prefix = line[0..offset] || ""
|
87
|
+
if prefix.strip.empty?
|
88
|
+
line[offset..]
|
89
|
+
else
|
90
|
+
line.lstrip
|
91
|
+
end
|
92
|
+
end.join("\n")
|
93
|
+
else
|
94
|
+
lines.join("\n")
|
60
95
|
end
|
61
96
|
end
|
62
97
|
|
63
|
-
|
64
|
-
|
65
|
-
lines.map(&:first).join("\n")
|
98
|
+
def lines #: Array[String]
|
99
|
+
comments.map { _1.location.slice[1...] || "" }
|
66
100
|
end
|
67
101
|
end
|
68
102
|
|
69
|
-
|
103
|
+
include Tokens
|
104
|
+
|
105
|
+
attr_reader :input #: Array[Prism::Comment]
|
70
106
|
|
71
107
|
# @rbs input: Array[Prism::Comment]
|
72
|
-
def initialize(input)
|
108
|
+
def initialize(input) #: void
|
73
109
|
@input = input
|
74
110
|
end
|
75
111
|
|
76
112
|
# @rbs input: Array[Prism::Comment]
|
77
|
-
# @rbs
|
113
|
+
# @rbs return: Array[ParsingResult]
|
78
114
|
def self.parse(input)
|
79
115
|
new(input).parse
|
80
116
|
end
|
81
117
|
|
82
|
-
# @rbs
|
118
|
+
# @rbs return: Array[ParsingResult]
|
83
119
|
def parse
|
84
120
|
results = [] #: Array[ParsingResult]
|
85
121
|
|
@@ -97,9 +133,13 @@ module RBS
|
|
97
133
|
end
|
98
134
|
|
99
135
|
results.each do |result|
|
100
|
-
each_annotation_paragraph(result) do |comments|
|
101
|
-
|
136
|
+
each_annotation_paragraph(result) do |comments, annotation|
|
137
|
+
lines = AST::CommentLines.new(comments)
|
138
|
+
|
139
|
+
if annotation && annot = parse_annotation(lines)
|
102
140
|
result.annotations << annot
|
141
|
+
else
|
142
|
+
result.annotations << lines
|
103
143
|
end
|
104
144
|
end
|
105
145
|
end
|
@@ -109,308 +149,311 @@ module RBS
|
|
109
149
|
|
110
150
|
private
|
111
151
|
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
next_line, next_comment = lines.first
|
123
|
-
|
124
|
-
possible_annotation = false
|
125
|
-
possible_annotation ||= line.start_with?('@rbs', '@rbs!')
|
126
|
-
possible_annotation ||= comment.location.slice.start_with?("#::", "#[") # No leading whitespace is allowed
|
127
|
-
|
128
|
-
if possible_annotation
|
129
|
-
line_offset = line.index(/\S/) || raise
|
130
|
-
|
131
|
-
comments = [comment]
|
132
|
-
|
133
|
-
while true
|
134
|
-
break unless next_line && next_comment
|
135
|
-
next_offset = next_line.index(/\S/) || 0
|
136
|
-
break unless next_offset > line_offset
|
137
|
-
|
138
|
-
comments << next_comment
|
139
|
-
lines.shift
|
152
|
+
# Test if the comment is an annotation comment
|
153
|
+
#
|
154
|
+
# - Returns `nil` if the comment is not an annotation.
|
155
|
+
# - Returns `true` if the comment is `#:` or `#[` annotation. (Offset is `1`)
|
156
|
+
# - Returns Integer if the comment is `#@rbs` annotation. (Offset is the number of leading spaces including `#`)
|
157
|
+
#
|
158
|
+
#: (Prism::Comment) -> (Integer | true | nil)
|
159
|
+
def annotation_comment?(comment)
|
160
|
+
line = comment.location.slice
|
140
161
|
|
141
|
-
|
142
|
-
|
162
|
+
# No leading whitespace is allowed
|
163
|
+
return true if line.start_with?("#:")
|
164
|
+
return true if line.start_with?("#[")
|
143
165
|
|
144
|
-
|
145
|
-
|
166
|
+
if match = line.match(/\A#(\s*)@rbs(\b|!)/)
|
167
|
+
leading_spaces = match[1] or raise
|
168
|
+
leading_spaces.size + 1
|
146
169
|
end
|
147
170
|
end
|
148
171
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
"*" => :kSTAR,
|
178
|
-
"--" => :kMINUS2,
|
179
|
-
"<" => :kLT,
|
180
|
-
"." => :kDOT,
|
181
|
-
} #:: Hash[String, Symbol]
|
182
|
-
PUNCTS_RE = Regexp.union(PUNCTS.keys) #:: Regexp
|
183
|
-
|
184
|
-
# @rbs scanner: StringScanner
|
185
|
-
# @rbs returns void
|
186
|
-
def initialize(scanner)
|
187
|
-
@scanner = scanner
|
188
|
-
@current_token = nil
|
189
|
-
end
|
190
|
-
|
191
|
-
# @rbs tree: AST::Tree
|
192
|
-
# @rbs returns token?
|
193
|
-
def advance(tree)
|
194
|
-
last = current_token
|
172
|
+
# Split lines of comments in `result` into paragraphs
|
173
|
+
#
|
174
|
+
# A paragraph consists of:
|
175
|
+
#
|
176
|
+
# * An annotation syntax constructs -- starting with `@rbs` or `::`, or
|
177
|
+
# * A lines something else
|
178
|
+
#
|
179
|
+
# Yields an array of comments, and a boolean indicating if the comments may be an annotation.
|
180
|
+
#
|
181
|
+
#: (ParsingResult) { (Array[Prism::Comment], bool is_annotation) -> void } -> void
|
182
|
+
def each_annotation_paragraph(result, &block)
|
183
|
+
yield_paragraph([], result.comments.dup, &block)
|
184
|
+
end
|
185
|
+
|
186
|
+
# The first annotation line is already detected and consumed.
|
187
|
+
# The annotation comment is already in `comments`.
|
188
|
+
#
|
189
|
+
# @rbs comments: Array[Prism::Comment] -- Annotation comments
|
190
|
+
# @rbs lines: Array[Prism::Comment] -- Lines to be consumed
|
191
|
+
# @rbs offset: Integer -- Offset of the first character of the first annotation comment from the `#` (>= 1)
|
192
|
+
# @rbs allow_empty_lines: bool -- `true` if empty line is allowed inside the annotation comments
|
193
|
+
# @rbs &block: (Array[Prism::Comment], bool is_annotation) -> void
|
194
|
+
# @rbs return: void
|
195
|
+
def yield_annotation(comments, lines, offset, allow_empty_lines:, &block)
|
196
|
+
first_comment = lines.first
|
197
|
+
|
198
|
+
if first_comment
|
199
|
+
nonspace_index = first_comment.location.slice.index(/\S/, 1)
|
195
200
|
|
196
201
|
case
|
197
|
-
when
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
when
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
@current_token = [:tIFIDENT, s]
|
212
|
-
when s = scanner.scan(/[a-z]\w*/)
|
213
|
-
@current_token = [:tLVAR, s]
|
214
|
-
when s = scanner.scan(/![a-z]\w*/)
|
215
|
-
@current_token = [:tELVAR, s]
|
216
|
-
when s = scanner.scan(/@\w+/)
|
217
|
-
@current_token = [:tATIDENT, s]
|
218
|
-
when s = scanner.scan(/%a\{[^}]+\}/)
|
219
|
-
@current_token = [:tANNOTATION, s]
|
220
|
-
when s = scanner.scan(/%a\[[^\]]+\]/)
|
221
|
-
@current_token = [:tANNOTATION, s]
|
222
|
-
when s = scanner.scan(/%a\([^)]+\)/)
|
223
|
-
@current_token = [:tANNOTATION, s]
|
202
|
+
when nonspace_index.nil?
|
203
|
+
if allow_empty_lines
|
204
|
+
lines.shift
|
205
|
+
yield_empty_annotation(comments, [first_comment], lines, offset, &block)
|
206
|
+
else
|
207
|
+
# Starting next paragraph (or annotation)
|
208
|
+
yield(comments, true)
|
209
|
+
yield_paragraph([], lines, &block)
|
210
|
+
end
|
211
|
+
when nonspace_index > offset
|
212
|
+
# Continuation of the annotation
|
213
|
+
lines.shift
|
214
|
+
comments.push(first_comment)
|
215
|
+
yield_annotation(comments, lines, offset, allow_empty_lines: allow_empty_lines, &block)
|
224
216
|
else
|
225
|
-
|
217
|
+
# Starting next paragraph (or annotation)
|
218
|
+
yield(comments, true)
|
219
|
+
yield_paragraph([], lines, &block)
|
226
220
|
end
|
227
|
-
|
228
|
-
|
221
|
+
else
|
222
|
+
yield(comments, true)
|
229
223
|
end
|
224
|
+
end
|
230
225
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
226
|
+
# The first line is NOT consumed.
|
227
|
+
#
|
228
|
+
# The `comments` may be empty.
|
229
|
+
#
|
230
|
+
# @rbs comments: Array[Prism::Comment] -- Leading comments
|
231
|
+
# @rbs lines: Array[Prism::Comment] -- Lines to be consumed
|
232
|
+
# @rbs &block: (Array[Prism::Comment], bool is_annotation) -> void
|
233
|
+
# @rbs return: void
|
234
|
+
def yield_paragraph(comments, lines, &block)
|
235
|
+
while first_comment = lines.first
|
236
|
+
if offset = annotation_comment?(first_comment)
|
237
|
+
yield comments, false unless comments.empty?
|
238
|
+
lines.shift
|
239
|
+
case offset
|
240
|
+
when Integer
|
241
|
+
yield_annotation([first_comment], lines, offset, allow_empty_lines: true, &block)
|
242
|
+
when true
|
243
|
+
yield_annotation([first_comment], lines, 1, allow_empty_lines: false, &block)
|
244
|
+
end
|
245
|
+
return
|
239
246
|
else
|
240
|
-
|
247
|
+
lines.shift
|
248
|
+
comments.push(first_comment)
|
241
249
|
end
|
242
250
|
end
|
243
251
|
|
244
|
-
|
245
|
-
|
246
|
-
# @rbs type: Array[Symbol]
|
247
|
-
# @rbs tree: AST::Tree
|
248
|
-
# @rbs returns void
|
249
|
-
def consume_token!(*types, tree:)
|
250
|
-
type!(*types)
|
251
|
-
tree << advance(tree)
|
252
|
-
end
|
253
|
-
|
254
|
-
# Test if current token has specified `type`
|
255
|
-
#
|
256
|
-
# @rbs type: Array[Symbol]
|
257
|
-
# @rbs returns bool
|
258
|
-
def type?(*type)
|
259
|
-
type.any? { current_token && current_token[0] == _1 }
|
260
|
-
end
|
261
|
-
|
262
|
-
# Ensure current token is one of the specified in types
|
263
|
-
#
|
264
|
-
# @rbs types: Array[Symbol]
|
265
|
-
# @rbs returns void
|
266
|
-
def type!(*types)
|
267
|
-
raise "Unexpected token: #{current_token&.[](0)}, where expected token: #{types.join(",")}" unless type?(*types)
|
268
|
-
end
|
252
|
+
yield comments, false unless comments.empty?
|
253
|
+
end
|
269
254
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
255
|
+
# Consumes empty lines between annotation lines
|
256
|
+
#
|
257
|
+
# An empty line is already detected and consumed.
|
258
|
+
# The line is already removed from `lines` and put in `empty_comments`.
|
259
|
+
#
|
260
|
+
# Note that the arguments, `comments`, `empty_comments`, and `lines` are modified in place.
|
261
|
+
#
|
262
|
+
# @rbs comments: Array[Prism::Comment] -- Non empty annotation comments
|
263
|
+
# @rbs empty_comments: Array[Prism::Comment] -- Empty comments that may be part of the annotation
|
264
|
+
# @rbs lines: Array[Prism::Comment] -- Lines
|
265
|
+
# @rbs offset: Integer -- Offset of the first character of the annotation
|
266
|
+
# @rbs &block: (Array[Prism::Comment], bool is_annotation) -> void
|
267
|
+
# @rbs return: void
|
268
|
+
def yield_empty_annotation(comments, empty_comments, lines, offset, &block)
|
269
|
+
first_comment = lines.first
|
270
|
+
|
271
|
+
if first_comment
|
272
|
+
nonspace_index = first_comment.location.slice.index(/\S/, 1)
|
277
273
|
|
278
|
-
|
279
|
-
|
280
|
-
|
274
|
+
case
|
275
|
+
when nonspace_index.nil?
|
276
|
+
# Empty line, possibly continues the annotation
|
277
|
+
lines.shift
|
278
|
+
empty_comments << first_comment
|
279
|
+
yield_empty_annotation(comments, empty_comments, lines, offset, &block)
|
280
|
+
when nonspace_index > offset
|
281
|
+
# Continuation of the annotation
|
282
|
+
lines.shift
|
283
|
+
comments.concat(empty_comments)
|
284
|
+
comments.push(first_comment)
|
285
|
+
yield_annotation(comments, lines, offset, allow_empty_lines: true, &block)
|
281
286
|
else
|
282
|
-
|
283
|
-
|
284
|
-
scanner.terminate
|
285
|
-
s
|
287
|
+
yield comments, true
|
288
|
+
yield_paragraph(empty_comments, lines, &block)
|
286
289
|
end
|
290
|
+
else
|
291
|
+
# EOF
|
292
|
+
yield comments, true
|
293
|
+
yield empty_comments, false
|
287
294
|
end
|
288
295
|
end
|
289
296
|
|
290
297
|
# @rbs comments: AST::CommentLines
|
291
|
-
# @rbs
|
298
|
+
# @rbs return: AST::Annotations::t?
|
292
299
|
def parse_annotation(comments)
|
293
300
|
scanner = StringScanner.new(comments.string)
|
294
301
|
tokenizer = Tokenizer.new(scanner)
|
295
302
|
|
296
303
|
tree = AST::Tree.new(:rbs_annotation)
|
297
304
|
tokenizer.advance(tree)
|
305
|
+
tokenizer.advance(tree)
|
298
306
|
|
299
307
|
case
|
300
|
-
when tokenizer.type?(
|
301
|
-
|
302
|
-
tree <<
|
308
|
+
when tokenizer.type?(K_RBSE)
|
309
|
+
tokenizer.consume_trivias(tree)
|
310
|
+
tree << tokenizer.lookahead1
|
311
|
+
rest = tokenizer.rest
|
312
|
+
rest.delete_prefix!("@rbs!")
|
313
|
+
tree << [:EMBEDDED_RBS, rest]
|
303
314
|
tokenizer.scanner.terminate
|
304
315
|
AST::Annotations::Embedded.new(tree, comments)
|
305
|
-
when tokenizer.type?(
|
306
|
-
tree
|
307
|
-
|
308
|
-
tokenizer.advance(tree)
|
316
|
+
when tokenizer.type?(K_RBS)
|
317
|
+
tokenizer.advance(tree, eat: true)
|
309
318
|
|
310
319
|
case
|
311
|
-
when tokenizer.type?(
|
320
|
+
when tokenizer.type?(T_LVAR, :tELVAR)
|
321
|
+
tree << parse_var_decl(tokenizer)
|
322
|
+
AST::Annotations::VarType.new(tree, comments)
|
323
|
+
when tokenizer.type?(K_SKIP, K_INHERITS, K_OVERRIDE, K_USE, K_GENERIC, K_MODULE, K_CLASS) &&
|
324
|
+
tokenizer.type2?(K_COLON)
|
312
325
|
tree << parse_var_decl(tokenizer)
|
313
326
|
AST::Annotations::VarType.new(tree, comments)
|
314
|
-
when tokenizer.type?(
|
327
|
+
when tokenizer.type?(K_MODULE)
|
328
|
+
tree << parse_module_decl(tokenizer)
|
329
|
+
AST::Annotations::ModuleDecl.new(tree, comments)
|
330
|
+
when tokenizer.type?(K_CLASS)
|
331
|
+
tree << parse_class_decl(tokenizer)
|
332
|
+
AST::Annotations::ClassDecl.new(tree, comments)
|
333
|
+
when tokenizer.type?(K_SKIP)
|
315
334
|
AST::Annotations::Skip.new(tree, comments)
|
316
|
-
when tokenizer.type?(
|
335
|
+
when tokenizer.type?(K_RETURN)
|
317
336
|
tree << parse_return_type_decl(tokenizer)
|
318
337
|
AST::Annotations::ReturnType.new(tree, comments)
|
319
|
-
when tokenizer.type?(
|
338
|
+
when tokenizer.type?(T_ANNOTATION)
|
320
339
|
tree << parse_rbs_annotation(tokenizer)
|
321
340
|
AST::Annotations::RBSAnnotation.new(tree, comments)
|
322
|
-
when tokenizer.type?(
|
341
|
+
when tokenizer.type?(K_INHERITS)
|
323
342
|
tree << parse_inherits(tokenizer)
|
324
343
|
AST::Annotations::Inherits.new(tree, comments)
|
325
|
-
when tokenizer.type?(
|
344
|
+
when tokenizer.type?(K_OVERRIDE)
|
326
345
|
tree << parse_override(tokenizer)
|
327
346
|
AST::Annotations::Override.new(tree, comments)
|
328
|
-
when tokenizer.type?(
|
347
|
+
when tokenizer.type?(K_USE)
|
329
348
|
tree << parse_use(tokenizer)
|
330
349
|
AST::Annotations::Use.new(tree, comments)
|
331
|
-
when tokenizer.type?(
|
350
|
+
when tokenizer.type?(K_MODULE_SELF)
|
332
351
|
tree << parse_module_self(tokenizer)
|
333
352
|
AST::Annotations::ModuleSelf.new(tree, comments)
|
334
|
-
when tokenizer.type?(
|
353
|
+
when tokenizer.type?(K_GENERIC)
|
335
354
|
tree << parse_generic(tokenizer)
|
336
355
|
AST::Annotations::Generic.new(tree, comments)
|
337
|
-
when tokenizer.type?(
|
356
|
+
when tokenizer.type?(K_SELF, T_ATIDENT)
|
338
357
|
tree << parse_ivar_type(tokenizer)
|
339
358
|
AST::Annotations::IvarType.new(tree, comments)
|
340
|
-
when tokenizer.type?(
|
341
|
-
tree <<
|
342
|
-
AST::Annotations::
|
359
|
+
when tokenizer.type?(K_STAR)
|
360
|
+
tree << parse_splat_param_type(tokenizer)
|
361
|
+
AST::Annotations::SplatParamType.new(tree, comments)
|
362
|
+
when tokenizer.type?(K_STAR2)
|
363
|
+
tree << parse_splat_param_type(tokenizer)
|
364
|
+
AST::Annotations::DoubleSplatParamType.new(tree, comments)
|
365
|
+
when tokenizer.type?(K_AMP)
|
366
|
+
tree << parse_block_type(tokenizer)
|
367
|
+
AST::Annotations::BlockType.new(tree, comments)
|
368
|
+
when tokenizer.type?(K_LPAREN, K_ARROW, K_LBRACE, K_LBRACKET, K_DOT3)
|
369
|
+
tree << parse_method_type_annotation(tokenizer)
|
370
|
+
AST::Annotations::Method.new(tree, comments)
|
343
371
|
end
|
344
|
-
when tokenizer.type?(
|
345
|
-
tree
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
372
|
+
when tokenizer.type?(K_COLON)
|
373
|
+
tokenizer.advance(tree, eat: true)
|
374
|
+
|
375
|
+
if tokenizer.type?(K_DOT3)
|
376
|
+
tokenizer.advance(tree, eat: true)
|
377
|
+
AST::Annotations::Dot3Assertion.new(tree, comments)
|
378
|
+
else
|
379
|
+
type = parse_type_method_type(tokenizer, tree)
|
380
|
+
tree << type
|
381
|
+
|
382
|
+
case type
|
383
|
+
when MethodType
|
384
|
+
AST::Annotations::MethodTypeAssertion.new(tree, comments)
|
385
|
+
when AST::Tree, nil
|
386
|
+
AST::Annotations::SyntaxErrorAssertion.new(tree, comments)
|
387
|
+
else
|
388
|
+
AST::Annotations::TypeAssertion.new(tree, comments)
|
389
|
+
end
|
390
|
+
end
|
391
|
+
when tokenizer.type?(K_LBRACKET)
|
350
392
|
tree << parse_type_app(tokenizer)
|
351
393
|
AST::Annotations::Application.new(tree, comments)
|
352
394
|
end
|
353
395
|
end
|
354
396
|
|
355
397
|
# @rbs tokenizer: Tokenizer
|
356
|
-
# @rbs
|
398
|
+
# @rbs return: AST::Tree
|
357
399
|
def parse_var_decl(tokenizer)
|
358
400
|
tree = AST::Tree.new(:var_decl)
|
359
401
|
|
360
|
-
tokenizer.
|
402
|
+
tokenizer.advance(tree, eat: true)
|
361
403
|
|
362
|
-
if tokenizer.type?(
|
363
|
-
tree << tokenizer.
|
404
|
+
if tokenizer.type?(K_COLON)
|
405
|
+
tree << tokenizer.lookahead1
|
364
406
|
tokenizer.advance(tree)
|
365
407
|
else
|
366
408
|
tree << nil
|
367
409
|
end
|
368
410
|
|
411
|
+
tokenizer.consume_trivias(tree)
|
369
412
|
tree << parse_type(tokenizer, tree)
|
370
413
|
|
371
|
-
|
372
|
-
|
373
|
-
else
|
374
|
-
tree << nil
|
414
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
415
|
+
parse_comment(tokenizer)
|
375
416
|
end
|
376
417
|
|
377
418
|
tree
|
378
419
|
end
|
379
420
|
|
380
421
|
# @rbs tokenizer: Tokenizer
|
381
|
-
# @rbs
|
422
|
+
# @rbs return: AST::Tree
|
382
423
|
def parse_return_type_decl(tokenizer)
|
383
424
|
tree = AST::Tree.new(:return_type_decl)
|
384
425
|
|
385
|
-
tokenizer.consume_token!(
|
426
|
+
tokenizer.consume_token!(K_RETURN, tree: tree)
|
427
|
+
tokenizer.consume_token(K_COLON, tree: tree)
|
386
428
|
tree << parse_type(tokenizer, tree)
|
387
|
-
tree << parse_optional(tokenizer, :
|
429
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
430
|
+
parse_comment(tokenizer)
|
431
|
+
end
|
388
432
|
|
389
433
|
tree
|
390
434
|
end
|
391
435
|
|
392
436
|
# @rbs tokenizer: Tokenizer
|
393
|
-
# @rbs
|
437
|
+
# @rbs return: AST::Tree
|
394
438
|
def parse_comment(tokenizer)
|
395
439
|
tree = AST::Tree.new(:comment)
|
396
440
|
|
397
|
-
tokenizer.
|
441
|
+
tokenizer.consume_token(K_MINUS2, tree: tree)
|
398
442
|
|
399
|
-
|
400
|
-
rest = tokenizer.scanner.rest || ""
|
443
|
+
rest = tokenizer.rest
|
401
444
|
tokenizer.scanner.terminate
|
402
|
-
tree << [
|
445
|
+
tree << [T_COMMENT, rest]
|
403
446
|
|
404
447
|
tree
|
405
448
|
end
|
406
449
|
|
407
450
|
# @rbs tokenizer: Tokenizer
|
408
|
-
# @rbs
|
451
|
+
# @rbs return: AST::Tree
|
409
452
|
def parse_type_app(tokenizer)
|
410
453
|
tree = AST::Tree.new(:tapp)
|
411
454
|
|
412
|
-
if tokenizer.type?(
|
413
|
-
tree << tokenizer.
|
455
|
+
if tokenizer.type?(K_LBRACKET)
|
456
|
+
tree << tokenizer.lookahead1
|
414
457
|
tokenizer.advance(tree)
|
415
458
|
end
|
416
459
|
|
@@ -422,25 +465,55 @@ module RBS
|
|
422
465
|
break unless type
|
423
466
|
break if type.is_a?(AST::Tree)
|
424
467
|
|
425
|
-
if tokenizer.type?(
|
426
|
-
types << tokenizer.
|
468
|
+
if tokenizer.type?(K_COMMA)
|
469
|
+
types << tokenizer.lookahead1
|
427
470
|
tokenizer.advance(types)
|
428
471
|
end
|
429
472
|
|
430
|
-
if tokenizer.type?(
|
473
|
+
if tokenizer.type?(K_RBRACKET)
|
431
474
|
break
|
432
475
|
end
|
433
476
|
end
|
434
477
|
tree << types
|
435
478
|
|
436
|
-
if tokenizer.type?(
|
437
|
-
tree << tokenizer.
|
479
|
+
if tokenizer.type?(K_RBRACKET)
|
480
|
+
tree << tokenizer.lookahead1
|
438
481
|
tokenizer.advance(tree)
|
439
482
|
end
|
440
483
|
|
441
484
|
tree
|
442
485
|
end
|
443
486
|
|
487
|
+
# @rbs (Tokenizer) -> AST::Tree
|
488
|
+
def parse_method_type_annotation(tokenizer)
|
489
|
+
tree = AST::Tree.new(:method_type_annotation)
|
490
|
+
|
491
|
+
until tokenizer.type?(K_EOF)
|
492
|
+
if tokenizer.type?(K_DOT3)
|
493
|
+
tree << tokenizer.lookahead1
|
494
|
+
tokenizer.advance(tree)
|
495
|
+
break
|
496
|
+
else
|
497
|
+
method_type = parse_method_type(tokenizer, tree)
|
498
|
+
case method_type
|
499
|
+
when MethodType
|
500
|
+
tree << method_type
|
501
|
+
|
502
|
+
if tokenizer.type?(K_VBAR)
|
503
|
+
tokenizer.advance(tree, eat: true)
|
504
|
+
else
|
505
|
+
break
|
506
|
+
end
|
507
|
+
when AST::Tree
|
508
|
+
tree << method_type
|
509
|
+
break
|
510
|
+
end
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
tree
|
515
|
+
end
|
516
|
+
|
444
517
|
# Parse a RBS method type or type and returns it
|
445
518
|
#
|
446
519
|
# It tries parsing a method type, and then parsing a type if failed.
|
@@ -451,44 +524,66 @@ module RBS
|
|
451
524
|
#
|
452
525
|
# @rbs tokenizer: Tokenizer
|
453
526
|
# @rbs parent_tree: AST::Tree
|
454
|
-
# @rbs
|
527
|
+
# @rbs return: MethodType | AST::Tree | Types::t | nil
|
455
528
|
def parse_type_method_type(tokenizer, parent_tree)
|
529
|
+
tokenizer.consume_trivias(parent_tree)
|
456
530
|
buffer = RBS::Buffer.new(name: "", content: tokenizer.scanner.string)
|
457
|
-
range = (tokenizer.
|
531
|
+
range = (tokenizer.current_position..)
|
458
532
|
begin
|
459
533
|
if type = RBS::Parser.parse_method_type(buffer, range: range, require_eof: false)
|
460
534
|
loc = type.location or raise
|
461
|
-
|
462
|
-
(size - (tokenizer.scanner.matched_size || 0)).times do
|
463
|
-
tokenizer.scanner.skip(/./)
|
464
|
-
end
|
465
|
-
tokenizer.advance(parent_tree)
|
535
|
+
tokenizer.reset(loc.end_pos, parent_tree)
|
466
536
|
type
|
467
537
|
else
|
468
|
-
tokenizer.advance(parent_tree)
|
469
538
|
nil
|
470
539
|
end
|
471
540
|
rescue RBS::ParsingError
|
472
541
|
begin
|
473
542
|
if type = RBS::Parser.parse_type(buffer, range: range, require_eof: false)
|
474
543
|
loc = type.location or raise
|
475
|
-
|
476
|
-
(size - (tokenizer.scanner.matched_size || 0)).times do
|
477
|
-
tokenizer.scanner.skip(/./)
|
478
|
-
end
|
479
|
-
tokenizer.advance(parent_tree)
|
544
|
+
tokenizer.reset(loc.end_pos, parent_tree)
|
480
545
|
type
|
481
546
|
else
|
482
|
-
tokenizer.advance(parent_tree)
|
483
547
|
nil
|
484
548
|
end
|
485
549
|
rescue RBS::ParsingError
|
486
|
-
content = (tokenizer.scanner.matched || "") + (tokenizer.scanner.rest || "")
|
487
550
|
tree = AST::Tree.new(:type_syntax_error)
|
488
|
-
tree << [
|
551
|
+
tree << [T_SOURCE, tokenizer.rest]
|
552
|
+
tokenizer.scanner.terminate
|
553
|
+
tree
|
554
|
+
end
|
555
|
+
end
|
556
|
+
end
|
557
|
+
|
558
|
+
# Parse a RBS method type
|
559
|
+
#
|
560
|
+
# If parsing failed, it returns a Tree(`:type_syntax_error), consuming all of the remaining input.
|
561
|
+
#
|
562
|
+
# Note that this doesn't recognize `--` comment unlike `parse_type`.
|
563
|
+
#
|
564
|
+
# @rbs tokenizer: Tokenizer
|
565
|
+
# @rbs parent_tree: AST::Tree
|
566
|
+
# @rbs return: MethodType | AST::Tree
|
567
|
+
def parse_method_type(tokenizer, parent_tree)
|
568
|
+
tokenizer.consume_trivias(parent_tree)
|
569
|
+
buffer = RBS::Buffer.new(name: "", content: tokenizer.scanner.string)
|
570
|
+
range = (tokenizer.current_position..)
|
571
|
+
begin
|
572
|
+
if type = RBS::Parser.parse_method_type(buffer, range: range, require_eof: false)
|
573
|
+
loc = type.location or raise
|
574
|
+
tokenizer.reset(loc.end_pos, parent_tree)
|
575
|
+
type
|
576
|
+
else
|
577
|
+
tree = AST::Tree.new(:type_syntax_error)
|
578
|
+
tree << [T_SOURCE, tokenizer.rest]
|
489
579
|
tokenizer.scanner.terminate
|
490
580
|
tree
|
491
581
|
end
|
582
|
+
rescue RBS::ParsingError
|
583
|
+
tree = AST::Tree.new(:type_syntax_error)
|
584
|
+
tree << [T_SOURCE, tokenizer.rest]
|
585
|
+
tokenizer.scanner.terminate
|
586
|
+
tree
|
492
587
|
end
|
493
588
|
end
|
494
589
|
|
@@ -507,49 +602,45 @@ module RBS
|
|
507
602
|
#
|
508
603
|
# @rbs tokenizer: Tokenizer
|
509
604
|
# @rbs parent_tree: AST::Tree
|
510
|
-
# @rbs
|
605
|
+
# @rbs return: Types::t | AST::Tree | nil
|
511
606
|
def parse_type(tokenizer, parent_tree)
|
607
|
+
tokenizer.consume_trivias(parent_tree)
|
512
608
|
buffer = RBS::Buffer.new(name: "", content: tokenizer.scanner.string)
|
513
|
-
range = (tokenizer.
|
609
|
+
range = (tokenizer.current_position..)
|
514
610
|
if type = RBS::Parser.parse_type(buffer, range: range, require_eof: false)
|
515
611
|
loc = type.location or raise
|
516
|
-
|
517
|
-
(size - (tokenizer.scanner.matched_size || 0)).times do
|
518
|
-
tokenizer.scanner.skip(/./)
|
519
|
-
end
|
520
|
-
tokenizer.advance(parent_tree)
|
612
|
+
tokenizer.reset(loc.end_pos, parent_tree)
|
521
613
|
type
|
522
614
|
else
|
523
|
-
tokenizer.advance(parent_tree)
|
524
615
|
nil
|
525
616
|
end
|
526
617
|
rescue RBS::ParsingError
|
527
618
|
content = tokenizer.skip_to_comment
|
528
619
|
tree = AST::Tree.new(:type_syntax_error)
|
529
|
-
tree << [
|
620
|
+
tree << [T_SOURCE, content]
|
530
621
|
tree
|
531
622
|
end
|
532
623
|
|
533
624
|
# @rbs tokenizer: Tokenizer
|
534
|
-
# @rbs
|
625
|
+
# @rbs return: AST::Tree
|
535
626
|
def parse_rbs_annotation(tokenizer)
|
536
627
|
tree = AST::Tree.new(:rbs_annotation)
|
537
628
|
|
538
|
-
while tokenizer.type?(
|
539
|
-
tree << tokenizer.
|
629
|
+
while tokenizer.type?(T_ANNOTATION)
|
630
|
+
tree << tokenizer.lookahead1
|
540
631
|
tokenizer.advance(tree)
|
541
632
|
end
|
542
633
|
|
543
634
|
tree
|
544
635
|
end
|
545
636
|
|
546
|
-
# @rbs
|
547
|
-
# @rbs
|
637
|
+
# @rbs tokenizer: Tokenizer
|
638
|
+
# @rbs return: AST::Tree
|
548
639
|
def parse_inherits(tokenizer)
|
549
640
|
tree = AST::Tree.new(:rbs_inherits)
|
550
641
|
|
551
|
-
if tokenizer.type?(
|
552
|
-
tree << tokenizer.
|
642
|
+
if tokenizer.type?(K_INHERITS)
|
643
|
+
tree << tokenizer.lookahead1
|
553
644
|
tokenizer.advance(tree)
|
554
645
|
end
|
555
646
|
|
@@ -561,12 +652,12 @@ module RBS
|
|
561
652
|
# Parse `@rbs override` annotation
|
562
653
|
#
|
563
654
|
# @rbs tokenizer: Tokenizer
|
564
|
-
# @rbs
|
655
|
+
# @rbs return: AST::Tree
|
565
656
|
def parse_override(tokenizer)
|
566
657
|
tree = AST::Tree.new(:override)
|
567
658
|
|
568
|
-
if tokenizer.type?(
|
569
|
-
tree << tokenizer.
|
659
|
+
if tokenizer.type?(K_OVERRIDE)
|
660
|
+
tree << tokenizer.lookahead1
|
570
661
|
tokenizer.advance(tree)
|
571
662
|
end
|
572
663
|
|
@@ -576,20 +667,20 @@ module RBS
|
|
576
667
|
# Parse `@rbs use [CLAUSES]` annotation
|
577
668
|
#
|
578
669
|
# @rbs tokenizer: Tokenizer
|
579
|
-
# @rbs
|
670
|
+
# @rbs return: AST::Tree
|
580
671
|
def parse_use(tokenizer)
|
581
672
|
tree = AST::Tree.new(:use)
|
582
673
|
|
583
|
-
if tokenizer.type?(
|
584
|
-
tree << tokenizer.
|
674
|
+
if tokenizer.type?(K_USE)
|
675
|
+
tree << tokenizer.lookahead1
|
585
676
|
tokenizer.advance(tree)
|
586
677
|
end
|
587
678
|
|
588
|
-
while tokenizer.type?(
|
679
|
+
while tokenizer.type?(K_COLON2, T_UIDENT, :tIFIDENT, :tLVAR)
|
589
680
|
tree << parse_use_clause(tokenizer)
|
590
681
|
|
591
|
-
if tokenizer.type?(
|
592
|
-
|
682
|
+
if tokenizer.type?(K_COMMA)
|
683
|
+
tokenizer.advance(tree, eat: true)
|
593
684
|
else
|
594
685
|
tree << nil
|
595
686
|
end
|
@@ -608,23 +699,23 @@ module RBS
|
|
608
699
|
# * [`::`?, [UIDENT) `::`]*, `*`]
|
609
700
|
#
|
610
701
|
# @rbs tokenizer: Tokenizer
|
611
|
-
# @rbs
|
702
|
+
# @rbs return: AST::Tree
|
612
703
|
def parse_use_clause(tokenizer)
|
613
704
|
tree = AST::Tree.new(:use_clause)
|
614
705
|
|
615
|
-
if tokenizer.type?(
|
616
|
-
tree << tokenizer.
|
706
|
+
if tokenizer.type?(K_COLON2)
|
707
|
+
tree << tokenizer.lookahead1
|
617
708
|
tokenizer.advance(tree)
|
618
709
|
end
|
619
710
|
|
620
711
|
while true
|
621
712
|
case
|
622
|
-
when tokenizer.type?(
|
623
|
-
|
713
|
+
when tokenizer.type?(T_UIDENT)
|
714
|
+
tokenizer.advance(tree, eat: true)
|
624
715
|
|
625
716
|
case
|
626
|
-
when tokenizer.type?(
|
627
|
-
|
717
|
+
when tokenizer.type?(K_COLON2)
|
718
|
+
tokenizer.advance(tree, eat: true)
|
628
719
|
else
|
629
720
|
break
|
630
721
|
end
|
@@ -634,20 +725,20 @@ module RBS
|
|
634
725
|
end
|
635
726
|
|
636
727
|
case
|
637
|
-
when tokenizer.type?(
|
638
|
-
|
639
|
-
when tokenizer.type?(
|
640
|
-
|
641
|
-
when tokenizer.type?(
|
642
|
-
|
728
|
+
when tokenizer.type?(T_LVAR)
|
729
|
+
tokenizer.advance(tree, eat: true)
|
730
|
+
when tokenizer.type?(T_IFIDENT)
|
731
|
+
tokenizer.advance(tree, eat: true)
|
732
|
+
when tokenizer.type?(K_STAR)
|
733
|
+
tokenizer.advance(tree, eat: true)
|
643
734
|
return tree
|
644
735
|
end
|
645
736
|
|
646
|
-
if tokenizer.type?(
|
737
|
+
if tokenizer.type?(K_AS)
|
647
738
|
as_tree = AST::Tree.new(:as)
|
648
739
|
|
649
|
-
tokenizer.consume_token!(
|
650
|
-
tokenizer.consume_token(
|
740
|
+
tokenizer.consume_token!(K_AS, tree: as_tree)
|
741
|
+
tokenizer.consume_token(T_LVAR, T_IFIDENT, T_UIDENT, tree: as_tree)
|
651
742
|
|
652
743
|
tree << as_tree
|
653
744
|
else
|
@@ -658,17 +749,15 @@ module RBS
|
|
658
749
|
end
|
659
750
|
|
660
751
|
# @rbs tokenizer: Tokenizer
|
661
|
-
# @rbs
|
752
|
+
# @rbs return: AST::Tree
|
662
753
|
def parse_module_self(tokenizer)
|
663
754
|
tree = AST::Tree.new(:module_self)
|
664
755
|
|
665
|
-
tokenizer.consume_token!(
|
756
|
+
tokenizer.consume_token!(K_MODULE_SELF, tree: tree)
|
666
757
|
tree << parse_type(tokenizer, tree)
|
667
758
|
|
668
|
-
|
669
|
-
|
670
|
-
else
|
671
|
-
tree << nil
|
759
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
760
|
+
parse_comment(tokenizer)
|
672
761
|
end
|
673
762
|
|
674
763
|
tree
|
@@ -679,87 +768,220 @@ module RBS
|
|
679
768
|
# ```rb
|
680
769
|
# # Test if tokenize has `--` token, then parse comment or insert `nil` to tree
|
681
770
|
#
|
682
|
-
# tree << parse_optional(tokenizer,
|
771
|
+
# tree << parse_optional(tokenizer, K_MINUS2) do
|
683
772
|
# parse_comment(tokenizer)
|
684
773
|
# end
|
685
774
|
# ```
|
686
775
|
#
|
776
|
+
# If `tree:` is given, it consumes trivia tokens before yielding the block.
|
777
|
+
#
|
687
778
|
# @rbs tokenizer: Tokenizer
|
688
|
-
# @rbs types:
|
689
|
-
# @rbs
|
690
|
-
# @rbs
|
691
|
-
|
779
|
+
# @rbs *types: Symbol
|
780
|
+
# @rbs tree: AST::Tree? -- the parent tree to consume leading trivia tokens
|
781
|
+
# @rbs &block: () -> AST::Tree
|
782
|
+
# @rbs return: AST::Tree?
|
783
|
+
def parse_optional(tokenizer, *types, tree: nil, &block)
|
692
784
|
if tokenizer.type?(*types)
|
785
|
+
if tree
|
786
|
+
tokenizer.consume_trivias(tree)
|
787
|
+
end
|
693
788
|
yield
|
694
789
|
end
|
695
790
|
end
|
696
791
|
|
697
792
|
# @rbs tokenizer: Tokenizer
|
698
|
-
# @rbs
|
793
|
+
# @rbs return: AST::Tree
|
699
794
|
def parse_generic(tokenizer)
|
700
795
|
tree = AST::Tree.new(:generic)
|
701
796
|
|
702
|
-
tokenizer.consume_token!(
|
797
|
+
tokenizer.consume_token!(K_GENERIC, tree: tree)
|
703
798
|
|
704
|
-
|
705
|
-
tokenizer.consume_token(:kIN, :kOUT, tree: tree)
|
799
|
+
tree << parse_type_param(tokenizer)
|
706
800
|
|
707
|
-
tokenizer
|
801
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
802
|
+
parse_comment(tokenizer)
|
803
|
+
end
|
708
804
|
|
709
|
-
tree
|
805
|
+
tree
|
806
|
+
end
|
807
|
+
|
808
|
+
# @rbs (Tokenizer) -> AST::Tree
|
809
|
+
def parse_type_param(tokenizer)
|
810
|
+
tree = AST::Tree.new(:type_param)
|
811
|
+
|
812
|
+
tokenizer.consume_token(K_UNCHECKED, tree: tree)
|
813
|
+
tokenizer.consume_token(K_IN, K_OUT, tree: tree)
|
814
|
+
|
815
|
+
tokenizer.consume_token(T_UIDENT, tree: tree)
|
816
|
+
|
817
|
+
tree << parse_optional(tokenizer, K_LT, tree: tree) do
|
710
818
|
bound = AST::Tree.new(:upper_bound)
|
711
819
|
|
712
|
-
tokenizer.consume_token!(
|
820
|
+
tokenizer.consume_token!(K_LT, tree: bound)
|
713
821
|
bound << parse_type(tokenizer, bound)
|
714
822
|
|
715
823
|
bound
|
716
824
|
end
|
717
825
|
|
718
|
-
tree << parse_optional(tokenizer, :kMINUS2) do
|
719
|
-
parse_comment(tokenizer)
|
720
|
-
end
|
721
|
-
|
722
826
|
tree
|
723
827
|
end
|
724
828
|
|
725
|
-
|
829
|
+
#: (Tokenizer) -> AST::Tree
|
726
830
|
def parse_ivar_type(tokenizer)
|
727
831
|
tree = AST::Tree.new(:ivar_type)
|
728
832
|
|
729
|
-
tokenizer.consume_token(
|
730
|
-
tokenizer.consume_token(
|
833
|
+
tokenizer.consume_token(K_SELF, tree: tree)
|
834
|
+
tokenizer.consume_token(K_DOT, tree: tree)
|
835
|
+
|
836
|
+
tokenizer.consume_token(T_ATIDENT, tree: tree)
|
837
|
+
tokenizer.consume_token(K_COLON, tree: tree)
|
838
|
+
|
839
|
+
tree << parse_type(tokenizer, tree)
|
840
|
+
|
841
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
842
|
+
parse_comment(tokenizer)
|
843
|
+
end
|
844
|
+
|
845
|
+
tree
|
846
|
+
end
|
847
|
+
|
848
|
+
#: (Tokenizer) -> AST::Tree
|
849
|
+
def parse_splat_param_type(tokenizer)
|
850
|
+
tree = AST::Tree.new(:splat_param_type)
|
731
851
|
|
732
|
-
tokenizer.consume_token(:
|
733
|
-
tokenizer.consume_token(
|
852
|
+
tokenizer.consume_token!(K_STAR, :kSTAR2, tree: tree)
|
853
|
+
tokenizer.consume_token(T_LVAR, tree: tree)
|
854
|
+
tokenizer.consume_token(K_COLON, tree: tree)
|
734
855
|
|
735
856
|
tree << parse_type(tokenizer, tree)
|
736
857
|
|
737
|
-
tree << parse_optional(tokenizer, :
|
858
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
738
859
|
parse_comment(tokenizer)
|
739
860
|
end
|
740
861
|
|
741
862
|
tree
|
742
863
|
end
|
743
864
|
|
744
|
-
|
745
|
-
def
|
746
|
-
tree = AST::Tree.new(:
|
865
|
+
#: (Tokenizer) -> AST::Tree
|
866
|
+
def parse_block_type(tokenizer)
|
867
|
+
tree = AST::Tree.new(:block_type)
|
868
|
+
|
869
|
+
tokenizer.consume_token!(K_AMP, tree: tree)
|
870
|
+
tokenizer.consume_token(T_LVAR, tree: tree)
|
871
|
+
tokenizer.consume_token(K_COLON, tree: tree)
|
872
|
+
|
873
|
+
tokenizer.consume_token(K_QUESTION, tree: tree)
|
747
874
|
|
748
|
-
tokenizer.
|
749
|
-
tokenizer.consume_token(:kOPTIONAL, tree: tree)
|
875
|
+
tokenizer.consume_trivias(tree)
|
750
876
|
|
751
877
|
unless (string = tokenizer.skip_to_comment()).empty?
|
752
|
-
tree << [
|
878
|
+
tree << [T_BLOCKSTR, string]
|
753
879
|
else
|
754
880
|
tree << nil
|
755
881
|
end
|
756
882
|
|
757
|
-
tree << parse_optional(tokenizer, :
|
883
|
+
tree << parse_optional(tokenizer, K_MINUS2, tree: tree) do
|
758
884
|
parse_comment(tokenizer)
|
759
885
|
end
|
760
886
|
|
761
887
|
tree
|
762
888
|
end
|
889
|
+
|
890
|
+
# @rbs (Tokenizer) -> AST::Tree
|
891
|
+
def parse_module_decl(tokenizer)
|
892
|
+
tree = AST::Tree.new(:module_decl)
|
893
|
+
|
894
|
+
tokenizer.consume_token!(K_MODULE, tree: tree)
|
895
|
+
|
896
|
+
tree << parse_module_name(tokenizer)
|
897
|
+
|
898
|
+
tree << parse_optional(tokenizer, K_LBRACKET) do
|
899
|
+
parse_type_params(tokenizer)
|
900
|
+
end
|
901
|
+
|
902
|
+
tree << parse_optional(tokenizer, K_COLON) do
|
903
|
+
parse_module_selfs(tokenizer)
|
904
|
+
end
|
905
|
+
|
906
|
+
tree
|
907
|
+
end
|
908
|
+
|
909
|
+
# @rbs (Tokenizer) -> AST::Tree
|
910
|
+
def parse_class_decl(tokenizer)
|
911
|
+
tree = AST::Tree.new(:class_decl)
|
912
|
+
|
913
|
+
tokenizer.consume_token!(K_CLASS, tree: tree)
|
914
|
+
|
915
|
+
tree << parse_module_name(tokenizer)
|
916
|
+
|
917
|
+
tree << parse_optional(tokenizer, K_LBRACKET) do
|
918
|
+
parse_type_params(tokenizer)
|
919
|
+
end
|
920
|
+
|
921
|
+
tree << parse_optional(tokenizer, K_LT) do
|
922
|
+
super_class = AST::Tree.new(:super_class)
|
923
|
+
tokenizer.consume_token!(K_LT, tree: super_class)
|
924
|
+
super_class << parse_type(tokenizer, super_class)
|
925
|
+
super_class
|
926
|
+
end
|
927
|
+
|
928
|
+
tree
|
929
|
+
end
|
930
|
+
|
931
|
+
# @rbs (Tokenizer) -> AST::Tree
|
932
|
+
def parse_module_name(tokenizer)
|
933
|
+
tree = AST::Tree.new(:module_name)
|
934
|
+
|
935
|
+
tokenizer.consume_token(K_COLON2, tree: tree)
|
936
|
+
|
937
|
+
while tokenizer.type?(T_UIDENT) && tokenizer.type2?(K_COLON2)
|
938
|
+
tokenizer.consume_token!(T_UIDENT, tree: tree)
|
939
|
+
tokenizer.consume_token!(K_COLON2, tree: tree)
|
940
|
+
end
|
941
|
+
|
942
|
+
tokenizer.consume_token(T_UIDENT, tree: tree)
|
943
|
+
|
944
|
+
tree
|
945
|
+
end
|
946
|
+
|
947
|
+
# @rbs (Tokenizer) -> AST::Tree
|
948
|
+
def parse_type_params(tokenizer)
|
949
|
+
tree = AST::Tree.new(:type_params)
|
950
|
+
|
951
|
+
tokenizer.consume_token!(K_LBRACKET, tree: tree)
|
952
|
+
|
953
|
+
while true
|
954
|
+
if type_param = parse_optional(tokenizer, T_UIDENT, K_UNCHECKED, K_IN, K_OUT) { parse_type_param(tokenizer) }
|
955
|
+
tree << type_param
|
956
|
+
break if tokenizer.type?(K_RBRACKET)
|
957
|
+
tokenizer.consume_token(K_COMMA, tree: tree)
|
958
|
+
else
|
959
|
+
break
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
tokenizer.consume_token(K_RBRACKET, tree: tree)
|
964
|
+
|
965
|
+
tree
|
966
|
+
end
|
967
|
+
|
968
|
+
# @rbs (Tokenizer) -> AST::Tree
|
969
|
+
def parse_module_selfs(tokenizer)
|
970
|
+
tree = AST::Tree.new(:module_selfs)
|
971
|
+
|
972
|
+
tokenizer.consume_token!(K_COLON, tree: tree)
|
973
|
+
|
974
|
+
while true
|
975
|
+
tree << parse_type(tokenizer, tree)
|
976
|
+
if tokenizer.type?(K_COMMA)
|
977
|
+
tokenizer.advance(tree, eat: true)
|
978
|
+
else
|
979
|
+
break
|
980
|
+
end
|
981
|
+
end
|
982
|
+
|
983
|
+
tree
|
984
|
+
end
|
763
985
|
end
|
764
986
|
end
|
765
987
|
end
|