rbs-inline 0.4.0 → 0.5.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.
- checksums.yaml +4 -4
- data/README.md +8 -5
- 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 +427 -138
- data/lib/rbs/inline/ast/comment_lines.rb +17 -20
- data/lib/rbs/inline/ast/declarations.rb +64 -28
- data/lib/rbs/inline/ast/members.rb +129 -115
- data/lib/rbs/inline/ast/tree.rb +37 -22
- data/lib/rbs/inline/cli.rb +12 -12
- data/lib/rbs/inline/node_utils.rb +1 -1
- data/lib/rbs/inline/parser.rb +134 -65
- data/lib/rbs/inline/version.rb +1 -1
- data/lib/rbs/inline/writer.rb +195 -118
- data/lib/rbs/inline.rb +1 -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 +141 -37
- data/sig/generated/rbs/inline/ast/comment_lines.rbs +8 -4
- data/sig/generated/rbs/inline/ast/declarations.rbs +26 -10
- data/sig/generated/rbs/inline/ast/members.rbs +26 -15
- data/sig/generated/rbs/inline/ast/tree.rbs +23 -17
- data/sig/generated/rbs/inline/cli.rbs +3 -3
- data/sig/generated/rbs/inline/node_utils.rbs +1 -1
- data/sig/generated/rbs/inline/parser.rbs +35 -18
- data/sig/generated/rbs/inline/writer.rbs +54 -22
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c6ea86390a9ce51331956c34fb2eedc77ae45c4ac0fc7b39d67f2cacb2a5af0
|
4
|
+
data.tar.gz: 9e1446ab0920edec03ed54a1a07c8868e3dac9529813c389ed35f85f0380e7c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 793f9e99431ac027e1ccf6d3b2b31ead740b9227584aa5be5f751cd1eafea85ce8db37e070b5dfcde28139f629d2c2a499aa5e2d507fcbe53c7fd8a3e9cf2377
|
7
|
+
data.tar.gz: 3f74d9a9a96189fcd21c470aa7b97949fa625dbb46b218c6ae993b049993947d7a27840755af43626702aa6b55cebc1a25d70830343c6f954bcb2694f30fc34b
|
data/README.md
CHANGED
@@ -8,29 +8,32 @@ RBS::Inline allows embedding RBS type declarations into Ruby code as comments. Y
|
|
8
8
|
> [!IMPORTANT]
|
9
9
|
> This gem is a prototype for testing. We plan to merge this feature to rbs-gem and deprecate rbs-inline gem after that.
|
10
10
|
|
11
|
+
> [!NOTE]
|
12
|
+
> Use Steep >= `1.8.0.dev` to avoid the conflicts on `#:` syntax.
|
13
|
+
|
11
14
|
Here is a quick example of embedded declarations.
|
12
15
|
|
13
16
|
```rb
|
14
17
|
# rbs_inline: enabled
|
15
18
|
|
16
19
|
class Person
|
17
|
-
attr_reader :name
|
20
|
+
attr_reader :name #: String
|
18
21
|
|
19
|
-
attr_reader :addresses
|
22
|
+
attr_reader :addresses #: Array[String]
|
20
23
|
|
21
24
|
# @rbs name: String
|
22
25
|
# @rbs addresses: Array[String]
|
23
|
-
# @rbs
|
26
|
+
# @rbs return: void
|
24
27
|
def initialize(name:, addresses:)
|
25
28
|
@name = name
|
26
29
|
@addresses = addresses
|
27
30
|
end
|
28
31
|
|
29
|
-
def to_s
|
32
|
+
def to_s #: String
|
30
33
|
"Person(name = #{name}, addresses = #{addresses.join(", ")})"
|
31
34
|
end
|
32
35
|
|
33
|
-
# @rbs
|
36
|
+
# @rbs &block: (String) -> void
|
34
37
|
def each_address(&block) #:: void
|
35
38
|
addresses.each(&block)
|
36
39
|
end
|
data/Rakefile
CHANGED
@@ -10,3 +10,15 @@ Rake::TestTask.new(:test) do |t|
|
|
10
10
|
end
|
11
11
|
|
12
12
|
task default: :test
|
13
|
+
|
14
|
+
namespace :rbs do
|
15
|
+
task :generate do
|
16
|
+
sh "rbs-inline --opt-out --output lib"
|
17
|
+
end
|
18
|
+
|
19
|
+
task :watch do
|
20
|
+
sh "fswatch -0 lib | xargs -n1 -0 rbs-inline --opt-out --output lib"
|
21
|
+
rescue Interrupt
|
22
|
+
# nop
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,361 @@
|
|
1
|
+
module RBS
|
2
|
+
module Inline
|
3
|
+
class AnnotationParser
|
4
|
+
module Tokens
|
5
|
+
K_RETURN = :kRETURN
|
6
|
+
K_INHERITS = :kINHERITS
|
7
|
+
K_AS = :kAS
|
8
|
+
K_OVERRIDE = :kOVERRIDE
|
9
|
+
K_USE = :kUSE
|
10
|
+
K_MODULE_SELF = :kMODULESELF
|
11
|
+
K_GENERIC = :kGENERIC
|
12
|
+
K_IN = :kIN
|
13
|
+
K_OUT = :kOUT
|
14
|
+
K_UNCHECKED = :kUNCHECKED
|
15
|
+
K_SELF = :kSELF
|
16
|
+
K_SKIP = :kSKIP
|
17
|
+
K_YIELDS = :kYIELDS
|
18
|
+
K_MODULE = :kMODULE
|
19
|
+
K_CLASS = :kCLASS
|
20
|
+
K_COLON2 = :kCOLON2
|
21
|
+
K_COLON = :kCOLON
|
22
|
+
K_LBRACKET = :kLBRACKET
|
23
|
+
K_RBRACKET = :kRBRACKET
|
24
|
+
K_COMMA = :kCOMMA
|
25
|
+
K_STAR2 = :kSTAR2
|
26
|
+
K_STAR = :kSTAR
|
27
|
+
K_MINUS2 = :kMINUS2
|
28
|
+
K_LT = :kLT
|
29
|
+
K_DOT3 = :kDOT3
|
30
|
+
K_DOT = :kDOT
|
31
|
+
K_ARROW = :kARROW
|
32
|
+
K_LBRACE = :kLBRACE
|
33
|
+
K_LPAREN = :kLPAREN
|
34
|
+
K_AMP = :kAMP
|
35
|
+
K_QUESTION = :kQUESTION
|
36
|
+
K_VBAR = :kVBAR
|
37
|
+
|
38
|
+
K_EOF = :kEOF
|
39
|
+
|
40
|
+
# `@rbs!`
|
41
|
+
K_RBSE = :kRBSE
|
42
|
+
|
43
|
+
# `@rbs`
|
44
|
+
K_RBS = :kRBS
|
45
|
+
|
46
|
+
T_UIDENT = :tUIDENT
|
47
|
+
T_IFIDENT = :tIFIDENT
|
48
|
+
T_LVAR = :tLVAR
|
49
|
+
|
50
|
+
# The body of comment string following `--`
|
51
|
+
T_COMMENT = :tCOMMENT
|
52
|
+
|
53
|
+
# Type/method type source
|
54
|
+
T_SOURCE = :tSOURCE
|
55
|
+
|
56
|
+
# Block type source
|
57
|
+
T_BLOCKSTR = :tBLOCKSTR
|
58
|
+
|
59
|
+
# `!` local variable
|
60
|
+
T_ELVAR = :tELVAR
|
61
|
+
|
62
|
+
T_ATIDENT = :tATIDENT
|
63
|
+
T_ANNOTATION = :tANNOTATION
|
64
|
+
T_WHITESPACE = :tWHITESPACE
|
65
|
+
end
|
66
|
+
|
67
|
+
class Tokenizer
|
68
|
+
include Tokens
|
69
|
+
|
70
|
+
KEYWORDS = {
|
71
|
+
"return" => K_RETURN,
|
72
|
+
"inherits" => K_INHERITS,
|
73
|
+
"as" => K_AS,
|
74
|
+
"override" => K_OVERRIDE,
|
75
|
+
"use" => K_USE,
|
76
|
+
"module-self" => K_MODULE_SELF,
|
77
|
+
"generic" => K_GENERIC,
|
78
|
+
"in" => K_IN,
|
79
|
+
"out" => K_OUT,
|
80
|
+
"unchecked" => K_UNCHECKED,
|
81
|
+
"self" => K_SELF,
|
82
|
+
"skip" => K_SKIP,
|
83
|
+
"yields" => K_YIELDS,
|
84
|
+
"module" => K_MODULE,
|
85
|
+
"class" => K_CLASS,
|
86
|
+
} #: Hash[String, Symbol]
|
87
|
+
KW_RE = /#{Regexp.union(KEYWORDS.keys)}\b/
|
88
|
+
|
89
|
+
PUNCTS = {
|
90
|
+
"::" => K_COLON2,
|
91
|
+
":" => K_COLON,
|
92
|
+
"[" => K_LBRACKET,
|
93
|
+
"]" => K_RBRACKET,
|
94
|
+
"," => K_COMMA,
|
95
|
+
"**" => K_STAR2,
|
96
|
+
"*" => K_STAR,
|
97
|
+
"--" => K_MINUS2,
|
98
|
+
"<" => K_LT,
|
99
|
+
"..." => K_DOT3,
|
100
|
+
"." => K_DOT,
|
101
|
+
"->" => K_ARROW,
|
102
|
+
"{" => K_LBRACE,
|
103
|
+
"(" => K_LPAREN,
|
104
|
+
"&" => K_AMP,
|
105
|
+
"?" => K_QUESTION,
|
106
|
+
"|" => K_VBAR,
|
107
|
+
} #: Hash[String, Symbol]
|
108
|
+
PUNCTS_RE = Regexp.union(PUNCTS.keys) #: Regexp
|
109
|
+
|
110
|
+
attr_reader :scanner #: StringScanner
|
111
|
+
|
112
|
+
# Tokens that comes after the current position
|
113
|
+
#
|
114
|
+
# This is a four tuple of tokens.
|
115
|
+
#
|
116
|
+
# 1. The first array is a trivia tokens before current position
|
117
|
+
# 2. The second token is the first lookahead token after the current position
|
118
|
+
# 3. The third array is a trivia tokens between the first lookahead and the second lookahead
|
119
|
+
# 4. The fourth token is the second lookahead token
|
120
|
+
#
|
121
|
+
attr_reader :lookahead_tokens #: [Array[token], token?, Array[token], token?]
|
122
|
+
|
123
|
+
# Token that comes after the current position
|
124
|
+
# @rbs %a{pure}
|
125
|
+
def lookahead1 #: token?
|
126
|
+
lookahead_tokens[1]
|
127
|
+
end
|
128
|
+
|
129
|
+
# Token that comes after `lookahead1`
|
130
|
+
# @rbs %a{pure}
|
131
|
+
def lookahead2 #: token?
|
132
|
+
lookahead_tokens[3]
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns the current char position of the first lookahead token
|
136
|
+
#
|
137
|
+
# ```
|
138
|
+
# __ foo ___ bar baz
|
139
|
+
# ^^ Trivia tokens before lookahead1
|
140
|
+
# ^ #current_position
|
141
|
+
# ^^^ lookahead1
|
142
|
+
# ^^^ Trivia tokens between lookahead1 and lookahead2
|
143
|
+
# ^^^ lookahead2
|
144
|
+
# ^ <= scanner.charpos
|
145
|
+
# ```
|
146
|
+
#
|
147
|
+
def current_position #: Integer
|
148
|
+
start = scanner.charpos
|
149
|
+
start -= lookahead1[1].size if lookahead1
|
150
|
+
lookahead_tokens[2].each {|_, s| start -= s.size }
|
151
|
+
start -= lookahead2[1].size if lookahead2
|
152
|
+
start
|
153
|
+
end
|
154
|
+
|
155
|
+
def lookaheads #: Array[Symbol?]
|
156
|
+
[lookahead1&.[](0), lookahead2&.[](0)]
|
157
|
+
end
|
158
|
+
|
159
|
+
# @rbs scanner: StringScanner
|
160
|
+
# @rbs return: void
|
161
|
+
def initialize(scanner)
|
162
|
+
@scanner = scanner
|
163
|
+
|
164
|
+
@lookahead_tokens = [[], nil, [], nil]
|
165
|
+
end
|
166
|
+
|
167
|
+
# Advances the scanner
|
168
|
+
#
|
169
|
+
# @rbs tree: AST::Tree -- Tree to insert trivia tokens
|
170
|
+
# @rbs eat: bool -- true to add the current lookahead token into the tree
|
171
|
+
# @rbs return: void
|
172
|
+
def advance(tree, eat: false)
|
173
|
+
consume_trivias(tree)
|
174
|
+
last = lookahead_tokens[1]
|
175
|
+
tree << last if eat
|
176
|
+
|
177
|
+
lookahead_tokens[0].replace(lookahead_tokens[2])
|
178
|
+
lookahead_tokens[1] = lookahead_tokens[3]
|
179
|
+
lookahead_tokens[2].clear
|
180
|
+
|
181
|
+
while s = scanner.scan(/\s+/)
|
182
|
+
lookahead_tokens[2] << [T_WHITESPACE, s]
|
183
|
+
end
|
184
|
+
|
185
|
+
lookahead =
|
186
|
+
case
|
187
|
+
when scanner.eos?
|
188
|
+
[K_EOF, ""]
|
189
|
+
when s = scanner.scan(/@rbs!/)
|
190
|
+
[K_RBSE, s]
|
191
|
+
when s = scanner.scan(/@rbs\b/)
|
192
|
+
[K_RBS, s]
|
193
|
+
when s = scanner.scan(PUNCTS_RE)
|
194
|
+
[PUNCTS.fetch(s), s]
|
195
|
+
when s = scanner.scan(KW_RE)
|
196
|
+
[KEYWORDS.fetch(s), s]
|
197
|
+
when s = scanner.scan(/[A-Z]\w*/)
|
198
|
+
[T_UIDENT, s]
|
199
|
+
when s = scanner.scan(/_[A-Z]\w*/)
|
200
|
+
[T_IFIDENT, s]
|
201
|
+
when s = scanner.scan(/[a-z]\w*/)
|
202
|
+
[T_LVAR, s]
|
203
|
+
when s = scanner.scan(/![a-z]\w*/)
|
204
|
+
[T_ELVAR, s]
|
205
|
+
when s = scanner.scan(/@\w+/)
|
206
|
+
[T_ATIDENT, s]
|
207
|
+
when s = scanner.scan(/%a\{[^}]+\}/)
|
208
|
+
[T_ANNOTATION, s]
|
209
|
+
when s = scanner.scan(/%a\[[^\]]+\]/)
|
210
|
+
[T_ANNOTATION, s]
|
211
|
+
when s = scanner.scan(/%a\([^)]+\)/)
|
212
|
+
[T_ANNOTATION, s]
|
213
|
+
end #: token?
|
214
|
+
|
215
|
+
lookahead_tokens[3] = lookahead
|
216
|
+
|
217
|
+
last
|
218
|
+
end
|
219
|
+
|
220
|
+
# @rbs (AST::Tree?) -> String
|
221
|
+
def consume_trivias(tree)
|
222
|
+
buf = +""
|
223
|
+
|
224
|
+
lookahead_tokens[0].each do |tok|
|
225
|
+
tree << tok if tree
|
226
|
+
buf << tok[1]
|
227
|
+
end
|
228
|
+
lookahead_tokens[0].clear
|
229
|
+
|
230
|
+
buf
|
231
|
+
end
|
232
|
+
|
233
|
+
# Returns true if the scanner cannot consume next token
|
234
|
+
def stuck? #: bool
|
235
|
+
lookahead1.nil? && lookahead2.nil?
|
236
|
+
end
|
237
|
+
|
238
|
+
# Skips characters
|
239
|
+
#
|
240
|
+
# This method ensures the `current_position` will be the given `position`.
|
241
|
+
#
|
242
|
+
# @rbs position: Integer -- The new position
|
243
|
+
# @rbs tree: AST::Tree -- Tree to insert trivia tokens
|
244
|
+
# @rbs return: void
|
245
|
+
def reset(position, tree)
|
246
|
+
if scanner.charpos > position
|
247
|
+
scanner.reset()
|
248
|
+
end
|
249
|
+
|
250
|
+
skips = position - scanner.charpos
|
251
|
+
|
252
|
+
if scanner.rest_size < skips
|
253
|
+
raise "The position is bigger than the size of the rest of the input: input size=#{scanner.string.size}, position=#{position}"
|
254
|
+
end
|
255
|
+
|
256
|
+
scanner.skip(/.{#{skips}}/)
|
257
|
+
|
258
|
+
@lookahead_tokens = [[], nil, [], nil]
|
259
|
+
|
260
|
+
advance(tree)
|
261
|
+
advance(tree)
|
262
|
+
end
|
263
|
+
|
264
|
+
def rest #: String
|
265
|
+
buf = +""
|
266
|
+
lookahead_tokens[0].each {|_, s| buf << s }
|
267
|
+
buf << lookahead1[1] if lookahead1
|
268
|
+
lookahead_tokens[2].each {|_, s| buf << s }
|
269
|
+
buf << lookahead2[1] if lookahead2
|
270
|
+
buf << scanner.rest
|
271
|
+
buf
|
272
|
+
end
|
273
|
+
|
274
|
+
# Consume given token type and inserts the token to the tree or `nil`
|
275
|
+
#
|
276
|
+
# @rbs *types: Symbol
|
277
|
+
# @rbs tree: AST::Tree
|
278
|
+
# @rbs return: void
|
279
|
+
def consume_token(*types, tree:)
|
280
|
+
if type?(*types)
|
281
|
+
advance(tree, eat: true)
|
282
|
+
else
|
283
|
+
tree << nil
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Consume given token type and inserts the token to the tree or raise
|
288
|
+
#
|
289
|
+
# @rbs *types: Symbol
|
290
|
+
# @rbs tree: AST::Tree
|
291
|
+
# @rbs return: void
|
292
|
+
def consume_token!(*types, tree:)
|
293
|
+
type!(*types)
|
294
|
+
advance(tree, eat: true)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Test if current token has specified `type`
|
298
|
+
#
|
299
|
+
# @rbs *types: Symbol
|
300
|
+
# @rbs return: bool
|
301
|
+
def type?(*types)
|
302
|
+
types.any? { lookahead1 && lookahead1[0] == _1 }
|
303
|
+
end
|
304
|
+
|
305
|
+
# Test if lookahead2 token have specified `type`
|
306
|
+
#
|
307
|
+
# @rbs *types: Symbol -- The type of the lookahead2 token
|
308
|
+
# @rbs return: bool
|
309
|
+
def type2?(*types)
|
310
|
+
types.any? { lookahead2 && lookahead2[0] == _1 }
|
311
|
+
end
|
312
|
+
|
313
|
+
# Ensure current token is one of the specified in types
|
314
|
+
#
|
315
|
+
# @rbs *types: Symbol
|
316
|
+
# @rbs return: void
|
317
|
+
def type!(*types)
|
318
|
+
raise "Unexpected token: #{lookahead1&.[](0)}, where expected token: #{types.join(",")}" unless type?(*types)
|
319
|
+
end
|
320
|
+
|
321
|
+
# Reset the current_token to incoming comment `--`
|
322
|
+
#
|
323
|
+
# Reset to the end of the input if `--` token cannot be found.
|
324
|
+
#
|
325
|
+
# @rbs return: String -- String that is skipped
|
326
|
+
def skip_to_comment
|
327
|
+
prefix = +""
|
328
|
+
|
329
|
+
lookahead_tokens[0].each { prefix << _1[1] }
|
330
|
+
lookahead_tokens[0].clear
|
331
|
+
|
332
|
+
if type?(K_MINUS2)
|
333
|
+
return prefix
|
334
|
+
end
|
335
|
+
|
336
|
+
prefix << lookahead1[1] if lookahead1
|
337
|
+
lookahead_tokens[2].each { prefix << _1[1] }
|
338
|
+
lookahead_tokens[2].clear
|
339
|
+
|
340
|
+
if type2?(K_MINUS2)
|
341
|
+
advance(_ = nil) # The tree is unused because no trivia tokens are left
|
342
|
+
return prefix
|
343
|
+
end
|
344
|
+
|
345
|
+
prefix << lookahead2[1] if lookahead2
|
346
|
+
|
347
|
+
if string = scanner.scan_until(/--/)
|
348
|
+
@lookahead_tokens = [[], nil, [], [K_MINUS2, "--"]]
|
349
|
+
advance(_ = nil) # The tree is unused because no trivia tokens are left
|
350
|
+
prefix + string.delete_suffix("--")
|
351
|
+
else
|
352
|
+
s = scanner.rest
|
353
|
+
@lookahead_tokens = [[], [K_EOF, ""], [], nil]
|
354
|
+
scanner.terminate
|
355
|
+
prefix + s
|
356
|
+
end
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|