jruby-prism-parser 0.24.0-java → 1.4.0-java
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/BSDmakefile +58 -0
- data/CHANGELOG.md +269 -1
- data/CONTRIBUTING.md +0 -4
- data/Makefile +25 -18
- data/README.md +57 -6
- data/config.yml +1724 -140
- data/docs/build_system.md +39 -11
- data/docs/configuration.md +4 -0
- data/docs/cruby_compilation.md +1 -1
- data/docs/fuzzing.md +1 -1
- data/docs/parser_translation.md +14 -9
- data/docs/parsing_rules.md +4 -1
- data/docs/releasing.md +8 -10
- data/docs/relocation.md +34 -0
- data/docs/ripper_translation.md +72 -0
- data/docs/ruby_api.md +2 -1
- data/docs/serialization.md +29 -5
- data/ext/prism/api_node.c +3395 -1999
- data/ext/prism/api_pack.c +9 -0
- data/ext/prism/extconf.rb +55 -34
- data/ext/prism/extension.c +597 -346
- data/ext/prism/extension.h +6 -5
- data/include/prism/ast.h +2612 -455
- data/include/prism/defines.h +160 -2
- data/include/prism/diagnostic.h +188 -76
- data/include/prism/encoding.h +22 -4
- data/include/prism/node.h +89 -17
- data/include/prism/options.h +224 -12
- data/include/prism/pack.h +11 -0
- data/include/prism/parser.h +267 -66
- data/include/prism/prettyprint.h +8 -0
- data/include/prism/regexp.h +18 -8
- data/include/prism/static_literals.h +121 -0
- data/include/prism/util/pm_buffer.h +75 -2
- data/include/prism/util/pm_char.h +1 -2
- data/include/prism/util/pm_constant_pool.h +18 -9
- data/include/prism/util/pm_integer.h +126 -0
- data/include/prism/util/pm_list.h +1 -1
- data/include/prism/util/pm_newline_list.h +19 -0
- data/include/prism/util/pm_string.h +48 -8
- data/include/prism/version.h +3 -3
- data/include/prism.h +99 -5
- data/jruby-prism.jar +0 -0
- data/lib/prism/compiler.rb +11 -1
- data/lib/prism/desugar_compiler.rb +113 -74
- data/lib/prism/dispatcher.rb +45 -1
- data/lib/prism/dot_visitor.rb +201 -77
- data/lib/prism/dsl.rb +673 -461
- data/lib/prism/ffi.rb +233 -45
- data/lib/prism/inspect_visitor.rb +2389 -0
- data/lib/prism/lex_compat.rb +35 -16
- data/lib/prism/mutation_compiler.rb +24 -8
- data/lib/prism/node.rb +7731 -8460
- data/lib/prism/node_ext.rb +328 -32
- data/lib/prism/pack.rb +4 -0
- data/lib/prism/parse_result/comments.rb +34 -24
- data/lib/prism/parse_result/errors.rb +65 -0
- data/lib/prism/parse_result/newlines.rb +102 -12
- data/lib/prism/parse_result.rb +448 -44
- data/lib/prism/pattern.rb +28 -10
- data/lib/prism/polyfill/append_as_bytes.rb +15 -0
- data/lib/prism/polyfill/byteindex.rb +13 -0
- data/lib/prism/polyfill/unpack1.rb +14 -0
- data/lib/prism/reflection.rb +413 -0
- data/lib/prism/relocation.rb +504 -0
- data/lib/prism/serialize.rb +1940 -1198
- data/lib/prism/string_query.rb +30 -0
- data/lib/prism/translation/parser/builder.rb +61 -0
- data/lib/prism/translation/parser/compiler.rb +569 -195
- data/lib/prism/translation/parser/lexer.rb +516 -39
- data/lib/prism/translation/parser.rb +177 -12
- data/lib/prism/translation/parser33.rb +1 -1
- data/lib/prism/translation/parser34.rb +1 -1
- data/lib/prism/translation/parser35.rb +12 -0
- data/lib/prism/translation/ripper/sexp.rb +125 -0
- data/lib/prism/translation/ripper/shim.rb +5 -0
- data/lib/prism/translation/ripper.rb +3224 -462
- data/lib/prism/translation/ruby_parser.rb +194 -69
- data/lib/prism/translation.rb +4 -1
- data/lib/prism/version.rb +1 -1
- data/lib/prism/visitor.rb +13 -0
- data/lib/prism.rb +17 -27
- data/prism.gemspec +57 -17
- data/rbi/prism/compiler.rbi +12 -0
- data/rbi/prism/dsl.rbi +524 -0
- data/rbi/prism/inspect_visitor.rbi +12 -0
- data/rbi/prism/node.rbi +8722 -0
- data/rbi/prism/node_ext.rbi +107 -0
- data/rbi/prism/parse_result.rbi +404 -0
- data/rbi/prism/reflection.rbi +58 -0
- data/rbi/prism/string_query.rbi +12 -0
- data/rbi/prism/translation/parser.rbi +11 -0
- data/rbi/prism/translation/parser33.rbi +6 -0
- data/rbi/prism/translation/parser34.rbi +6 -0
- data/rbi/prism/translation/parser35.rbi +6 -0
- data/rbi/prism/translation/ripper.rbi +15 -0
- data/rbi/prism/visitor.rbi +473 -0
- data/rbi/prism.rbi +44 -7745
- data/sig/prism/compiler.rbs +9 -0
- data/sig/prism/dispatcher.rbs +16 -0
- data/sig/prism/dot_visitor.rbs +6 -0
- data/sig/prism/dsl.rbs +351 -0
- data/sig/prism/inspect_visitor.rbs +22 -0
- data/sig/prism/lex_compat.rbs +10 -0
- data/sig/prism/mutation_compiler.rbs +159 -0
- data/sig/prism/node.rbs +3614 -0
- data/sig/prism/node_ext.rbs +82 -0
- data/sig/prism/pack.rbs +43 -0
- data/sig/prism/parse_result.rbs +192 -0
- data/sig/prism/pattern.rbs +13 -0
- data/sig/prism/reflection.rbs +50 -0
- data/sig/prism/relocation.rbs +185 -0
- data/sig/prism/serialize.rbs +8 -0
- data/sig/prism/string_query.rbs +11 -0
- data/sig/prism/visitor.rbs +169 -0
- data/sig/prism.rbs +248 -4767
- data/src/diagnostic.c +672 -230
- data/src/encoding.c +211 -108
- data/src/node.c +7541 -1653
- data/src/options.c +135 -20
- data/src/pack.c +33 -17
- data/src/prettyprint.c +1543 -1485
- data/src/prism.c +7813 -3050
- data/src/regexp.c +225 -73
- data/src/serialize.c +101 -77
- data/src/static_literals.c +617 -0
- data/src/token_type.c +14 -13
- data/src/util/pm_buffer.c +187 -20
- data/src/util/pm_char.c +5 -5
- data/src/util/pm_constant_pool.c +39 -19
- data/src/util/pm_integer.c +670 -0
- data/src/util/pm_list.c +1 -1
- data/src/util/pm_newline_list.c +43 -5
- data/src/util/pm_string.c +213 -33
- data/src/util/pm_strncasecmp.c +13 -1
- data/src/util/pm_strpbrk.c +32 -6
- metadata +55 -19
- data/docs/ripper.md +0 -36
- data/include/prism/util/pm_state_stack.h +0 -42
- data/include/prism/util/pm_string_list.h +0 -44
- data/lib/prism/debug.rb +0 -206
- data/lib/prism/node_inspector.rb +0 -68
- data/lib/prism/translation/parser/rubocop.rb +0 -45
- data/rbi/prism_static.rbi +0 -207
- data/sig/prism_static.rbs +0 -201
- data/src/util/pm_state_stack.c +0 -25
- data/src/util/pm_string_list.c +0 -28
@@ -4,67 +4,436 @@ require "ripper"
|
|
4
4
|
|
5
5
|
module Prism
|
6
6
|
module Translation
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
7
|
+
# This class provides a compatibility layer between prism and Ripper. It
|
8
|
+
# functions by parsing the entire tree first and then walking it and
|
9
|
+
# executing each of the Ripper callbacks as it goes. To use this class, you
|
10
|
+
# treat `Prism::Translation::Ripper` effectively as you would treat the
|
11
|
+
# `Ripper` class.
|
10
12
|
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
13
|
+
# Note that this class will serve the most common use cases, but Ripper's
|
14
|
+
# API is extensive and undocumented. It relies on reporting the state of the
|
15
|
+
# parser at any given time. We do our best to replicate that here, but
|
16
|
+
# because it is a different architecture it is not possible to perfectly
|
17
|
+
# replicate the behavior of Ripper.
|
14
18
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
19
|
+
# The main known difference is that we may omit dispatching some events in
|
20
|
+
# some cases. This impacts the following events:
|
21
|
+
#
|
22
|
+
# - on_assign_error
|
23
|
+
# - on_comma
|
24
|
+
# - on_ignored_nl
|
25
|
+
# - on_ignored_sp
|
26
|
+
# - on_kw
|
27
|
+
# - on_label_end
|
28
|
+
# - on_lbrace
|
29
|
+
# - on_lbracket
|
30
|
+
# - on_lparen
|
31
|
+
# - on_nl
|
32
|
+
# - on_op
|
33
|
+
# - on_operator_ambiguous
|
34
|
+
# - on_rbrace
|
35
|
+
# - on_rbracket
|
36
|
+
# - on_rparen
|
37
|
+
# - on_semicolon
|
38
|
+
# - on_sp
|
39
|
+
# - on_symbeg
|
40
|
+
# - on_tstring_beg
|
41
|
+
# - on_tstring_end
|
18
42
|
#
|
19
|
-
# To use this class, you treat `Prism::Translation::Ripper` effectively as you would
|
20
|
-
# treat the `Ripper` class.
|
21
43
|
class Ripper < Compiler
|
22
|
-
#
|
23
|
-
#
|
24
|
-
|
25
|
-
|
44
|
+
# Parses the given Ruby program read from +src+.
|
45
|
+
# +src+ must be a String or an IO or a object with a #gets method.
|
46
|
+
def self.parse(src, filename = "(ripper)", lineno = 1)
|
47
|
+
new(src, filename, lineno).parse
|
48
|
+
end
|
26
49
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
50
|
+
# Tokenizes the Ruby program and returns an array of an array,
|
51
|
+
# which is formatted like
|
52
|
+
# <code>[[lineno, column], type, token, state]</code>.
|
53
|
+
# The +filename+ argument is mostly ignored.
|
54
|
+
# By default, this method does not handle syntax errors in +src+,
|
55
|
+
# use the +raise_errors+ keyword to raise a SyntaxError for an error in +src+.
|
56
|
+
#
|
57
|
+
# require "ripper"
|
58
|
+
# require "pp"
|
59
|
+
#
|
60
|
+
# pp Ripper.lex("def m(a) nil end")
|
61
|
+
# #=> [[[1, 0], :on_kw, "def", FNAME ],
|
62
|
+
# [[1, 3], :on_sp, " ", FNAME ],
|
63
|
+
# [[1, 4], :on_ident, "m", ENDFN ],
|
64
|
+
# [[1, 5], :on_lparen, "(", BEG|LABEL],
|
65
|
+
# [[1, 6], :on_ident, "a", ARG ],
|
66
|
+
# [[1, 7], :on_rparen, ")", ENDFN ],
|
67
|
+
# [[1, 8], :on_sp, " ", BEG ],
|
68
|
+
# [[1, 9], :on_kw, "nil", END ],
|
69
|
+
# [[1, 12], :on_sp, " ", END ],
|
70
|
+
# [[1, 13], :on_kw, "end", END ]]
|
71
|
+
#
|
72
|
+
def self.lex(src, filename = "-", lineno = 1, raise_errors: false)
|
73
|
+
result = Prism.lex_compat(src, filepath: filename, line: lineno)
|
32
74
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
75
|
+
if result.failure? && raise_errors
|
76
|
+
raise SyntaxError, result.errors.first.message
|
77
|
+
else
|
78
|
+
result.value
|
37
79
|
end
|
38
80
|
end
|
39
81
|
|
40
|
-
# This
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
82
|
+
# This contains a table of all of the parser events and their
|
83
|
+
# corresponding arity.
|
84
|
+
PARSER_EVENT_TABLE = {
|
85
|
+
BEGIN: 1,
|
86
|
+
END: 1,
|
87
|
+
alias: 2,
|
88
|
+
alias_error: 2,
|
89
|
+
aref: 2,
|
90
|
+
aref_field: 2,
|
91
|
+
arg_ambiguous: 1,
|
92
|
+
arg_paren: 1,
|
93
|
+
args_add: 2,
|
94
|
+
args_add_block: 2,
|
95
|
+
args_add_star: 2,
|
96
|
+
args_forward: 0,
|
97
|
+
args_new: 0,
|
98
|
+
array: 1,
|
99
|
+
aryptn: 4,
|
100
|
+
assign: 2,
|
101
|
+
assign_error: 2,
|
102
|
+
assoc_new: 2,
|
103
|
+
assoc_splat: 1,
|
104
|
+
assoclist_from_args: 1,
|
105
|
+
bare_assoc_hash: 1,
|
106
|
+
begin: 1,
|
107
|
+
binary: 3,
|
108
|
+
block_var: 2,
|
109
|
+
blockarg: 1,
|
110
|
+
bodystmt: 4,
|
111
|
+
brace_block: 2,
|
112
|
+
break: 1,
|
113
|
+
call: 3,
|
114
|
+
case: 2,
|
115
|
+
class: 3,
|
116
|
+
class_name_error: 2,
|
117
|
+
command: 2,
|
118
|
+
command_call: 4,
|
119
|
+
const_path_field: 2,
|
120
|
+
const_path_ref: 2,
|
121
|
+
const_ref: 1,
|
122
|
+
def: 3,
|
123
|
+
defined: 1,
|
124
|
+
defs: 5,
|
125
|
+
do_block: 2,
|
126
|
+
dot2: 2,
|
127
|
+
dot3: 2,
|
128
|
+
dyna_symbol: 1,
|
129
|
+
else: 1,
|
130
|
+
elsif: 3,
|
131
|
+
ensure: 1,
|
132
|
+
excessed_comma: 0,
|
133
|
+
fcall: 1,
|
134
|
+
field: 3,
|
135
|
+
fndptn: 4,
|
136
|
+
for: 3,
|
137
|
+
hash: 1,
|
138
|
+
heredoc_dedent: 2,
|
139
|
+
hshptn: 3,
|
140
|
+
if: 3,
|
141
|
+
if_mod: 2,
|
142
|
+
ifop: 3,
|
143
|
+
in: 3,
|
144
|
+
kwrest_param: 1,
|
145
|
+
lambda: 2,
|
146
|
+
magic_comment: 2,
|
147
|
+
massign: 2,
|
148
|
+
method_add_arg: 2,
|
149
|
+
method_add_block: 2,
|
150
|
+
mlhs_add: 2,
|
151
|
+
mlhs_add_post: 2,
|
152
|
+
mlhs_add_star: 2,
|
153
|
+
mlhs_new: 0,
|
154
|
+
mlhs_paren: 1,
|
155
|
+
module: 2,
|
156
|
+
mrhs_add: 2,
|
157
|
+
mrhs_add_star: 2,
|
158
|
+
mrhs_new: 0,
|
159
|
+
mrhs_new_from_args: 1,
|
160
|
+
next: 1,
|
161
|
+
nokw_param: 1,
|
162
|
+
opassign: 3,
|
163
|
+
operator_ambiguous: 2,
|
164
|
+
param_error: 2,
|
165
|
+
params: 7,
|
166
|
+
paren: 1,
|
167
|
+
parse_error: 1,
|
168
|
+
program: 1,
|
169
|
+
qsymbols_add: 2,
|
170
|
+
qsymbols_new: 0,
|
171
|
+
qwords_add: 2,
|
172
|
+
qwords_new: 0,
|
173
|
+
redo: 0,
|
174
|
+
regexp_add: 2,
|
175
|
+
regexp_literal: 2,
|
176
|
+
regexp_new: 0,
|
177
|
+
rescue: 4,
|
178
|
+
rescue_mod: 2,
|
179
|
+
rest_param: 1,
|
180
|
+
retry: 0,
|
181
|
+
return: 1,
|
182
|
+
return0: 0,
|
183
|
+
sclass: 2,
|
184
|
+
stmts_add: 2,
|
185
|
+
stmts_new: 0,
|
186
|
+
string_add: 2,
|
187
|
+
string_concat: 2,
|
188
|
+
string_content: 0,
|
189
|
+
string_dvar: 1,
|
190
|
+
string_embexpr: 1,
|
191
|
+
string_literal: 1,
|
192
|
+
super: 1,
|
193
|
+
symbol: 1,
|
194
|
+
symbol_literal: 1,
|
195
|
+
symbols_add: 2,
|
196
|
+
symbols_new: 0,
|
197
|
+
top_const_field: 1,
|
198
|
+
top_const_ref: 1,
|
199
|
+
unary: 2,
|
200
|
+
undef: 1,
|
201
|
+
unless: 3,
|
202
|
+
unless_mod: 2,
|
203
|
+
until: 2,
|
204
|
+
until_mod: 2,
|
205
|
+
var_alias: 2,
|
206
|
+
var_field: 1,
|
207
|
+
var_ref: 1,
|
208
|
+
vcall: 1,
|
209
|
+
void_stmt: 0,
|
210
|
+
when: 3,
|
211
|
+
while: 2,
|
212
|
+
while_mod: 2,
|
213
|
+
word_add: 2,
|
214
|
+
word_new: 0,
|
215
|
+
words_add: 2,
|
216
|
+
words_new: 0,
|
217
|
+
xstring_add: 2,
|
218
|
+
xstring_literal: 1,
|
219
|
+
xstring_new: 0,
|
220
|
+
yield: 1,
|
221
|
+
yield0: 0,
|
222
|
+
zsuper: 0
|
223
|
+
}
|
224
|
+
|
225
|
+
# This contains a table of all of the scanner events and their
|
226
|
+
# corresponding arity.
|
227
|
+
SCANNER_EVENT_TABLE = {
|
228
|
+
CHAR: 1,
|
229
|
+
__end__: 1,
|
230
|
+
backref: 1,
|
231
|
+
backtick: 1,
|
232
|
+
comma: 1,
|
233
|
+
comment: 1,
|
234
|
+
const: 1,
|
235
|
+
cvar: 1,
|
236
|
+
embdoc: 1,
|
237
|
+
embdoc_beg: 1,
|
238
|
+
embdoc_end: 1,
|
239
|
+
embexpr_beg: 1,
|
240
|
+
embexpr_end: 1,
|
241
|
+
embvar: 1,
|
242
|
+
float: 1,
|
243
|
+
gvar: 1,
|
244
|
+
heredoc_beg: 1,
|
245
|
+
heredoc_end: 1,
|
246
|
+
ident: 1,
|
247
|
+
ignored_nl: 1,
|
248
|
+
imaginary: 1,
|
249
|
+
int: 1,
|
250
|
+
ivar: 1,
|
251
|
+
kw: 1,
|
252
|
+
label: 1,
|
253
|
+
label_end: 1,
|
254
|
+
lbrace: 1,
|
255
|
+
lbracket: 1,
|
256
|
+
lparen: 1,
|
257
|
+
nl: 1,
|
258
|
+
op: 1,
|
259
|
+
period: 1,
|
260
|
+
qsymbols_beg: 1,
|
261
|
+
qwords_beg: 1,
|
262
|
+
rational: 1,
|
263
|
+
rbrace: 1,
|
264
|
+
rbracket: 1,
|
265
|
+
regexp_beg: 1,
|
266
|
+
regexp_end: 1,
|
267
|
+
rparen: 1,
|
268
|
+
semicolon: 1,
|
269
|
+
sp: 1,
|
270
|
+
symbeg: 1,
|
271
|
+
symbols_beg: 1,
|
272
|
+
tlambda: 1,
|
273
|
+
tlambeg: 1,
|
274
|
+
tstring_beg: 1,
|
275
|
+
tstring_content: 1,
|
276
|
+
tstring_end: 1,
|
277
|
+
words_beg: 1,
|
278
|
+
words_sep: 1,
|
279
|
+
ignored_sp: 1
|
280
|
+
}
|
281
|
+
|
282
|
+
# This array contains name of parser events.
|
283
|
+
PARSER_EVENTS = PARSER_EVENT_TABLE.keys
|
284
|
+
|
285
|
+
# This array contains name of scanner events.
|
286
|
+
SCANNER_EVENTS = SCANNER_EVENT_TABLE.keys
|
287
|
+
|
288
|
+
# This array contains name of all ripper events.
|
289
|
+
EVENTS = PARSER_EVENTS + SCANNER_EVENTS
|
290
|
+
|
291
|
+
# A list of all of the Ruby keywords.
|
292
|
+
KEYWORDS = [
|
293
|
+
"alias",
|
294
|
+
"and",
|
295
|
+
"begin",
|
296
|
+
"BEGIN",
|
297
|
+
"break",
|
298
|
+
"case",
|
299
|
+
"class",
|
300
|
+
"def",
|
301
|
+
"defined?",
|
302
|
+
"do",
|
303
|
+
"else",
|
304
|
+
"elsif",
|
305
|
+
"end",
|
306
|
+
"END",
|
307
|
+
"ensure",
|
308
|
+
"false",
|
309
|
+
"for",
|
310
|
+
"if",
|
311
|
+
"in",
|
312
|
+
"module",
|
313
|
+
"next",
|
314
|
+
"nil",
|
315
|
+
"not",
|
316
|
+
"or",
|
317
|
+
"redo",
|
318
|
+
"rescue",
|
319
|
+
"retry",
|
320
|
+
"return",
|
321
|
+
"self",
|
322
|
+
"super",
|
323
|
+
"then",
|
324
|
+
"true",
|
325
|
+
"undef",
|
326
|
+
"unless",
|
327
|
+
"until",
|
328
|
+
"when",
|
329
|
+
"while",
|
330
|
+
"yield",
|
331
|
+
"__ENCODING__",
|
332
|
+
"__FILE__",
|
333
|
+
"__LINE__"
|
334
|
+
]
|
335
|
+
|
336
|
+
# A list of all of the Ruby binary operators.
|
337
|
+
BINARY_OPERATORS = [
|
338
|
+
:!=,
|
339
|
+
:!~,
|
340
|
+
:=~,
|
341
|
+
:==,
|
342
|
+
:===,
|
343
|
+
:<=>,
|
344
|
+
:>,
|
345
|
+
:>=,
|
346
|
+
:<,
|
347
|
+
:<=,
|
348
|
+
:&,
|
349
|
+
:|,
|
350
|
+
:^,
|
351
|
+
:>>,
|
352
|
+
:<<,
|
353
|
+
:-,
|
354
|
+
:+,
|
355
|
+
:%,
|
356
|
+
:/,
|
357
|
+
:*,
|
358
|
+
:**
|
359
|
+
]
|
45
360
|
|
46
|
-
|
47
|
-
[]
|
48
|
-
end
|
361
|
+
private_constant :KEYWORDS, :BINARY_OPERATORS
|
49
362
|
|
50
|
-
|
51
|
-
|
52
|
-
|
363
|
+
# Parses +src+ and create S-exp tree.
|
364
|
+
# Returns more readable tree rather than Ripper.sexp_raw.
|
365
|
+
# This method is mainly for developer use.
|
366
|
+
# The +filename+ argument is mostly ignored.
|
367
|
+
# By default, this method does not handle syntax errors in +src+,
|
368
|
+
# returning +nil+ in such cases. Use the +raise_errors+ keyword
|
369
|
+
# to raise a SyntaxError for an error in +src+.
|
370
|
+
#
|
371
|
+
# require "ripper"
|
372
|
+
# require "pp"
|
373
|
+
#
|
374
|
+
# pp Ripper.sexp("def m(a) nil end")
|
375
|
+
# #=> [:program,
|
376
|
+
# [[:def,
|
377
|
+
# [:@ident, "m", [1, 4]],
|
378
|
+
# [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil, nil, nil, nil]],
|
379
|
+
# [:bodystmt, [[:var_ref, [:@kw, "nil", [1, 9]]]], nil, nil, nil]]]]
|
380
|
+
#
|
381
|
+
def self.sexp(src, filename = "-", lineno = 1, raise_errors: false)
|
382
|
+
builder = SexpBuilderPP.new(src, filename, lineno)
|
383
|
+
sexp = builder.parse
|
384
|
+
if builder.error?
|
385
|
+
if raise_errors
|
386
|
+
raise SyntaxError, builder.error
|
387
|
+
end
|
388
|
+
else
|
389
|
+
sexp
|
53
390
|
end
|
391
|
+
end
|
54
392
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
393
|
+
# Parses +src+ and create S-exp tree.
|
394
|
+
# This method is mainly for developer use.
|
395
|
+
# The +filename+ argument is mostly ignored.
|
396
|
+
# By default, this method does not handle syntax errors in +src+,
|
397
|
+
# returning +nil+ in such cases. Use the +raise_errors+ keyword
|
398
|
+
# to raise a SyntaxError for an error in +src+.
|
399
|
+
#
|
400
|
+
# require "ripper"
|
401
|
+
# require "pp"
|
402
|
+
#
|
403
|
+
# pp Ripper.sexp_raw("def m(a) nil end")
|
404
|
+
# #=> [:program,
|
405
|
+
# [:stmts_add,
|
406
|
+
# [:stmts_new],
|
407
|
+
# [:def,
|
408
|
+
# [:@ident, "m", [1, 4]],
|
409
|
+
# [:paren, [:params, [[:@ident, "a", [1, 6]]], nil, nil, nil]],
|
410
|
+
# [:bodystmt,
|
411
|
+
# [:stmts_add, [:stmts_new], [:var_ref, [:@kw, "nil", [1, 9]]]],
|
412
|
+
# nil,
|
413
|
+
# nil,
|
414
|
+
# nil]]]]
|
415
|
+
#
|
416
|
+
def self.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false)
|
417
|
+
builder = SexpBuilder.new(src, filename, lineno)
|
418
|
+
sexp = builder.parse
|
419
|
+
if builder.error?
|
420
|
+
if raise_errors
|
421
|
+
raise SyntaxError, builder.error
|
61
422
|
end
|
423
|
+
else
|
424
|
+
sexp
|
62
425
|
end
|
63
426
|
end
|
64
427
|
|
428
|
+
autoload :SexpBuilder, "prism/translation/ripper/sexp"
|
429
|
+
autoload :SexpBuilderPP, "prism/translation/ripper/sexp"
|
430
|
+
|
65
431
|
# The source that is being parsed.
|
66
432
|
attr_reader :source
|
67
433
|
|
434
|
+
# The filename of the source being parsed.
|
435
|
+
attr_reader :filename
|
436
|
+
|
68
437
|
# The current line number of the parser.
|
69
438
|
attr_reader :lineno
|
70
439
|
|
@@ -72,16 +441,17 @@ module Prism
|
|
72
441
|
attr_reader :column
|
73
442
|
|
74
443
|
# Create a new Translation::Ripper object with the given source.
|
75
|
-
def initialize(source)
|
444
|
+
def initialize(source, filename = "(ripper)", lineno = 1)
|
76
445
|
@source = source
|
446
|
+
@filename = filename
|
447
|
+
@lineno = lineno
|
448
|
+
@column = 0
|
77
449
|
@result = nil
|
78
|
-
@lineno = nil
|
79
|
-
@column = nil
|
80
450
|
end
|
81
451
|
|
82
|
-
|
452
|
+
##########################################################################
|
83
453
|
# Public interface
|
84
|
-
|
454
|
+
##########################################################################
|
85
455
|
|
86
456
|
# True if the parser encountered an error during parsing.
|
87
457
|
def error?
|
@@ -90,13 +460,80 @@ module Prism
|
|
90
460
|
|
91
461
|
# Parse the source and return the result.
|
92
462
|
def parse
|
463
|
+
result.comments.each do |comment|
|
464
|
+
location = comment.location
|
465
|
+
bounds(location)
|
466
|
+
|
467
|
+
if comment.is_a?(InlineComment)
|
468
|
+
on_comment(comment.slice)
|
469
|
+
else
|
470
|
+
offset = location.start_offset
|
471
|
+
lines = comment.slice.lines
|
472
|
+
|
473
|
+
lines.each_with_index do |line, index|
|
474
|
+
bounds(location.copy(start_offset: offset))
|
475
|
+
|
476
|
+
if index == 0
|
477
|
+
on_embdoc_beg(line)
|
478
|
+
elsif index == lines.size - 1
|
479
|
+
on_embdoc_end(line)
|
480
|
+
else
|
481
|
+
on_embdoc(line)
|
482
|
+
end
|
483
|
+
|
484
|
+
offset += line.bytesize
|
485
|
+
end
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
93
489
|
result.magic_comments.each do |magic_comment|
|
94
490
|
on_magic_comment(magic_comment.key, magic_comment.value)
|
95
491
|
end
|
96
492
|
|
493
|
+
unless result.data_loc.nil?
|
494
|
+
on___end__(result.data_loc.slice.each_line.first)
|
495
|
+
end
|
496
|
+
|
497
|
+
result.warnings.each do |warning|
|
498
|
+
bounds(warning.location)
|
499
|
+
|
500
|
+
if warning.level == :default
|
501
|
+
warning(warning.message)
|
502
|
+
else
|
503
|
+
case warning.type
|
504
|
+
when :ambiguous_first_argument_plus
|
505
|
+
on_arg_ambiguous("+")
|
506
|
+
when :ambiguous_first_argument_minus
|
507
|
+
on_arg_ambiguous("-")
|
508
|
+
when :ambiguous_slash
|
509
|
+
on_arg_ambiguous("/")
|
510
|
+
else
|
511
|
+
warn(warning.message)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
97
516
|
if error?
|
98
517
|
result.errors.each do |error|
|
99
|
-
|
518
|
+
location = error.location
|
519
|
+
bounds(location)
|
520
|
+
|
521
|
+
case error.type
|
522
|
+
when :alias_argument
|
523
|
+
on_alias_error("can't make alias for the number variables", location.slice)
|
524
|
+
when :argument_formal_class
|
525
|
+
on_param_error("formal argument cannot be a class variable", location.slice)
|
526
|
+
when :argument_format_constant
|
527
|
+
on_param_error("formal argument cannot be a constant", location.slice)
|
528
|
+
when :argument_formal_global
|
529
|
+
on_param_error("formal argument cannot be a global variable", location.slice)
|
530
|
+
when :argument_formal_ivar
|
531
|
+
on_param_error("formal argument cannot be an instance variable", location.slice)
|
532
|
+
when :class_name, :module_name
|
533
|
+
on_class_name_error("class/module name must be CONSTANT", location.slice)
|
534
|
+
else
|
535
|
+
on_parse_error(error.message)
|
536
|
+
end
|
100
537
|
end
|
101
538
|
|
102
539
|
nil
|
@@ -105,556 +542,2841 @@ module Prism
|
|
105
542
|
end
|
106
543
|
end
|
107
544
|
|
108
|
-
|
545
|
+
##########################################################################
|
109
546
|
# Visitor methods
|
110
|
-
|
547
|
+
##########################################################################
|
548
|
+
|
549
|
+
# alias foo bar
|
550
|
+
# ^^^^^^^^^^^^^
|
551
|
+
def visit_alias_method_node(node)
|
552
|
+
new_name = visit(node.new_name)
|
553
|
+
old_name = visit(node.old_name)
|
111
554
|
|
112
|
-
# Visit an ArrayNode node.
|
113
|
-
def visit_array_node(node)
|
114
|
-
elements = visit_elements(node.elements) unless node.elements.empty?
|
115
555
|
bounds(node.location)
|
116
|
-
|
556
|
+
on_alias(new_name, old_name)
|
117
557
|
end
|
118
558
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
return visit_aref_node(node) if node.name == :[]
|
125
|
-
return visit_aref_field_node(node) if node.name == :[]=
|
126
|
-
|
127
|
-
if node.variable_call?
|
128
|
-
raise NotImplementedError unless node.receiver.nil?
|
129
|
-
|
130
|
-
bounds(node.message_loc)
|
131
|
-
return on_vcall(on_ident(node.message))
|
132
|
-
end
|
559
|
+
# alias $foo $bar
|
560
|
+
# ^^^^^^^^^^^^^^^
|
561
|
+
def visit_alias_global_variable_node(node)
|
562
|
+
new_name = visit_alias_global_variable_node_value(node.new_name)
|
563
|
+
old_name = visit_alias_global_variable_node_value(node.old_name)
|
133
564
|
|
134
|
-
|
135
|
-
|
136
|
-
|
565
|
+
bounds(node.location)
|
566
|
+
on_var_alias(new_name, old_name)
|
567
|
+
end
|
137
568
|
|
138
|
-
|
569
|
+
# Visit one side of an alias global variable node.
|
570
|
+
private def visit_alias_global_variable_node_value(node)
|
571
|
+
bounds(node.location)
|
139
572
|
|
140
|
-
|
141
|
-
|
573
|
+
case node
|
574
|
+
when BackReferenceReadNode
|
575
|
+
on_backref(node.slice)
|
576
|
+
when GlobalVariableReadNode
|
577
|
+
on_gvar(node.name.to_s)
|
142
578
|
else
|
143
|
-
|
579
|
+
raise
|
144
580
|
end
|
581
|
+
end
|
145
582
|
|
146
|
-
|
147
|
-
|
583
|
+
# foo => bar | baz
|
584
|
+
# ^^^^^^^^^
|
585
|
+
def visit_alternation_pattern_node(node)
|
586
|
+
left = visit_pattern_node(node.left)
|
587
|
+
right = visit_pattern_node(node.right)
|
148
588
|
|
149
589
|
bounds(node.location)
|
150
|
-
|
151
|
-
|
152
|
-
block_val = visit(node.block)
|
590
|
+
on_binary(left, :|, right)
|
591
|
+
end
|
153
592
|
|
154
|
-
|
593
|
+
# Visit a pattern within a pattern match. This is used to bypass the
|
594
|
+
# parenthesis node that can be used to wrap patterns.
|
595
|
+
private def visit_pattern_node(node)
|
596
|
+
if node.is_a?(ParenthesesNode)
|
597
|
+
visit(node.body)
|
155
598
|
else
|
156
|
-
|
599
|
+
visit(node)
|
157
600
|
end
|
158
601
|
end
|
159
602
|
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
end
|
166
|
-
|
167
|
-
# Visit a LocalVariableAndWriteNode.
|
168
|
-
def visit_local_variable_and_write_node(node)
|
169
|
-
visit_binary_op_assign(node)
|
170
|
-
end
|
603
|
+
# a and b
|
604
|
+
# ^^^^^^^
|
605
|
+
def visit_and_node(node)
|
606
|
+
left = visit(node.left)
|
607
|
+
right = visit(node.right)
|
171
608
|
|
172
|
-
|
173
|
-
|
174
|
-
visit_binary_op_assign(node)
|
609
|
+
bounds(node.location)
|
610
|
+
on_binary(left, node.operator.to_sym, right)
|
175
611
|
end
|
176
612
|
|
177
|
-
#
|
178
|
-
|
179
|
-
|
180
|
-
|
613
|
+
# []
|
614
|
+
# ^^
|
615
|
+
def visit_array_node(node)
|
616
|
+
case (opening = node.opening)
|
617
|
+
when /^%w/
|
618
|
+
opening_loc = node.opening_loc
|
619
|
+
bounds(opening_loc)
|
620
|
+
on_qwords_beg(opening)
|
181
621
|
|
182
|
-
|
183
|
-
|
184
|
-
bounds(node.location)
|
185
|
-
ident_val = on_ident(node.slice)
|
622
|
+
elements = on_qwords_new
|
623
|
+
previous = nil
|
186
624
|
|
187
|
-
|
188
|
-
|
625
|
+
node.elements.each do |element|
|
626
|
+
visit_words_sep(opening_loc, previous, element)
|
189
627
|
|
190
|
-
|
191
|
-
|
192
|
-
params_val = node.parameters.nil? ? nil : visit(node.parameters)
|
628
|
+
bounds(element.location)
|
629
|
+
elements = on_qwords_add(elements, on_tstring_content(element.content))
|
193
630
|
|
194
|
-
|
631
|
+
previous = element
|
632
|
+
end
|
195
633
|
|
196
|
-
|
197
|
-
|
634
|
+
bounds(node.closing_loc)
|
635
|
+
on_tstring_end(node.closing)
|
636
|
+
when /^%i/
|
637
|
+
opening_loc = node.opening_loc
|
638
|
+
bounds(opening_loc)
|
639
|
+
on_qsymbols_beg(opening)
|
198
640
|
|
199
|
-
|
200
|
-
|
201
|
-
on_block_var(visit(node.parameters), no_block_value)
|
202
|
-
end
|
641
|
+
elements = on_qsymbols_new
|
642
|
+
previous = nil
|
203
643
|
|
204
|
-
|
205
|
-
|
206
|
-
def visit_parameters_node(node)
|
207
|
-
#on_params(required, optional, nil, nil, nil, nil, nil)
|
208
|
-
on_params(visit_all(node.requireds), nil, nil, nil, nil, nil, nil)
|
209
|
-
end
|
644
|
+
node.elements.each do |element|
|
645
|
+
visit_words_sep(opening_loc, previous, element)
|
210
646
|
|
211
|
-
|
212
|
-
|
213
|
-
bounds(node.location)
|
214
|
-
on_ident(node.name.to_s)
|
215
|
-
end
|
647
|
+
bounds(element.location)
|
648
|
+
elements = on_qsymbols_add(elements, on_tstring_content(element.value))
|
216
649
|
|
217
|
-
|
218
|
-
|
219
|
-
return on_break(on_args_new) if node.arguments.nil?
|
650
|
+
previous = element
|
651
|
+
end
|
220
652
|
|
221
|
-
|
222
|
-
|
223
|
-
|
653
|
+
bounds(node.closing_loc)
|
654
|
+
on_tstring_end(node.closing)
|
655
|
+
when /^%W/
|
656
|
+
opening_loc = node.opening_loc
|
657
|
+
bounds(opening_loc)
|
658
|
+
on_words_beg(opening)
|
659
|
+
|
660
|
+
elements = on_words_new
|
661
|
+
previous = nil
|
662
|
+
|
663
|
+
node.elements.each do |element|
|
664
|
+
visit_words_sep(opening_loc, previous, element)
|
665
|
+
|
666
|
+
bounds(element.location)
|
667
|
+
elements =
|
668
|
+
on_words_add(
|
669
|
+
elements,
|
670
|
+
if element.is_a?(StringNode)
|
671
|
+
on_word_add(on_word_new, on_tstring_content(element.content))
|
672
|
+
else
|
673
|
+
element.parts.inject(on_word_new) do |word, part|
|
674
|
+
word_part =
|
675
|
+
if part.is_a?(StringNode)
|
676
|
+
bounds(part.location)
|
677
|
+
on_tstring_content(part.content)
|
678
|
+
else
|
679
|
+
visit(part)
|
680
|
+
end
|
681
|
+
|
682
|
+
on_word_add(word, word_part)
|
683
|
+
end
|
684
|
+
end
|
685
|
+
)
|
686
|
+
|
687
|
+
previous = element
|
688
|
+
end
|
224
689
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
690
|
+
bounds(node.closing_loc)
|
691
|
+
on_tstring_end(node.closing)
|
692
|
+
when /^%I/
|
693
|
+
opening_loc = node.opening_loc
|
694
|
+
bounds(opening_loc)
|
695
|
+
on_symbols_beg(opening)
|
696
|
+
|
697
|
+
elements = on_symbols_new
|
698
|
+
previous = nil
|
699
|
+
|
700
|
+
node.elements.each do |element|
|
701
|
+
visit_words_sep(opening_loc, previous, element)
|
702
|
+
|
703
|
+
bounds(element.location)
|
704
|
+
elements =
|
705
|
+
on_symbols_add(
|
706
|
+
elements,
|
707
|
+
if element.is_a?(SymbolNode)
|
708
|
+
on_word_add(on_word_new, on_tstring_content(element.value))
|
709
|
+
else
|
710
|
+
element.parts.inject(on_word_new) do |word, part|
|
711
|
+
word_part =
|
712
|
+
if part.is_a?(StringNode)
|
713
|
+
bounds(part.location)
|
714
|
+
on_tstring_content(part.content)
|
715
|
+
else
|
716
|
+
visit(part)
|
717
|
+
end
|
718
|
+
|
719
|
+
on_word_add(word, word_part)
|
720
|
+
end
|
721
|
+
end
|
722
|
+
)
|
723
|
+
|
724
|
+
previous = element
|
725
|
+
end
|
231
726
|
|
232
|
-
|
233
|
-
|
234
|
-
else
|
235
|
-
new_name_val = visit(node.new_name)
|
236
|
-
end
|
237
|
-
if node.old_name.is_a?(SymbolNode) && !node.old_name.opening
|
238
|
-
old_name_val = visit_symbol_literal_node(node.old_name, no_symbol_wrapper: true)
|
727
|
+
bounds(node.closing_loc)
|
728
|
+
on_tstring_end(node.closing)
|
239
729
|
else
|
240
|
-
|
730
|
+
bounds(node.opening_loc)
|
731
|
+
on_lbracket(opening)
|
732
|
+
|
733
|
+
elements = visit_arguments(node.elements) unless node.elements.empty?
|
734
|
+
|
735
|
+
bounds(node.closing_loc)
|
736
|
+
on_rbracket(node.closing)
|
241
737
|
end
|
242
738
|
|
243
|
-
|
739
|
+
bounds(node.location)
|
740
|
+
on_array(elements)
|
244
741
|
end
|
245
742
|
|
246
|
-
#
|
247
|
-
|
248
|
-
|
743
|
+
# Dispatch a words_sep event that contains the space between the elements
|
744
|
+
# of list literals.
|
745
|
+
private def visit_words_sep(opening_loc, previous, current)
|
746
|
+
end_offset = (previous.nil? ? opening_loc : previous.location).end_offset
|
747
|
+
start_offset = current.location.start_offset
|
748
|
+
|
749
|
+
if end_offset != start_offset
|
750
|
+
bounds(current.location.copy(start_offset: end_offset))
|
751
|
+
on_words_sep(source.byteslice(end_offset...start_offset))
|
752
|
+
end
|
249
753
|
end
|
250
754
|
|
251
|
-
# Visit a
|
252
|
-
def
|
253
|
-
bounds(
|
254
|
-
|
755
|
+
# Visit a list of elements, like the elements of an array or arguments.
|
756
|
+
private def visit_arguments(elements)
|
757
|
+
bounds(elements.first.location)
|
758
|
+
elements.inject(on_args_new) do |args, element|
|
759
|
+
arg = visit(element)
|
760
|
+
bounds(element.location)
|
761
|
+
|
762
|
+
case element
|
763
|
+
when BlockArgumentNode
|
764
|
+
on_args_add_block(args, arg)
|
765
|
+
when SplatNode
|
766
|
+
on_args_add_star(args, arg)
|
767
|
+
else
|
768
|
+
on_args_add(args, arg)
|
769
|
+
end
|
770
|
+
end
|
255
771
|
end
|
256
772
|
|
257
|
-
#
|
258
|
-
|
773
|
+
# foo => [bar]
|
774
|
+
# ^^^^^
|
775
|
+
def visit_array_pattern_node(node)
|
776
|
+
constant = visit(node.constant)
|
777
|
+
requireds = visit_all(node.requireds) if node.requireds.any?
|
778
|
+
rest =
|
779
|
+
if (rest_node = node.rest).is_a?(SplatNode)
|
780
|
+
if rest_node.expression.nil?
|
781
|
+
bounds(rest_node.location)
|
782
|
+
on_var_field(nil)
|
783
|
+
else
|
784
|
+
visit(rest_node.expression)
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
posts = visit_all(node.posts) if node.posts.any?
|
789
|
+
|
259
790
|
bounds(node.location)
|
260
|
-
|
791
|
+
on_aryptn(constant, requireds, rest, posts)
|
261
792
|
end
|
262
793
|
|
263
|
-
#
|
264
|
-
|
265
|
-
|
794
|
+
# foo(bar)
|
795
|
+
# ^^^
|
796
|
+
def visit_arguments_node(node)
|
797
|
+
arguments, _ = visit_call_node_arguments(node, nil, false)
|
798
|
+
arguments
|
266
799
|
end
|
267
800
|
|
268
|
-
#
|
269
|
-
|
270
|
-
|
271
|
-
|
801
|
+
# { a: 1 }
|
802
|
+
# ^^^^
|
803
|
+
def visit_assoc_node(node)
|
804
|
+
key = visit(node.key)
|
805
|
+
value = visit(node.value)
|
272
806
|
|
273
|
-
# Visit a TrueNode.
|
274
|
-
def visit_true_node(node)
|
275
807
|
bounds(node.location)
|
276
|
-
|
808
|
+
on_assoc_new(key, value)
|
277
809
|
end
|
278
810
|
|
279
|
-
#
|
280
|
-
|
811
|
+
# def foo(**); bar(**); end
|
812
|
+
# ^^
|
813
|
+
#
|
814
|
+
# { **foo }
|
815
|
+
# ^^^^^
|
816
|
+
def visit_assoc_splat_node(node)
|
817
|
+
value = visit(node.value)
|
818
|
+
|
281
819
|
bounds(node.location)
|
282
|
-
|
820
|
+
on_assoc_splat(value)
|
283
821
|
end
|
284
822
|
|
285
|
-
#
|
286
|
-
|
287
|
-
|
823
|
+
# $+
|
824
|
+
# ^^
|
825
|
+
def visit_back_reference_read_node(node)
|
826
|
+
bounds(node.location)
|
827
|
+
on_backref(node.slice)
|
288
828
|
end
|
289
829
|
|
290
|
-
#
|
291
|
-
|
292
|
-
|
293
|
-
|
830
|
+
# begin end
|
831
|
+
# ^^^^^^^^^
|
832
|
+
def visit_begin_node(node)
|
833
|
+
clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false)
|
294
834
|
|
295
|
-
|
296
|
-
|
297
|
-
visit_number(node) { |text| on_int(text) }
|
835
|
+
bounds(node.location)
|
836
|
+
on_begin(clauses)
|
298
837
|
end
|
299
838
|
|
300
|
-
# Visit a
|
301
|
-
def
|
302
|
-
|
303
|
-
if node.
|
839
|
+
# Visit the clauses of a begin node to form an on_bodystmt call.
|
840
|
+
private def visit_begin_node_clauses(location, node, allow_newline)
|
841
|
+
statements =
|
842
|
+
if node.statements.nil?
|
304
843
|
on_stmts_add(on_stmts_new, on_void_stmt)
|
305
844
|
else
|
306
|
-
|
845
|
+
body = node.statements.body
|
846
|
+
body.unshift(nil) if void_stmt?(location, node.statements.body[0].location, allow_newline)
|
847
|
+
|
848
|
+
bounds(node.statements.location)
|
849
|
+
visit_statements_node_body(body)
|
307
850
|
end
|
308
851
|
|
852
|
+
rescue_clause = visit(node.rescue_clause)
|
853
|
+
else_clause =
|
854
|
+
unless (else_clause_node = node.else_clause).nil?
|
855
|
+
else_statements =
|
856
|
+
if else_clause_node.statements.nil?
|
857
|
+
[nil]
|
858
|
+
else
|
859
|
+
body = else_clause_node.statements.body
|
860
|
+
body.unshift(nil) if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline)
|
861
|
+
body
|
862
|
+
end
|
863
|
+
|
864
|
+
bounds(else_clause_node.location)
|
865
|
+
visit_statements_node_body(else_statements)
|
866
|
+
end
|
867
|
+
ensure_clause = visit(node.ensure_clause)
|
868
|
+
|
309
869
|
bounds(node.location)
|
310
|
-
|
870
|
+
on_bodystmt(statements, rescue_clause, else_clause, ensure_clause)
|
311
871
|
end
|
312
872
|
|
313
|
-
# Visit a
|
314
|
-
#
|
315
|
-
def
|
316
|
-
|
317
|
-
|
318
|
-
|
873
|
+
# Visit the body of a structure that can have either a set of statements
|
874
|
+
# or statements wrapped in rescue/else/ensure.
|
875
|
+
private def visit_body_node(location, node, allow_newline = false)
|
876
|
+
case node
|
877
|
+
when nil
|
878
|
+
bounds(location)
|
879
|
+
on_bodystmt(visit_statements_node_body([nil]), nil, nil, nil)
|
880
|
+
when StatementsNode
|
881
|
+
body = [*node.body]
|
882
|
+
body.unshift(nil) if void_stmt?(location, body[0].location, allow_newline)
|
883
|
+
stmts = visit_statements_node_body(body)
|
884
|
+
|
885
|
+
bounds(node.body.first.location)
|
886
|
+
on_bodystmt(stmts, nil, nil, nil)
|
887
|
+
when BeginNode
|
888
|
+
visit_begin_node_clauses(location, node, allow_newline)
|
889
|
+
else
|
890
|
+
raise
|
891
|
+
end
|
319
892
|
end
|
320
893
|
|
321
|
-
#
|
322
|
-
|
323
|
-
|
894
|
+
# foo(&bar)
|
895
|
+
# ^^^^
|
896
|
+
def visit_block_argument_node(node)
|
897
|
+
visit(node.expression)
|
324
898
|
end
|
325
899
|
|
326
|
-
#
|
327
|
-
|
328
|
-
|
900
|
+
# foo { |; bar| }
|
901
|
+
# ^^^
|
902
|
+
def visit_block_local_variable_node(node)
|
329
903
|
bounds(node.location)
|
330
|
-
|
904
|
+
on_ident(node.name.to_s)
|
331
905
|
end
|
332
906
|
|
333
|
-
# Visit a
|
334
|
-
def
|
335
|
-
|
336
|
-
|
907
|
+
# Visit a BlockNode.
|
908
|
+
def visit_block_node(node)
|
909
|
+
braces = node.opening == "{"
|
910
|
+
parameters = visit(node.parameters)
|
337
911
|
|
338
|
-
|
339
|
-
|
340
|
-
|
912
|
+
body =
|
913
|
+
case node.body
|
914
|
+
when nil
|
915
|
+
bounds(node.location)
|
916
|
+
stmts = on_stmts_add(on_stmts_new, on_void_stmt)
|
917
|
+
|
918
|
+
bounds(node.location)
|
919
|
+
braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
|
920
|
+
when StatementsNode
|
921
|
+
stmts = node.body.body
|
922
|
+
stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
|
923
|
+
stmts = visit_statements_node_body(stmts)
|
924
|
+
|
925
|
+
bounds(node.body.location)
|
926
|
+
braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
|
927
|
+
when BeginNode
|
928
|
+
visit_body_node(node.parameters&.location || node.opening_loc, node.body)
|
929
|
+
else
|
930
|
+
raise
|
931
|
+
end
|
932
|
+
|
933
|
+
if braces
|
934
|
+
bounds(node.location)
|
935
|
+
on_brace_block(parameters, body)
|
341
936
|
else
|
342
|
-
|
937
|
+
bounds(node.location)
|
938
|
+
on_do_block(parameters, body)
|
343
939
|
end
|
344
940
|
end
|
345
941
|
|
346
|
-
#
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
on_string_literal(on_string_add(on_string_content, tstring_val))
|
356
|
-
end
|
942
|
+
# def foo(&bar); end
|
943
|
+
# ^^^^
|
944
|
+
def visit_block_parameter_node(node)
|
945
|
+
if node.name_loc.nil?
|
946
|
+
bounds(node.location)
|
947
|
+
on_blockarg(nil)
|
948
|
+
else
|
949
|
+
bounds(node.name_loc)
|
950
|
+
name = visit_token(node.name.to_s)
|
357
951
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
tstring_val = on_tstring_content(node.unescaped.to_s)
|
362
|
-
on_xstring_literal(on_xstring_add(on_xstring_new, tstring_val))
|
952
|
+
bounds(node.location)
|
953
|
+
on_blockarg(name)
|
954
|
+
end
|
363
955
|
end
|
364
956
|
|
365
|
-
#
|
366
|
-
def
|
367
|
-
|
368
|
-
|
957
|
+
# A block's parameters.
|
958
|
+
def visit_block_parameters_node(node)
|
959
|
+
parameters =
|
960
|
+
if node.parameters.nil?
|
961
|
+
on_params(nil, nil, nil, nil, nil, nil, nil)
|
962
|
+
else
|
963
|
+
visit(node.parameters)
|
964
|
+
end
|
369
965
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
966
|
+
locals =
|
967
|
+
if node.locals.any?
|
968
|
+
visit_all(node.locals)
|
969
|
+
else
|
970
|
+
false
|
971
|
+
end
|
374
972
|
|
375
|
-
|
376
|
-
|
377
|
-
visit_symbol_literal_node(node)
|
973
|
+
bounds(node.location)
|
974
|
+
on_block_var(parameters, locals)
|
378
975
|
end
|
379
976
|
|
380
|
-
#
|
381
|
-
|
382
|
-
|
383
|
-
|
977
|
+
# break
|
978
|
+
# ^^^^^
|
979
|
+
#
|
980
|
+
# break foo
|
981
|
+
# ^^^^^^^^^
|
982
|
+
def visit_break_node(node)
|
983
|
+
if node.arguments.nil?
|
984
|
+
bounds(node.location)
|
985
|
+
on_break(on_args_new)
|
986
|
+
else
|
987
|
+
arguments = visit(node.arguments)
|
384
988
|
|
385
|
-
|
386
|
-
|
387
|
-
bounds(node.location)
|
388
|
-
node.body.inject(on_stmts_new) do |stmts, stmt|
|
389
|
-
on_stmts_add(stmts, visit(stmt))
|
989
|
+
bounds(node.location)
|
990
|
+
on_break(arguments)
|
390
991
|
end
|
391
992
|
end
|
392
993
|
|
393
|
-
|
394
|
-
#
|
395
|
-
|
994
|
+
# foo
|
995
|
+
# ^^^
|
996
|
+
#
|
997
|
+
# foo.bar
|
998
|
+
# ^^^^^^^
|
999
|
+
#
|
1000
|
+
# foo.bar() {}
|
1001
|
+
# ^^^^^^^^^^^^
|
1002
|
+
def visit_call_node(node)
|
1003
|
+
if node.call_operator_loc.nil?
|
1004
|
+
case node.name
|
1005
|
+
when :[]
|
1006
|
+
receiver = visit(node.receiver)
|
1007
|
+
arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
|
396
1008
|
|
397
|
-
|
398
|
-
|
399
|
-
SexpBuilder.new(source).parse
|
400
|
-
end
|
1009
|
+
bounds(node.location)
|
1010
|
+
call = on_aref(receiver, arguments)
|
401
1011
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
1012
|
+
if block.nil?
|
1013
|
+
call
|
1014
|
+
else
|
1015
|
+
bounds(node.location)
|
1016
|
+
on_method_add_block(call, block)
|
1017
|
+
end
|
1018
|
+
when :[]=
|
1019
|
+
receiver = visit(node.receiver)
|
1020
|
+
|
1021
|
+
*arguments, last_argument = node.arguments.arguments
|
1022
|
+
arguments << node.block if !node.block.nil?
|
1023
|
+
|
1024
|
+
arguments =
|
1025
|
+
if arguments.any?
|
1026
|
+
args = visit_arguments(arguments)
|
1027
|
+
|
1028
|
+
if !node.block.nil?
|
1029
|
+
args
|
1030
|
+
else
|
1031
|
+
bounds(arguments.first.location)
|
1032
|
+
on_args_add_block(args, false)
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
bounds(node.location)
|
1037
|
+
call = on_aref_field(receiver, arguments)
|
1038
|
+
value = visit_write_value(last_argument)
|
1039
|
+
|
1040
|
+
bounds(last_argument.location)
|
1041
|
+
on_assign(call, value)
|
1042
|
+
when :-@, :+@, :~
|
1043
|
+
receiver = visit(node.receiver)
|
1044
|
+
|
1045
|
+
bounds(node.location)
|
1046
|
+
on_unary(node.name, receiver)
|
1047
|
+
when :!
|
1048
|
+
if node.message == "not"
|
1049
|
+
receiver =
|
1050
|
+
if !node.receiver.is_a?(ParenthesesNode) || !node.receiver.body.nil?
|
1051
|
+
visit(node.receiver)
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
bounds(node.location)
|
1055
|
+
on_unary(:not, receiver)
|
1056
|
+
else
|
1057
|
+
receiver = visit(node.receiver)
|
406
1058
|
|
407
|
-
|
1059
|
+
bounds(node.location)
|
1060
|
+
on_unary(:!, receiver)
|
1061
|
+
end
|
1062
|
+
when *BINARY_OPERATORS
|
1063
|
+
receiver = visit(node.receiver)
|
1064
|
+
value = visit(node.arguments.arguments.first)
|
408
1065
|
|
409
|
-
|
410
|
-
|
411
|
-
# No opening_loc can mean an operator. It can also mean a
|
412
|
-
# method call with no parentheses.
|
413
|
-
if node.message.match?(/^[[:punct:]]/)
|
414
|
-
left = visit(node.receiver)
|
415
|
-
if node.arguments&.arguments&.length == 1
|
416
|
-
right = visit(node.arguments.arguments.first)
|
417
|
-
|
418
|
-
return on_binary(left, node.name, right)
|
419
|
-
elsif !node.arguments || node.arguments.empty?
|
420
|
-
return on_unary(node.name, left)
|
1066
|
+
bounds(node.location)
|
1067
|
+
on_binary(receiver, node.name, value)
|
421
1068
|
else
|
422
|
-
|
423
|
-
|
424
|
-
elsif node.call_operator_loc.nil?
|
425
|
-
# In Ripper a method call like "puts myvar" with no parentheses is a "command".
|
426
|
-
bounds(node.message_loc)
|
427
|
-
ident_val = on_ident(node.message)
|
1069
|
+
bounds(node.message_loc)
|
1070
|
+
message = visit_token(node.message, false)
|
428
1071
|
|
429
|
-
|
430
|
-
|
431
|
-
block_val = visit(node.block)
|
432
|
-
# In these calls, even if node.arguments is nil, we still get an :args_new call.
|
433
|
-
args = if node.arguments.nil?
|
434
|
-
on_args_new
|
1072
|
+
if node.variable_call?
|
1073
|
+
on_vcall(message)
|
435
1074
|
else
|
436
|
-
|
1075
|
+
arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
|
1076
|
+
call =
|
1077
|
+
if node.opening_loc.nil? && arguments&.any?
|
1078
|
+
bounds(node.location)
|
1079
|
+
on_command(message, arguments)
|
1080
|
+
elsif !node.opening_loc.nil?
|
1081
|
+
bounds(node.location)
|
1082
|
+
on_method_add_arg(on_fcall(message), on_arg_paren(arguments))
|
1083
|
+
else
|
1084
|
+
bounds(node.location)
|
1085
|
+
on_method_add_arg(on_fcall(message), on_args_new)
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
if block.nil?
|
1089
|
+
call
|
1090
|
+
else
|
1091
|
+
bounds(node.block.location)
|
1092
|
+
on_method_add_block(call, block)
|
1093
|
+
end
|
437
1094
|
end
|
438
|
-
|
439
|
-
|
1095
|
+
end
|
1096
|
+
else
|
1097
|
+
receiver = visit(node.receiver)
|
1098
|
+
|
1099
|
+
bounds(node.call_operator_loc)
|
1100
|
+
call_operator = visit_token(node.call_operator)
|
1101
|
+
|
1102
|
+
message =
|
1103
|
+
if node.message_loc.nil?
|
1104
|
+
:call
|
1105
|
+
else
|
1106
|
+
bounds(node.message_loc)
|
1107
|
+
visit_token(node.message, false)
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
if node.name.end_with?("=") && !node.message.end_with?("=") && !node.arguments.nil? && node.block.nil?
|
1111
|
+
value = visit_write_value(node.arguments.arguments.first)
|
1112
|
+
|
1113
|
+
bounds(node.location)
|
1114
|
+
on_assign(on_field(receiver, call_operator, message), value)
|
1115
|
+
else
|
1116
|
+
arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc || node.location))
|
1117
|
+
call =
|
1118
|
+
if node.opening_loc.nil?
|
1119
|
+
bounds(node.location)
|
1120
|
+
|
1121
|
+
if node.arguments.nil? && !node.block.is_a?(BlockArgumentNode)
|
1122
|
+
on_call(receiver, call_operator, message)
|
1123
|
+
else
|
1124
|
+
on_command_call(receiver, call_operator, message, arguments)
|
1125
|
+
end
|
1126
|
+
else
|
1127
|
+
bounds(node.opening_loc)
|
1128
|
+
arguments = on_arg_paren(arguments)
|
1129
|
+
|
1130
|
+
bounds(node.location)
|
1131
|
+
on_method_add_arg(on_call(receiver, call_operator, message), arguments)
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
if block.nil?
|
1135
|
+
call
|
1136
|
+
else
|
1137
|
+
bounds(node.block.location)
|
1138
|
+
on_method_add_block(call, block)
|
1139
|
+
end
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
# Visit the arguments and block of a call node and return the arguments
|
1145
|
+
# and block as they should be used.
|
1146
|
+
private def visit_call_node_arguments(arguments_node, block_node, trailing_comma)
|
1147
|
+
arguments = arguments_node&.arguments || []
|
1148
|
+
block = block_node
|
1149
|
+
|
1150
|
+
if block.is_a?(BlockArgumentNode)
|
1151
|
+
arguments << block
|
1152
|
+
block = nil
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
[
|
1156
|
+
if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
|
1157
|
+
visit(arguments.first)
|
1158
|
+
elsif arguments.any?
|
1159
|
+
args = visit_arguments(arguments)
|
1160
|
+
|
1161
|
+
if block_node.is_a?(BlockArgumentNode) || arguments.last.is_a?(ForwardingArgumentsNode) || command?(arguments.last) || trailing_comma
|
1162
|
+
args
|
1163
|
+
else
|
1164
|
+
bounds(arguments.first.location)
|
1165
|
+
on_args_add_block(args, false)
|
1166
|
+
end
|
1167
|
+
end,
|
1168
|
+
visit(block)
|
1169
|
+
]
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
# Returns true if the given node is a command node.
|
1173
|
+
private def command?(node)
|
1174
|
+
node.is_a?(CallNode) &&
|
1175
|
+
node.opening_loc.nil? &&
|
1176
|
+
(!node.arguments.nil? || node.block.is_a?(BlockArgumentNode)) &&
|
1177
|
+
!BINARY_OPERATORS.include?(node.name)
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
# foo.bar += baz
|
1181
|
+
# ^^^^^^^^^^^^^^^
|
1182
|
+
def visit_call_operator_write_node(node)
|
1183
|
+
receiver = visit(node.receiver)
|
1184
|
+
|
1185
|
+
bounds(node.call_operator_loc)
|
1186
|
+
call_operator = visit_token(node.call_operator)
|
1187
|
+
|
1188
|
+
bounds(node.message_loc)
|
1189
|
+
message = visit_token(node.message)
|
1190
|
+
|
1191
|
+
bounds(node.location)
|
1192
|
+
target = on_field(receiver, call_operator, message)
|
1193
|
+
|
1194
|
+
bounds(node.binary_operator_loc)
|
1195
|
+
operator = on_op("#{node.binary_operator}=")
|
1196
|
+
value = visit_write_value(node.value)
|
1197
|
+
|
1198
|
+
bounds(node.location)
|
1199
|
+
on_opassign(target, operator, value)
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
# foo.bar &&= baz
|
1203
|
+
# ^^^^^^^^^^^^^^^
|
1204
|
+
def visit_call_and_write_node(node)
|
1205
|
+
receiver = visit(node.receiver)
|
1206
|
+
|
1207
|
+
bounds(node.call_operator_loc)
|
1208
|
+
call_operator = visit_token(node.call_operator)
|
1209
|
+
|
1210
|
+
bounds(node.message_loc)
|
1211
|
+
message = visit_token(node.message)
|
1212
|
+
|
1213
|
+
bounds(node.location)
|
1214
|
+
target = on_field(receiver, call_operator, message)
|
1215
|
+
|
1216
|
+
bounds(node.operator_loc)
|
1217
|
+
operator = on_op("&&=")
|
1218
|
+
value = visit_write_value(node.value)
|
1219
|
+
|
1220
|
+
bounds(node.location)
|
1221
|
+
on_opassign(target, operator, value)
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
# foo.bar ||= baz
|
1225
|
+
# ^^^^^^^^^^^^^^^
|
1226
|
+
def visit_call_or_write_node(node)
|
1227
|
+
receiver = visit(node.receiver)
|
1228
|
+
|
1229
|
+
bounds(node.call_operator_loc)
|
1230
|
+
call_operator = visit_token(node.call_operator)
|
1231
|
+
|
1232
|
+
bounds(node.message_loc)
|
1233
|
+
message = visit_token(node.message)
|
1234
|
+
|
1235
|
+
bounds(node.location)
|
1236
|
+
target = on_field(receiver, call_operator, message)
|
1237
|
+
|
1238
|
+
bounds(node.operator_loc)
|
1239
|
+
operator = on_op("||=")
|
1240
|
+
value = visit_write_value(node.value)
|
1241
|
+
|
1242
|
+
bounds(node.location)
|
1243
|
+
on_opassign(target, operator, value)
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
# foo.bar, = 1
|
1247
|
+
# ^^^^^^^
|
1248
|
+
def visit_call_target_node(node)
|
1249
|
+
if node.call_operator == "::"
|
1250
|
+
receiver = visit(node.receiver)
|
1251
|
+
|
1252
|
+
bounds(node.message_loc)
|
1253
|
+
message = visit_token(node.message)
|
1254
|
+
|
1255
|
+
bounds(node.location)
|
1256
|
+
on_const_path_field(receiver, message)
|
1257
|
+
else
|
1258
|
+
receiver = visit(node.receiver)
|
1259
|
+
|
1260
|
+
bounds(node.call_operator_loc)
|
1261
|
+
call_operator = visit_token(node.call_operator)
|
1262
|
+
|
1263
|
+
bounds(node.message_loc)
|
1264
|
+
message = visit_token(node.message)
|
1265
|
+
|
1266
|
+
bounds(node.location)
|
1267
|
+
on_field(receiver, call_operator, message)
|
1268
|
+
end
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
# foo => bar => baz
|
1272
|
+
# ^^^^^^^^^^
|
1273
|
+
def visit_capture_pattern_node(node)
|
1274
|
+
value = visit(node.value)
|
1275
|
+
target = visit(node.target)
|
1276
|
+
|
1277
|
+
bounds(node.location)
|
1278
|
+
on_binary(value, :"=>", target)
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
# case foo; when bar; end
|
1282
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^
|
1283
|
+
def visit_case_node(node)
|
1284
|
+
predicate = visit(node.predicate)
|
1285
|
+
clauses =
|
1286
|
+
node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
|
1287
|
+
on_when(*visit(condition), current)
|
1288
|
+
end
|
1289
|
+
|
1290
|
+
bounds(node.location)
|
1291
|
+
on_case(predicate, clauses)
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
# case foo; in bar; end
|
1295
|
+
# ^^^^^^^^^^^^^^^^^^^^^
|
1296
|
+
def visit_case_match_node(node)
|
1297
|
+
predicate = visit(node.predicate)
|
1298
|
+
clauses =
|
1299
|
+
node.conditions.reverse_each.inject(visit(node.else_clause)) do |current, condition|
|
1300
|
+
on_in(*visit(condition), current)
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
bounds(node.location)
|
1304
|
+
on_case(predicate, clauses)
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
# class Foo; end
|
1308
|
+
# ^^^^^^^^^^^^^^
|
1309
|
+
def visit_class_node(node)
|
1310
|
+
constant_path =
|
1311
|
+
if node.constant_path.is_a?(ConstantReadNode)
|
1312
|
+
bounds(node.constant_path.location)
|
1313
|
+
on_const_ref(on_const(node.constant_path.name.to_s))
|
1314
|
+
else
|
1315
|
+
visit(node.constant_path)
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
superclass = visit(node.superclass)
|
1319
|
+
bodystmt = visit_body_node(node.superclass&.location || node.constant_path.location, node.body, node.superclass.nil?)
|
1320
|
+
|
1321
|
+
bounds(node.location)
|
1322
|
+
on_class(constant_path, superclass, bodystmt)
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
# @@foo
|
1326
|
+
# ^^^^^
|
1327
|
+
def visit_class_variable_read_node(node)
|
1328
|
+
bounds(node.location)
|
1329
|
+
on_var_ref(on_cvar(node.slice))
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
# @@foo = 1
|
1333
|
+
# ^^^^^^^^^
|
1334
|
+
#
|
1335
|
+
# @@foo, @@bar = 1
|
1336
|
+
# ^^^^^ ^^^^^
|
1337
|
+
def visit_class_variable_write_node(node)
|
1338
|
+
bounds(node.name_loc)
|
1339
|
+
target = on_var_field(on_cvar(node.name.to_s))
|
1340
|
+
value = visit_write_value(node.value)
|
1341
|
+
|
1342
|
+
bounds(node.location)
|
1343
|
+
on_assign(target, value)
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
# @@foo += bar
|
1347
|
+
# ^^^^^^^^^^^^
|
1348
|
+
def visit_class_variable_operator_write_node(node)
|
1349
|
+
bounds(node.name_loc)
|
1350
|
+
target = on_var_field(on_cvar(node.name.to_s))
|
1351
|
+
|
1352
|
+
bounds(node.binary_operator_loc)
|
1353
|
+
operator = on_op("#{node.binary_operator}=")
|
1354
|
+
value = visit_write_value(node.value)
|
1355
|
+
|
1356
|
+
bounds(node.location)
|
1357
|
+
on_opassign(target, operator, value)
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
# @@foo &&= bar
|
1361
|
+
# ^^^^^^^^^^^^^
|
1362
|
+
def visit_class_variable_and_write_node(node)
|
1363
|
+
bounds(node.name_loc)
|
1364
|
+
target = on_var_field(on_cvar(node.name.to_s))
|
1365
|
+
|
1366
|
+
bounds(node.operator_loc)
|
1367
|
+
operator = on_op("&&=")
|
1368
|
+
value = visit_write_value(node.value)
|
1369
|
+
|
1370
|
+
bounds(node.location)
|
1371
|
+
on_opassign(target, operator, value)
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
# @@foo ||= bar
|
1375
|
+
# ^^^^^^^^^^^^^
|
1376
|
+
def visit_class_variable_or_write_node(node)
|
1377
|
+
bounds(node.name_loc)
|
1378
|
+
target = on_var_field(on_cvar(node.name.to_s))
|
1379
|
+
|
1380
|
+
bounds(node.operator_loc)
|
1381
|
+
operator = on_op("||=")
|
1382
|
+
value = visit_write_value(node.value)
|
1383
|
+
|
1384
|
+
bounds(node.location)
|
1385
|
+
on_opassign(target, operator, value)
|
1386
|
+
end
|
1387
|
+
|
1388
|
+
# @@foo, = bar
|
1389
|
+
# ^^^^^
|
1390
|
+
def visit_class_variable_target_node(node)
|
1391
|
+
bounds(node.location)
|
1392
|
+
on_var_field(on_cvar(node.name.to_s))
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
# Foo
|
1396
|
+
# ^^^
|
1397
|
+
def visit_constant_read_node(node)
|
1398
|
+
bounds(node.location)
|
1399
|
+
on_var_ref(on_const(node.name.to_s))
|
1400
|
+
end
|
1401
|
+
|
1402
|
+
# Foo = 1
|
1403
|
+
# ^^^^^^^
|
1404
|
+
#
|
1405
|
+
# Foo, Bar = 1
|
1406
|
+
# ^^^ ^^^
|
1407
|
+
def visit_constant_write_node(node)
|
1408
|
+
bounds(node.name_loc)
|
1409
|
+
target = on_var_field(on_const(node.name.to_s))
|
1410
|
+
value = visit_write_value(node.value)
|
1411
|
+
|
1412
|
+
bounds(node.location)
|
1413
|
+
on_assign(target, value)
|
1414
|
+
end
|
1415
|
+
|
1416
|
+
# Foo += bar
|
1417
|
+
# ^^^^^^^^^^^
|
1418
|
+
def visit_constant_operator_write_node(node)
|
1419
|
+
bounds(node.name_loc)
|
1420
|
+
target = on_var_field(on_const(node.name.to_s))
|
1421
|
+
|
1422
|
+
bounds(node.binary_operator_loc)
|
1423
|
+
operator = on_op("#{node.binary_operator}=")
|
1424
|
+
value = visit_write_value(node.value)
|
1425
|
+
|
1426
|
+
bounds(node.location)
|
1427
|
+
on_opassign(target, operator, value)
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
# Foo &&= bar
|
1431
|
+
# ^^^^^^^^^^^^
|
1432
|
+
def visit_constant_and_write_node(node)
|
1433
|
+
bounds(node.name_loc)
|
1434
|
+
target = on_var_field(on_const(node.name.to_s))
|
1435
|
+
|
1436
|
+
bounds(node.operator_loc)
|
1437
|
+
operator = on_op("&&=")
|
1438
|
+
value = visit_write_value(node.value)
|
1439
|
+
|
1440
|
+
bounds(node.location)
|
1441
|
+
on_opassign(target, operator, value)
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
# Foo ||= bar
|
1445
|
+
# ^^^^^^^^^^^^
|
1446
|
+
def visit_constant_or_write_node(node)
|
1447
|
+
bounds(node.name_loc)
|
1448
|
+
target = on_var_field(on_const(node.name.to_s))
|
1449
|
+
|
1450
|
+
bounds(node.operator_loc)
|
1451
|
+
operator = on_op("||=")
|
1452
|
+
value = visit_write_value(node.value)
|
1453
|
+
|
1454
|
+
bounds(node.location)
|
1455
|
+
on_opassign(target, operator, value)
|
1456
|
+
end
|
1457
|
+
|
1458
|
+
# Foo, = bar
|
1459
|
+
# ^^^
|
1460
|
+
def visit_constant_target_node(node)
|
1461
|
+
bounds(node.location)
|
1462
|
+
on_var_field(on_const(node.name.to_s))
|
1463
|
+
end
|
1464
|
+
|
1465
|
+
# Foo::Bar
|
1466
|
+
# ^^^^^^^^
|
1467
|
+
def visit_constant_path_node(node)
|
1468
|
+
if node.parent.nil?
|
1469
|
+
bounds(node.name_loc)
|
1470
|
+
child = on_const(node.name.to_s)
|
1471
|
+
|
1472
|
+
bounds(node.location)
|
1473
|
+
on_top_const_ref(child)
|
1474
|
+
else
|
1475
|
+
parent = visit(node.parent)
|
1476
|
+
|
1477
|
+
bounds(node.name_loc)
|
1478
|
+
child = on_const(node.name.to_s)
|
1479
|
+
|
1480
|
+
bounds(node.location)
|
1481
|
+
on_const_path_ref(parent, child)
|
1482
|
+
end
|
1483
|
+
end
|
1484
|
+
|
1485
|
+
# Foo::Bar = 1
|
1486
|
+
# ^^^^^^^^^^^^
|
1487
|
+
#
|
1488
|
+
# Foo::Foo, Bar::Bar = 1
|
1489
|
+
# ^^^^^^^^ ^^^^^^^^
|
1490
|
+
def visit_constant_path_write_node(node)
|
1491
|
+
target = visit_constant_path_write_node_target(node.target)
|
1492
|
+
value = visit_write_value(node.value)
|
1493
|
+
|
1494
|
+
bounds(node.location)
|
1495
|
+
on_assign(target, value)
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
# Visit a constant path that is part of a write node.
|
1499
|
+
private def visit_constant_path_write_node_target(node)
|
1500
|
+
if node.parent.nil?
|
1501
|
+
bounds(node.name_loc)
|
1502
|
+
child = on_const(node.name.to_s)
|
1503
|
+
|
1504
|
+
bounds(node.location)
|
1505
|
+
on_top_const_field(child)
|
1506
|
+
else
|
1507
|
+
parent = visit(node.parent)
|
1508
|
+
|
1509
|
+
bounds(node.name_loc)
|
1510
|
+
child = on_const(node.name.to_s)
|
1511
|
+
|
1512
|
+
bounds(node.location)
|
1513
|
+
on_const_path_field(parent, child)
|
1514
|
+
end
|
1515
|
+
end
|
1516
|
+
|
1517
|
+
# Foo::Bar += baz
|
1518
|
+
# ^^^^^^^^^^^^^^^
|
1519
|
+
def visit_constant_path_operator_write_node(node)
|
1520
|
+
target = visit_constant_path_write_node_target(node.target)
|
1521
|
+
value = visit(node.value)
|
1522
|
+
|
1523
|
+
bounds(node.binary_operator_loc)
|
1524
|
+
operator = on_op("#{node.binary_operator}=")
|
1525
|
+
value = visit_write_value(node.value)
|
1526
|
+
|
1527
|
+
bounds(node.location)
|
1528
|
+
on_opassign(target, operator, value)
|
1529
|
+
end
|
1530
|
+
|
1531
|
+
# Foo::Bar &&= baz
|
1532
|
+
# ^^^^^^^^^^^^^^^^
|
1533
|
+
def visit_constant_path_and_write_node(node)
|
1534
|
+
target = visit_constant_path_write_node_target(node.target)
|
1535
|
+
value = visit(node.value)
|
1536
|
+
|
1537
|
+
bounds(node.operator_loc)
|
1538
|
+
operator = on_op("&&=")
|
1539
|
+
value = visit_write_value(node.value)
|
1540
|
+
|
1541
|
+
bounds(node.location)
|
1542
|
+
on_opassign(target, operator, value)
|
1543
|
+
end
|
1544
|
+
|
1545
|
+
# Foo::Bar ||= baz
|
1546
|
+
# ^^^^^^^^^^^^^^^^
|
1547
|
+
def visit_constant_path_or_write_node(node)
|
1548
|
+
target = visit_constant_path_write_node_target(node.target)
|
1549
|
+
value = visit(node.value)
|
1550
|
+
|
1551
|
+
bounds(node.operator_loc)
|
1552
|
+
operator = on_op("||=")
|
1553
|
+
value = visit_write_value(node.value)
|
1554
|
+
|
1555
|
+
bounds(node.location)
|
1556
|
+
on_opassign(target, operator, value)
|
1557
|
+
end
|
1558
|
+
|
1559
|
+
# Foo::Bar, = baz
|
1560
|
+
# ^^^^^^^^
|
1561
|
+
def visit_constant_path_target_node(node)
|
1562
|
+
visit_constant_path_write_node_target(node)
|
1563
|
+
end
|
1564
|
+
|
1565
|
+
# def foo; end
|
1566
|
+
# ^^^^^^^^^^^^
|
1567
|
+
#
|
1568
|
+
# def self.foo; end
|
1569
|
+
# ^^^^^^^^^^^^^^^^^
|
1570
|
+
def visit_def_node(node)
|
1571
|
+
receiver = visit(node.receiver)
|
1572
|
+
operator =
|
1573
|
+
if !node.operator_loc.nil?
|
1574
|
+
bounds(node.operator_loc)
|
1575
|
+
visit_token(node.operator)
|
1576
|
+
end
|
1577
|
+
|
1578
|
+
bounds(node.name_loc)
|
1579
|
+
name = visit_token(node.name_loc.slice)
|
1580
|
+
|
1581
|
+
parameters =
|
1582
|
+
if node.parameters.nil?
|
1583
|
+
bounds(node.location)
|
1584
|
+
on_params(nil, nil, nil, nil, nil, nil, nil)
|
1585
|
+
else
|
1586
|
+
visit(node.parameters)
|
1587
|
+
end
|
1588
|
+
|
1589
|
+
if !node.lparen_loc.nil?
|
1590
|
+
bounds(node.lparen_loc)
|
1591
|
+
parameters = on_paren(parameters)
|
1592
|
+
end
|
1593
|
+
|
1594
|
+
bodystmt =
|
1595
|
+
if node.equal_loc.nil?
|
1596
|
+
visit_body_node(node.rparen_loc || node.end_keyword_loc, node.body)
|
1597
|
+
else
|
1598
|
+
body = visit(node.body.body.first)
|
1599
|
+
|
1600
|
+
bounds(node.body.location)
|
1601
|
+
on_bodystmt(body, nil, nil, nil)
|
1602
|
+
end
|
1603
|
+
|
1604
|
+
bounds(node.location)
|
1605
|
+
if receiver.nil?
|
1606
|
+
on_def(name, parameters, bodystmt)
|
1607
|
+
else
|
1608
|
+
on_defs(receiver, operator, name, parameters, bodystmt)
|
1609
|
+
end
|
1610
|
+
end
|
1611
|
+
|
1612
|
+
# defined? a
|
1613
|
+
# ^^^^^^^^^^
|
1614
|
+
#
|
1615
|
+
# defined?(a)
|
1616
|
+
# ^^^^^^^^^^^
|
1617
|
+
def visit_defined_node(node)
|
1618
|
+
bounds(node.location)
|
1619
|
+
on_defined(visit(node.value))
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
# if foo then bar else baz end
|
1623
|
+
# ^^^^^^^^^^^^
|
1624
|
+
def visit_else_node(node)
|
1625
|
+
statements =
|
1626
|
+
if node.statements.nil?
|
1627
|
+
[nil]
|
1628
|
+
else
|
1629
|
+
body = node.statements.body
|
1630
|
+
body.unshift(nil) if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false)
|
1631
|
+
body
|
1632
|
+
end
|
1633
|
+
|
1634
|
+
bounds(node.location)
|
1635
|
+
on_else(visit_statements_node_body(statements))
|
1636
|
+
end
|
1637
|
+
|
1638
|
+
# "foo #{bar}"
|
1639
|
+
# ^^^^^^
|
1640
|
+
def visit_embedded_statements_node(node)
|
1641
|
+
bounds(node.opening_loc)
|
1642
|
+
on_embexpr_beg(node.opening)
|
1643
|
+
|
1644
|
+
statements =
|
1645
|
+
if node.statements.nil?
|
1646
|
+
bounds(node.location)
|
1647
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
1648
|
+
else
|
1649
|
+
visit(node.statements)
|
1650
|
+
end
|
1651
|
+
|
1652
|
+
bounds(node.closing_loc)
|
1653
|
+
on_embexpr_end(node.closing)
|
1654
|
+
|
1655
|
+
bounds(node.location)
|
1656
|
+
on_string_embexpr(statements)
|
1657
|
+
end
|
1658
|
+
|
1659
|
+
# "foo #@bar"
|
1660
|
+
# ^^^^^
|
1661
|
+
def visit_embedded_variable_node(node)
|
1662
|
+
bounds(node.operator_loc)
|
1663
|
+
on_embvar(node.operator)
|
1664
|
+
|
1665
|
+
variable = visit(node.variable)
|
1666
|
+
|
1667
|
+
bounds(node.location)
|
1668
|
+
on_string_dvar(variable)
|
1669
|
+
end
|
1670
|
+
|
1671
|
+
# Visit an EnsureNode node.
|
1672
|
+
def visit_ensure_node(node)
|
1673
|
+
statements =
|
1674
|
+
if node.statements.nil?
|
1675
|
+
[nil]
|
1676
|
+
else
|
1677
|
+
body = node.statements.body
|
1678
|
+
body.unshift(nil) if void_stmt?(node.ensure_keyword_loc, body[0].location, false)
|
1679
|
+
body
|
1680
|
+
end
|
1681
|
+
|
1682
|
+
statements = visit_statements_node_body(statements)
|
1683
|
+
|
1684
|
+
bounds(node.location)
|
1685
|
+
on_ensure(statements)
|
1686
|
+
end
|
1687
|
+
|
1688
|
+
# false
|
1689
|
+
# ^^^^^
|
1690
|
+
def visit_false_node(node)
|
1691
|
+
bounds(node.location)
|
1692
|
+
on_var_ref(on_kw("false"))
|
1693
|
+
end
|
1694
|
+
|
1695
|
+
# foo => [*, bar, *]
|
1696
|
+
# ^^^^^^^^^^^
|
1697
|
+
def visit_find_pattern_node(node)
|
1698
|
+
constant = visit(node.constant)
|
1699
|
+
left =
|
1700
|
+
if node.left.expression.nil?
|
1701
|
+
bounds(node.left.location)
|
1702
|
+
on_var_field(nil)
|
1703
|
+
else
|
1704
|
+
visit(node.left.expression)
|
1705
|
+
end
|
1706
|
+
|
1707
|
+
requireds = visit_all(node.requireds) if node.requireds.any?
|
1708
|
+
right =
|
1709
|
+
if node.right.expression.nil?
|
1710
|
+
bounds(node.right.location)
|
1711
|
+
on_var_field(nil)
|
1712
|
+
else
|
1713
|
+
visit(node.right.expression)
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
bounds(node.location)
|
1717
|
+
on_fndptn(constant, left, requireds, right)
|
1718
|
+
end
|
1719
|
+
|
1720
|
+
# if foo .. bar; end
|
1721
|
+
# ^^^^^^^^^^
|
1722
|
+
def visit_flip_flop_node(node)
|
1723
|
+
left = visit(node.left)
|
1724
|
+
right = visit(node.right)
|
1725
|
+
|
1726
|
+
bounds(node.location)
|
1727
|
+
if node.exclude_end?
|
1728
|
+
on_dot3(left, right)
|
1729
|
+
else
|
1730
|
+
on_dot2(left, right)
|
1731
|
+
end
|
1732
|
+
end
|
1733
|
+
|
1734
|
+
# 1.0
|
1735
|
+
# ^^^
|
1736
|
+
def visit_float_node(node)
|
1737
|
+
visit_number_node(node) { |text| on_float(text) }
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
# for foo in bar do end
|
1741
|
+
# ^^^^^^^^^^^^^^^^^^^^^
|
1742
|
+
def visit_for_node(node)
|
1743
|
+
index = visit(node.index)
|
1744
|
+
collection = visit(node.collection)
|
1745
|
+
statements =
|
1746
|
+
if node.statements.nil?
|
1747
|
+
bounds(node.location)
|
1748
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
1749
|
+
else
|
1750
|
+
visit(node.statements)
|
1751
|
+
end
|
1752
|
+
|
1753
|
+
bounds(node.location)
|
1754
|
+
on_for(index, collection, statements)
|
1755
|
+
end
|
1756
|
+
|
1757
|
+
# def foo(...); bar(...); end
|
1758
|
+
# ^^^
|
1759
|
+
def visit_forwarding_arguments_node(node)
|
1760
|
+
bounds(node.location)
|
1761
|
+
on_args_forward
|
1762
|
+
end
|
1763
|
+
|
1764
|
+
# def foo(...); end
|
1765
|
+
# ^^^
|
1766
|
+
def visit_forwarding_parameter_node(node)
|
1767
|
+
bounds(node.location)
|
1768
|
+
on_args_forward
|
1769
|
+
end
|
1770
|
+
|
1771
|
+
# super
|
1772
|
+
# ^^^^^
|
1773
|
+
#
|
1774
|
+
# super {}
|
1775
|
+
# ^^^^^^^^
|
1776
|
+
def visit_forwarding_super_node(node)
|
1777
|
+
if node.block.nil?
|
1778
|
+
bounds(node.location)
|
1779
|
+
on_zsuper
|
1780
|
+
else
|
1781
|
+
block = visit(node.block)
|
1782
|
+
|
1783
|
+
bounds(node.location)
|
1784
|
+
on_method_add_block(on_zsuper, block)
|
1785
|
+
end
|
1786
|
+
end
|
1787
|
+
|
1788
|
+
# $foo
|
1789
|
+
# ^^^^
|
1790
|
+
def visit_global_variable_read_node(node)
|
1791
|
+
bounds(node.location)
|
1792
|
+
on_var_ref(on_gvar(node.name.to_s))
|
1793
|
+
end
|
1794
|
+
|
1795
|
+
# $foo = 1
|
1796
|
+
# ^^^^^^^^
|
1797
|
+
#
|
1798
|
+
# $foo, $bar = 1
|
1799
|
+
# ^^^^ ^^^^
|
1800
|
+
def visit_global_variable_write_node(node)
|
1801
|
+
bounds(node.name_loc)
|
1802
|
+
target = on_var_field(on_gvar(node.name.to_s))
|
1803
|
+
value = visit_write_value(node.value)
|
1804
|
+
|
1805
|
+
bounds(node.location)
|
1806
|
+
on_assign(target, value)
|
1807
|
+
end
|
1808
|
+
|
1809
|
+
# $foo += bar
|
1810
|
+
# ^^^^^^^^^^^
|
1811
|
+
def visit_global_variable_operator_write_node(node)
|
1812
|
+
bounds(node.name_loc)
|
1813
|
+
target = on_var_field(on_gvar(node.name.to_s))
|
1814
|
+
|
1815
|
+
bounds(node.binary_operator_loc)
|
1816
|
+
operator = on_op("#{node.binary_operator}=")
|
1817
|
+
value = visit_write_value(node.value)
|
1818
|
+
|
1819
|
+
bounds(node.location)
|
1820
|
+
on_opassign(target, operator, value)
|
1821
|
+
end
|
1822
|
+
|
1823
|
+
# $foo &&= bar
|
1824
|
+
# ^^^^^^^^^^^^
|
1825
|
+
def visit_global_variable_and_write_node(node)
|
1826
|
+
bounds(node.name_loc)
|
1827
|
+
target = on_var_field(on_gvar(node.name.to_s))
|
1828
|
+
|
1829
|
+
bounds(node.operator_loc)
|
1830
|
+
operator = on_op("&&=")
|
1831
|
+
value = visit_write_value(node.value)
|
1832
|
+
|
1833
|
+
bounds(node.location)
|
1834
|
+
on_opassign(target, operator, value)
|
1835
|
+
end
|
1836
|
+
|
1837
|
+
# $foo ||= bar
|
1838
|
+
# ^^^^^^^^^^^^
|
1839
|
+
def visit_global_variable_or_write_node(node)
|
1840
|
+
bounds(node.name_loc)
|
1841
|
+
target = on_var_field(on_gvar(node.name.to_s))
|
1842
|
+
|
1843
|
+
bounds(node.operator_loc)
|
1844
|
+
operator = on_op("||=")
|
1845
|
+
value = visit_write_value(node.value)
|
1846
|
+
|
1847
|
+
bounds(node.location)
|
1848
|
+
on_opassign(target, operator, value)
|
1849
|
+
end
|
1850
|
+
|
1851
|
+
# $foo, = bar
|
1852
|
+
# ^^^^
|
1853
|
+
def visit_global_variable_target_node(node)
|
1854
|
+
bounds(node.location)
|
1855
|
+
on_var_field(on_gvar(node.name.to_s))
|
1856
|
+
end
|
1857
|
+
|
1858
|
+
# {}
|
1859
|
+
# ^^
|
1860
|
+
def visit_hash_node(node)
|
1861
|
+
elements =
|
1862
|
+
if node.elements.any?
|
1863
|
+
args = visit_all(node.elements)
|
1864
|
+
|
1865
|
+
bounds(node.elements.first.location)
|
1866
|
+
on_assoclist_from_args(args)
|
1867
|
+
end
|
1868
|
+
|
1869
|
+
bounds(node.location)
|
1870
|
+
on_hash(elements)
|
1871
|
+
end
|
1872
|
+
|
1873
|
+
# foo => {}
|
1874
|
+
# ^^
|
1875
|
+
def visit_hash_pattern_node(node)
|
1876
|
+
constant = visit(node.constant)
|
1877
|
+
elements =
|
1878
|
+
if node.elements.any? || !node.rest.nil?
|
1879
|
+
node.elements.map do |element|
|
1880
|
+
[
|
1881
|
+
if (key = element.key).opening_loc.nil?
|
1882
|
+
visit(key)
|
1883
|
+
else
|
1884
|
+
bounds(key.value_loc)
|
1885
|
+
if (value = key.value).empty?
|
1886
|
+
on_string_content
|
1887
|
+
else
|
1888
|
+
on_string_add(on_string_content, on_tstring_content(value))
|
1889
|
+
end
|
1890
|
+
end,
|
1891
|
+
visit(element.value)
|
1892
|
+
]
|
1893
|
+
end
|
1894
|
+
end
|
1895
|
+
|
1896
|
+
rest =
|
1897
|
+
case node.rest
|
1898
|
+
when AssocSplatNode
|
1899
|
+
visit(node.rest.value)
|
1900
|
+
when NoKeywordsParameterNode
|
1901
|
+
bounds(node.rest.location)
|
1902
|
+
on_var_field(visit(node.rest))
|
1903
|
+
end
|
1904
|
+
|
1905
|
+
bounds(node.location)
|
1906
|
+
on_hshptn(constant, elements, rest)
|
1907
|
+
end
|
1908
|
+
|
1909
|
+
# if foo then bar end
|
1910
|
+
# ^^^^^^^^^^^^^^^^^^^
|
1911
|
+
#
|
1912
|
+
# bar if foo
|
1913
|
+
# ^^^^^^^^^^
|
1914
|
+
#
|
1915
|
+
# foo ? bar : baz
|
1916
|
+
# ^^^^^^^^^^^^^^^
|
1917
|
+
def visit_if_node(node)
|
1918
|
+
if node.then_keyword == "?"
|
1919
|
+
predicate = visit(node.predicate)
|
1920
|
+
truthy = visit(node.statements.body.first)
|
1921
|
+
falsy = visit(node.subsequent.statements.body.first)
|
1922
|
+
|
1923
|
+
bounds(node.location)
|
1924
|
+
on_ifop(predicate, truthy, falsy)
|
1925
|
+
elsif node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
|
1926
|
+
predicate = visit(node.predicate)
|
1927
|
+
statements =
|
1928
|
+
if node.statements.nil?
|
1929
|
+
bounds(node.location)
|
1930
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
1931
|
+
else
|
1932
|
+
visit(node.statements)
|
1933
|
+
end
|
1934
|
+
subsequent = visit(node.subsequent)
|
1935
|
+
|
1936
|
+
bounds(node.location)
|
1937
|
+
if node.if_keyword == "if"
|
1938
|
+
on_if(predicate, statements, subsequent)
|
1939
|
+
else
|
1940
|
+
on_elsif(predicate, statements, subsequent)
|
1941
|
+
end
|
1942
|
+
else
|
1943
|
+
statements = visit(node.statements.body.first)
|
1944
|
+
predicate = visit(node.predicate)
|
1945
|
+
|
1946
|
+
bounds(node.location)
|
1947
|
+
on_if_mod(predicate, statements)
|
1948
|
+
end
|
1949
|
+
end
|
1950
|
+
|
1951
|
+
# 1i
|
1952
|
+
# ^^
|
1953
|
+
def visit_imaginary_node(node)
|
1954
|
+
visit_number_node(node) { |text| on_imaginary(text) }
|
1955
|
+
end
|
1956
|
+
|
1957
|
+
# { foo: }
|
1958
|
+
# ^^^^
|
1959
|
+
def visit_implicit_node(node)
|
1960
|
+
end
|
1961
|
+
|
1962
|
+
# foo { |bar,| }
|
1963
|
+
# ^
|
1964
|
+
def visit_implicit_rest_node(node)
|
1965
|
+
bounds(node.location)
|
1966
|
+
on_excessed_comma
|
1967
|
+
end
|
1968
|
+
|
1969
|
+
# case foo; in bar; end
|
1970
|
+
# ^^^^^^^^^^^^^^^^^^^^^
|
1971
|
+
def visit_in_node(node)
|
1972
|
+
# This is a special case where we're not going to call on_in directly
|
1973
|
+
# because we don't have access to the subsequent. Instead, we'll return
|
1974
|
+
# the component parts and let the parent node handle it.
|
1975
|
+
pattern = visit_pattern_node(node.pattern)
|
1976
|
+
statements =
|
1977
|
+
if node.statements.nil?
|
1978
|
+
bounds(node.location)
|
1979
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
1980
|
+
else
|
1981
|
+
visit(node.statements)
|
1982
|
+
end
|
1983
|
+
|
1984
|
+
[pattern, statements]
|
1985
|
+
end
|
1986
|
+
|
1987
|
+
# foo[bar] += baz
|
1988
|
+
# ^^^^^^^^^^^^^^^
|
1989
|
+
def visit_index_operator_write_node(node)
|
1990
|
+
receiver = visit(node.receiver)
|
1991
|
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
|
1992
|
+
|
1993
|
+
bounds(node.location)
|
1994
|
+
target = on_aref_field(receiver, arguments)
|
1995
|
+
|
1996
|
+
bounds(node.binary_operator_loc)
|
1997
|
+
operator = on_op("#{node.binary_operator}=")
|
1998
|
+
value = visit_write_value(node.value)
|
1999
|
+
|
2000
|
+
bounds(node.location)
|
2001
|
+
on_opassign(target, operator, value)
|
2002
|
+
end
|
2003
|
+
|
2004
|
+
# foo[bar] &&= baz
|
2005
|
+
# ^^^^^^^^^^^^^^^^
|
2006
|
+
def visit_index_and_write_node(node)
|
2007
|
+
receiver = visit(node.receiver)
|
2008
|
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
|
2009
|
+
|
2010
|
+
bounds(node.location)
|
2011
|
+
target = on_aref_field(receiver, arguments)
|
2012
|
+
|
2013
|
+
bounds(node.operator_loc)
|
2014
|
+
operator = on_op("&&=")
|
2015
|
+
value = visit_write_value(node.value)
|
2016
|
+
|
2017
|
+
bounds(node.location)
|
2018
|
+
on_opassign(target, operator, value)
|
2019
|
+
end
|
2020
|
+
|
2021
|
+
# foo[bar] ||= baz
|
2022
|
+
# ^^^^^^^^^^^^^^^^
|
2023
|
+
def visit_index_or_write_node(node)
|
2024
|
+
receiver = visit(node.receiver)
|
2025
|
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
|
2026
|
+
|
2027
|
+
bounds(node.location)
|
2028
|
+
target = on_aref_field(receiver, arguments)
|
2029
|
+
|
2030
|
+
bounds(node.operator_loc)
|
2031
|
+
operator = on_op("||=")
|
2032
|
+
value = visit_write_value(node.value)
|
2033
|
+
|
2034
|
+
bounds(node.location)
|
2035
|
+
on_opassign(target, operator, value)
|
2036
|
+
end
|
2037
|
+
|
2038
|
+
# foo[bar], = 1
|
2039
|
+
# ^^^^^^^^
|
2040
|
+
def visit_index_target_node(node)
|
2041
|
+
receiver = visit(node.receiver)
|
2042
|
+
arguments, _ = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.closing_loc))
|
2043
|
+
|
2044
|
+
bounds(node.location)
|
2045
|
+
on_aref_field(receiver, arguments)
|
2046
|
+
end
|
2047
|
+
|
2048
|
+
# @foo
|
2049
|
+
# ^^^^
|
2050
|
+
def visit_instance_variable_read_node(node)
|
2051
|
+
bounds(node.location)
|
2052
|
+
on_var_ref(on_ivar(node.name.to_s))
|
2053
|
+
end
|
2054
|
+
|
2055
|
+
# @foo = 1
|
2056
|
+
# ^^^^^^^^
|
2057
|
+
def visit_instance_variable_write_node(node)
|
2058
|
+
bounds(node.name_loc)
|
2059
|
+
target = on_var_field(on_ivar(node.name.to_s))
|
2060
|
+
value = visit_write_value(node.value)
|
2061
|
+
|
2062
|
+
bounds(node.location)
|
2063
|
+
on_assign(target, value)
|
2064
|
+
end
|
2065
|
+
|
2066
|
+
# @foo += bar
|
2067
|
+
# ^^^^^^^^^^^
|
2068
|
+
def visit_instance_variable_operator_write_node(node)
|
2069
|
+
bounds(node.name_loc)
|
2070
|
+
target = on_var_field(on_ivar(node.name.to_s))
|
2071
|
+
|
2072
|
+
bounds(node.binary_operator_loc)
|
2073
|
+
operator = on_op("#{node.binary_operator}=")
|
2074
|
+
value = visit_write_value(node.value)
|
2075
|
+
|
2076
|
+
bounds(node.location)
|
2077
|
+
on_opassign(target, operator, value)
|
2078
|
+
end
|
2079
|
+
|
2080
|
+
# @foo &&= bar
|
2081
|
+
# ^^^^^^^^^^^^
|
2082
|
+
def visit_instance_variable_and_write_node(node)
|
2083
|
+
bounds(node.name_loc)
|
2084
|
+
target = on_var_field(on_ivar(node.name.to_s))
|
2085
|
+
|
2086
|
+
bounds(node.operator_loc)
|
2087
|
+
operator = on_op("&&=")
|
2088
|
+
value = visit_write_value(node.value)
|
2089
|
+
|
2090
|
+
bounds(node.location)
|
2091
|
+
on_opassign(target, operator, value)
|
2092
|
+
end
|
2093
|
+
|
2094
|
+
# @foo ||= bar
|
2095
|
+
# ^^^^^^^^^^^^
|
2096
|
+
def visit_instance_variable_or_write_node(node)
|
2097
|
+
bounds(node.name_loc)
|
2098
|
+
target = on_var_field(on_ivar(node.name.to_s))
|
2099
|
+
|
2100
|
+
bounds(node.operator_loc)
|
2101
|
+
operator = on_op("||=")
|
2102
|
+
value = visit_write_value(node.value)
|
2103
|
+
|
2104
|
+
bounds(node.location)
|
2105
|
+
on_opassign(target, operator, value)
|
2106
|
+
end
|
2107
|
+
|
2108
|
+
# @foo, = bar
|
2109
|
+
# ^^^^
|
2110
|
+
def visit_instance_variable_target_node(node)
|
2111
|
+
bounds(node.location)
|
2112
|
+
on_var_field(on_ivar(node.name.to_s))
|
2113
|
+
end
|
2114
|
+
|
2115
|
+
# 1
|
2116
|
+
# ^
|
2117
|
+
def visit_integer_node(node)
|
2118
|
+
visit_number_node(node) { |text| on_int(text) }
|
2119
|
+
end
|
2120
|
+
|
2121
|
+
# if /foo #{bar}/ then end
|
2122
|
+
# ^^^^^^^^^^^^
|
2123
|
+
def visit_interpolated_match_last_line_node(node)
|
2124
|
+
bounds(node.opening_loc)
|
2125
|
+
on_regexp_beg(node.opening)
|
2126
|
+
|
2127
|
+
bounds(node.parts.first.location)
|
2128
|
+
parts =
|
2129
|
+
node.parts.inject(on_regexp_new) do |content, part|
|
2130
|
+
on_regexp_add(content, visit_string_content(part))
|
2131
|
+
end
|
2132
|
+
|
2133
|
+
bounds(node.closing_loc)
|
2134
|
+
closing = on_regexp_end(node.closing)
|
2135
|
+
|
2136
|
+
bounds(node.location)
|
2137
|
+
on_regexp_literal(parts, closing)
|
2138
|
+
end
|
2139
|
+
|
2140
|
+
# /foo #{bar}/
|
2141
|
+
# ^^^^^^^^^^^^
|
2142
|
+
def visit_interpolated_regular_expression_node(node)
|
2143
|
+
bounds(node.opening_loc)
|
2144
|
+
on_regexp_beg(node.opening)
|
2145
|
+
|
2146
|
+
bounds(node.parts.first.location)
|
2147
|
+
parts =
|
2148
|
+
node.parts.inject(on_regexp_new) do |content, part|
|
2149
|
+
on_regexp_add(content, visit_string_content(part))
|
2150
|
+
end
|
2151
|
+
|
2152
|
+
bounds(node.closing_loc)
|
2153
|
+
closing = on_regexp_end(node.closing)
|
2154
|
+
|
2155
|
+
bounds(node.location)
|
2156
|
+
on_regexp_literal(parts, closing)
|
2157
|
+
end
|
2158
|
+
|
2159
|
+
# "foo #{bar}"
|
2160
|
+
# ^^^^^^^^^^^^
|
2161
|
+
def visit_interpolated_string_node(node)
|
2162
|
+
if node.opening&.start_with?("<<~")
|
2163
|
+
heredoc = visit_heredoc_string_node(node)
|
2164
|
+
|
2165
|
+
bounds(node.location)
|
2166
|
+
on_string_literal(heredoc)
|
2167
|
+
elsif !node.heredoc? && node.parts.length > 1 && node.parts.any? { |part| (part.is_a?(StringNode) || part.is_a?(InterpolatedStringNode)) && !part.opening_loc.nil? }
|
2168
|
+
first, *rest = node.parts
|
2169
|
+
rest.inject(visit(first)) do |content, part|
|
2170
|
+
concat = visit(part)
|
2171
|
+
|
2172
|
+
bounds(part.location)
|
2173
|
+
on_string_concat(content, concat)
|
2174
|
+
end
|
2175
|
+
else
|
2176
|
+
bounds(node.parts.first.location)
|
2177
|
+
parts =
|
2178
|
+
node.parts.inject(on_string_content) do |content, part|
|
2179
|
+
on_string_add(content, visit_string_content(part))
|
2180
|
+
end
|
2181
|
+
|
2182
|
+
bounds(node.location)
|
2183
|
+
on_string_literal(parts)
|
2184
|
+
end
|
2185
|
+
end
|
2186
|
+
|
2187
|
+
# :"foo #{bar}"
|
2188
|
+
# ^^^^^^^^^^^^^
|
2189
|
+
def visit_interpolated_symbol_node(node)
|
2190
|
+
bounds(node.parts.first.location)
|
2191
|
+
parts =
|
2192
|
+
node.parts.inject(on_string_content) do |content, part|
|
2193
|
+
on_string_add(content, visit_string_content(part))
|
2194
|
+
end
|
2195
|
+
|
2196
|
+
bounds(node.location)
|
2197
|
+
on_dyna_symbol(parts)
|
2198
|
+
end
|
2199
|
+
|
2200
|
+
# `foo #{bar}`
|
2201
|
+
# ^^^^^^^^^^^^
|
2202
|
+
def visit_interpolated_x_string_node(node)
|
2203
|
+
if node.opening.start_with?("<<~")
|
2204
|
+
heredoc = visit_heredoc_x_string_node(node)
|
2205
|
+
|
2206
|
+
bounds(node.location)
|
2207
|
+
on_xstring_literal(heredoc)
|
2208
|
+
else
|
2209
|
+
bounds(node.parts.first.location)
|
2210
|
+
parts =
|
2211
|
+
node.parts.inject(on_xstring_new) do |content, part|
|
2212
|
+
on_xstring_add(content, visit_string_content(part))
|
2213
|
+
end
|
2214
|
+
|
2215
|
+
bounds(node.location)
|
2216
|
+
on_xstring_literal(parts)
|
2217
|
+
end
|
2218
|
+
end
|
2219
|
+
|
2220
|
+
# Visit an individual part of a string-like node.
|
2221
|
+
private def visit_string_content(part)
|
2222
|
+
if part.is_a?(StringNode)
|
2223
|
+
bounds(part.content_loc)
|
2224
|
+
on_tstring_content(part.content)
|
2225
|
+
else
|
2226
|
+
visit(part)
|
2227
|
+
end
|
2228
|
+
end
|
2229
|
+
|
2230
|
+
# -> { it }
|
2231
|
+
# ^^
|
2232
|
+
def visit_it_local_variable_read_node(node)
|
2233
|
+
bounds(node.location)
|
2234
|
+
on_vcall(on_ident(node.slice))
|
2235
|
+
end
|
2236
|
+
|
2237
|
+
# -> { it }
|
2238
|
+
# ^^^^^^^^^
|
2239
|
+
def visit_it_parameters_node(node)
|
2240
|
+
end
|
2241
|
+
|
2242
|
+
# foo(bar: baz)
|
2243
|
+
# ^^^^^^^^
|
2244
|
+
def visit_keyword_hash_node(node)
|
2245
|
+
elements = visit_all(node.elements)
|
2246
|
+
|
2247
|
+
bounds(node.location)
|
2248
|
+
on_bare_assoc_hash(elements)
|
2249
|
+
end
|
2250
|
+
|
2251
|
+
# def foo(**bar); end
|
2252
|
+
# ^^^^^
|
2253
|
+
#
|
2254
|
+
# def foo(**); end
|
2255
|
+
# ^^
|
2256
|
+
def visit_keyword_rest_parameter_node(node)
|
2257
|
+
if node.name_loc.nil?
|
2258
|
+
bounds(node.location)
|
2259
|
+
on_kwrest_param(nil)
|
2260
|
+
else
|
2261
|
+
bounds(node.name_loc)
|
2262
|
+
name = on_ident(node.name.to_s)
|
2263
|
+
|
2264
|
+
bounds(node.location)
|
2265
|
+
on_kwrest_param(name)
|
2266
|
+
end
|
2267
|
+
end
|
2268
|
+
|
2269
|
+
# -> {}
|
2270
|
+
def visit_lambda_node(node)
|
2271
|
+
bounds(node.operator_loc)
|
2272
|
+
on_tlambda(node.operator)
|
2273
|
+
|
2274
|
+
parameters =
|
2275
|
+
if node.parameters.is_a?(BlockParametersNode)
|
2276
|
+
# Ripper does not track block-locals within lambdas, so we skip
|
2277
|
+
# directly to the parameters here.
|
2278
|
+
params =
|
2279
|
+
if node.parameters.parameters.nil?
|
2280
|
+
bounds(node.location)
|
2281
|
+
on_params(nil, nil, nil, nil, nil, nil, nil)
|
2282
|
+
else
|
2283
|
+
visit(node.parameters.parameters)
|
2284
|
+
end
|
2285
|
+
|
2286
|
+
if node.parameters.opening_loc.nil?
|
2287
|
+
params
|
2288
|
+
else
|
2289
|
+
bounds(node.parameters.opening_loc)
|
2290
|
+
on_paren(params)
|
2291
|
+
end
|
2292
|
+
else
|
2293
|
+
bounds(node.location)
|
2294
|
+
on_params(nil, nil, nil, nil, nil, nil, nil)
|
2295
|
+
end
|
2296
|
+
|
2297
|
+
braces = node.opening == "{"
|
2298
|
+
if braces
|
2299
|
+
bounds(node.opening_loc)
|
2300
|
+
on_tlambeg(node.opening)
|
2301
|
+
end
|
2302
|
+
|
2303
|
+
body =
|
2304
|
+
case node.body
|
2305
|
+
when nil
|
2306
|
+
bounds(node.location)
|
2307
|
+
stmts = on_stmts_add(on_stmts_new, on_void_stmt)
|
2308
|
+
|
2309
|
+
bounds(node.location)
|
2310
|
+
braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
|
2311
|
+
when StatementsNode
|
2312
|
+
stmts = node.body.body
|
2313
|
+
stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false)
|
2314
|
+
stmts = visit_statements_node_body(stmts)
|
2315
|
+
|
2316
|
+
bounds(node.body.location)
|
2317
|
+
braces ? stmts : on_bodystmt(stmts, nil, nil, nil)
|
2318
|
+
when BeginNode
|
2319
|
+
visit_body_node(node.opening_loc, node.body)
|
2320
|
+
else
|
2321
|
+
raise
|
2322
|
+
end
|
2323
|
+
|
2324
|
+
bounds(node.location)
|
2325
|
+
on_lambda(parameters, body)
|
2326
|
+
end
|
2327
|
+
|
2328
|
+
# foo
|
2329
|
+
# ^^^
|
2330
|
+
def visit_local_variable_read_node(node)
|
2331
|
+
bounds(node.location)
|
2332
|
+
on_var_ref(on_ident(node.slice))
|
2333
|
+
end
|
2334
|
+
|
2335
|
+
# foo = 1
|
2336
|
+
# ^^^^^^^
|
2337
|
+
def visit_local_variable_write_node(node)
|
2338
|
+
bounds(node.name_loc)
|
2339
|
+
target = on_var_field(on_ident(node.name_loc.slice))
|
2340
|
+
value = visit_write_value(node.value)
|
2341
|
+
|
2342
|
+
bounds(node.location)
|
2343
|
+
on_assign(target, value)
|
2344
|
+
end
|
2345
|
+
|
2346
|
+
# foo += bar
|
2347
|
+
# ^^^^^^^^^^
|
2348
|
+
def visit_local_variable_operator_write_node(node)
|
2349
|
+
bounds(node.name_loc)
|
2350
|
+
target = on_var_field(on_ident(node.name_loc.slice))
|
2351
|
+
|
2352
|
+
bounds(node.binary_operator_loc)
|
2353
|
+
operator = on_op("#{node.binary_operator}=")
|
2354
|
+
value = visit_write_value(node.value)
|
2355
|
+
|
2356
|
+
bounds(node.location)
|
2357
|
+
on_opassign(target, operator, value)
|
2358
|
+
end
|
2359
|
+
|
2360
|
+
# foo &&= bar
|
2361
|
+
# ^^^^^^^^^^^
|
2362
|
+
def visit_local_variable_and_write_node(node)
|
2363
|
+
bounds(node.name_loc)
|
2364
|
+
target = on_var_field(on_ident(node.name_loc.slice))
|
2365
|
+
|
2366
|
+
bounds(node.operator_loc)
|
2367
|
+
operator = on_op("&&=")
|
2368
|
+
value = visit_write_value(node.value)
|
2369
|
+
|
2370
|
+
bounds(node.location)
|
2371
|
+
on_opassign(target, operator, value)
|
2372
|
+
end
|
2373
|
+
|
2374
|
+
# foo ||= bar
|
2375
|
+
# ^^^^^^^^^^^
|
2376
|
+
def visit_local_variable_or_write_node(node)
|
2377
|
+
bounds(node.name_loc)
|
2378
|
+
target = on_var_field(on_ident(node.name_loc.slice))
|
2379
|
+
|
2380
|
+
bounds(node.operator_loc)
|
2381
|
+
operator = on_op("||=")
|
2382
|
+
value = visit_write_value(node.value)
|
2383
|
+
|
2384
|
+
bounds(node.location)
|
2385
|
+
on_opassign(target, operator, value)
|
2386
|
+
end
|
2387
|
+
|
2388
|
+
# foo, = bar
|
2389
|
+
# ^^^
|
2390
|
+
def visit_local_variable_target_node(node)
|
2391
|
+
bounds(node.location)
|
2392
|
+
on_var_field(on_ident(node.name.to_s))
|
2393
|
+
end
|
2394
|
+
|
2395
|
+
# if /foo/ then end
|
2396
|
+
# ^^^^^
|
2397
|
+
def visit_match_last_line_node(node)
|
2398
|
+
bounds(node.opening_loc)
|
2399
|
+
on_regexp_beg(node.opening)
|
2400
|
+
|
2401
|
+
bounds(node.content_loc)
|
2402
|
+
tstring_content = on_tstring_content(node.content)
|
2403
|
+
|
2404
|
+
bounds(node.closing_loc)
|
2405
|
+
closing = on_regexp_end(node.closing)
|
2406
|
+
|
2407
|
+
on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing)
|
2408
|
+
end
|
2409
|
+
|
2410
|
+
# foo in bar
|
2411
|
+
# ^^^^^^^^^^
|
2412
|
+
def visit_match_predicate_node(node)
|
2413
|
+
value = visit(node.value)
|
2414
|
+
pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
|
2415
|
+
|
2416
|
+
on_case(value, pattern)
|
2417
|
+
end
|
2418
|
+
|
2419
|
+
# foo => bar
|
2420
|
+
# ^^^^^^^^^^
|
2421
|
+
def visit_match_required_node(node)
|
2422
|
+
value = visit(node.value)
|
2423
|
+
pattern = on_in(visit_pattern_node(node.pattern), nil, nil)
|
2424
|
+
|
2425
|
+
on_case(value, pattern)
|
2426
|
+
end
|
2427
|
+
|
2428
|
+
# /(?<foo>foo)/ =~ bar
|
2429
|
+
# ^^^^^^^^^^^^^^^^^^^^
|
2430
|
+
def visit_match_write_node(node)
|
2431
|
+
visit(node.call)
|
2432
|
+
end
|
2433
|
+
|
2434
|
+
# A node that is missing from the syntax tree. This is only used in the
|
2435
|
+
# case of a syntax error.
|
2436
|
+
def visit_missing_node(node)
|
2437
|
+
raise "Cannot visit missing nodes directly."
|
2438
|
+
end
|
2439
|
+
|
2440
|
+
# module Foo; end
|
2441
|
+
# ^^^^^^^^^^^^^^^
|
2442
|
+
def visit_module_node(node)
|
2443
|
+
constant_path =
|
2444
|
+
if node.constant_path.is_a?(ConstantReadNode)
|
2445
|
+
bounds(node.constant_path.location)
|
2446
|
+
on_const_ref(on_const(node.constant_path.name.to_s))
|
2447
|
+
else
|
2448
|
+
visit(node.constant_path)
|
2449
|
+
end
|
2450
|
+
|
2451
|
+
bodystmt = visit_body_node(node.constant_path.location, node.body, true)
|
2452
|
+
|
2453
|
+
bounds(node.location)
|
2454
|
+
on_module(constant_path, bodystmt)
|
2455
|
+
end
|
2456
|
+
|
2457
|
+
# (foo, bar), bar = qux
|
2458
|
+
# ^^^^^^^^^^
|
2459
|
+
def visit_multi_target_node(node)
|
2460
|
+
bounds(node.location)
|
2461
|
+
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
|
2462
|
+
|
2463
|
+
if node.lparen_loc.nil?
|
2464
|
+
targets
|
2465
|
+
else
|
2466
|
+
bounds(node.lparen_loc)
|
2467
|
+
on_mlhs_paren(targets)
|
2468
|
+
end
|
2469
|
+
end
|
2470
|
+
|
2471
|
+
# Visit the targets of a multi-target node.
|
2472
|
+
private def visit_multi_target_node_targets(lefts, rest, rights, skippable)
|
2473
|
+
if skippable && lefts.length == 1 && lefts.first.is_a?(MultiTargetNode) && rest.nil? && rights.empty?
|
2474
|
+
return visit(lefts.first)
|
2475
|
+
end
|
2476
|
+
|
2477
|
+
mlhs = on_mlhs_new
|
2478
|
+
|
2479
|
+
lefts.each do |left|
|
2480
|
+
bounds(left.location)
|
2481
|
+
mlhs = on_mlhs_add(mlhs, visit(left))
|
2482
|
+
end
|
2483
|
+
|
2484
|
+
case rest
|
2485
|
+
when nil
|
2486
|
+
# do nothing
|
2487
|
+
when ImplicitRestNode
|
2488
|
+
# these do not get put into the generated tree
|
2489
|
+
bounds(rest.location)
|
2490
|
+
on_excessed_comma
|
2491
|
+
else
|
2492
|
+
bounds(rest.location)
|
2493
|
+
mlhs = on_mlhs_add_star(mlhs, visit(rest))
|
2494
|
+
end
|
2495
|
+
|
2496
|
+
if rights.any?
|
2497
|
+
bounds(rights.first.location)
|
2498
|
+
post = on_mlhs_new
|
2499
|
+
|
2500
|
+
rights.each do |right|
|
2501
|
+
bounds(right.location)
|
2502
|
+
post = on_mlhs_add(post, visit(right))
|
2503
|
+
end
|
2504
|
+
|
2505
|
+
mlhs = on_mlhs_add_post(mlhs, post)
|
2506
|
+
end
|
2507
|
+
|
2508
|
+
mlhs
|
2509
|
+
end
|
2510
|
+
|
2511
|
+
# foo, bar = baz
|
2512
|
+
# ^^^^^^^^^^^^^^
|
2513
|
+
def visit_multi_write_node(node)
|
2514
|
+
bounds(node.location)
|
2515
|
+
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, true)
|
2516
|
+
|
2517
|
+
unless node.lparen_loc.nil?
|
2518
|
+
bounds(node.lparen_loc)
|
2519
|
+
targets = on_mlhs_paren(targets)
|
2520
|
+
end
|
2521
|
+
|
2522
|
+
value = visit_write_value(node.value)
|
2523
|
+
|
2524
|
+
bounds(node.location)
|
2525
|
+
on_massign(targets, value)
|
2526
|
+
end
|
2527
|
+
|
2528
|
+
# next
|
2529
|
+
# ^^^^
|
2530
|
+
#
|
2531
|
+
# next foo
|
2532
|
+
# ^^^^^^^^
|
2533
|
+
def visit_next_node(node)
|
2534
|
+
if node.arguments.nil?
|
2535
|
+
bounds(node.location)
|
2536
|
+
on_next(on_args_new)
|
2537
|
+
else
|
2538
|
+
arguments = visit(node.arguments)
|
2539
|
+
|
2540
|
+
bounds(node.location)
|
2541
|
+
on_next(arguments)
|
2542
|
+
end
|
2543
|
+
end
|
2544
|
+
|
2545
|
+
# nil
|
2546
|
+
# ^^^
|
2547
|
+
def visit_nil_node(node)
|
2548
|
+
bounds(node.location)
|
2549
|
+
on_var_ref(on_kw("nil"))
|
2550
|
+
end
|
2551
|
+
|
2552
|
+
# def foo(**nil); end
|
2553
|
+
# ^^^^^
|
2554
|
+
def visit_no_keywords_parameter_node(node)
|
2555
|
+
bounds(node.location)
|
2556
|
+
on_nokw_param(nil)
|
2557
|
+
|
2558
|
+
:nil
|
2559
|
+
end
|
2560
|
+
|
2561
|
+
# -> { _1 + _2 }
|
2562
|
+
# ^^^^^^^^^^^^^^
|
2563
|
+
def visit_numbered_parameters_node(node)
|
2564
|
+
end
|
2565
|
+
|
2566
|
+
# $1
|
2567
|
+
# ^^
|
2568
|
+
def visit_numbered_reference_read_node(node)
|
2569
|
+
bounds(node.location)
|
2570
|
+
on_backref(node.slice)
|
2571
|
+
end
|
2572
|
+
|
2573
|
+
# def foo(bar: baz); end
|
2574
|
+
# ^^^^^^^^
|
2575
|
+
def visit_optional_keyword_parameter_node(node)
|
2576
|
+
bounds(node.name_loc)
|
2577
|
+
name = on_label("#{node.name}:")
|
2578
|
+
value = visit(node.value)
|
2579
|
+
|
2580
|
+
[name, value]
|
2581
|
+
end
|
2582
|
+
|
2583
|
+
# def foo(bar = 1); end
|
2584
|
+
# ^^^^^^^
|
2585
|
+
def visit_optional_parameter_node(node)
|
2586
|
+
bounds(node.name_loc)
|
2587
|
+
name = visit_token(node.name.to_s)
|
2588
|
+
value = visit(node.value)
|
2589
|
+
|
2590
|
+
[name, value]
|
2591
|
+
end
|
2592
|
+
|
2593
|
+
# a or b
|
2594
|
+
# ^^^^^^
|
2595
|
+
def visit_or_node(node)
|
2596
|
+
left = visit(node.left)
|
2597
|
+
right = visit(node.right)
|
2598
|
+
|
2599
|
+
bounds(node.location)
|
2600
|
+
on_binary(left, node.operator.to_sym, right)
|
2601
|
+
end
|
2602
|
+
|
2603
|
+
# def foo(bar, *baz); end
|
2604
|
+
# ^^^^^^^^^
|
2605
|
+
def visit_parameters_node(node)
|
2606
|
+
requireds = node.requireds.map { |required| required.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(required) : visit(required) } if node.requireds.any?
|
2607
|
+
optionals = visit_all(node.optionals) if node.optionals.any?
|
2608
|
+
rest = visit(node.rest)
|
2609
|
+
posts = node.posts.map { |post| post.is_a?(MultiTargetNode) ? visit_destructured_parameter_node(post) : visit(post) } if node.posts.any?
|
2610
|
+
keywords = visit_all(node.keywords) if node.keywords.any?
|
2611
|
+
keyword_rest = visit(node.keyword_rest)
|
2612
|
+
block = visit(node.block)
|
2613
|
+
|
2614
|
+
bounds(node.location)
|
2615
|
+
on_params(requireds, optionals, rest, posts, keywords, keyword_rest, block)
|
2616
|
+
end
|
2617
|
+
|
2618
|
+
# Visit a destructured positional parameter node.
|
2619
|
+
private def visit_destructured_parameter_node(node)
|
2620
|
+
bounds(node.location)
|
2621
|
+
targets = visit_multi_target_node_targets(node.lefts, node.rest, node.rights, false)
|
2622
|
+
|
2623
|
+
bounds(node.lparen_loc)
|
2624
|
+
on_mlhs_paren(targets)
|
2625
|
+
end
|
2626
|
+
|
2627
|
+
# ()
|
2628
|
+
# ^^
|
2629
|
+
#
|
2630
|
+
# (1)
|
2631
|
+
# ^^^
|
2632
|
+
def visit_parentheses_node(node)
|
2633
|
+
body =
|
2634
|
+
if node.body.nil?
|
2635
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
2636
|
+
else
|
2637
|
+
visit(node.body)
|
2638
|
+
end
|
2639
|
+
|
2640
|
+
bounds(node.location)
|
2641
|
+
on_paren(body)
|
2642
|
+
end
|
2643
|
+
|
2644
|
+
# foo => ^(bar)
|
2645
|
+
# ^^^^^^
|
2646
|
+
def visit_pinned_expression_node(node)
|
2647
|
+
expression = visit(node.expression)
|
2648
|
+
|
2649
|
+
bounds(node.location)
|
2650
|
+
on_begin(expression)
|
2651
|
+
end
|
2652
|
+
|
2653
|
+
# foo = 1 and bar => ^foo
|
2654
|
+
# ^^^^
|
2655
|
+
def visit_pinned_variable_node(node)
|
2656
|
+
visit(node.variable)
|
2657
|
+
end
|
2658
|
+
|
2659
|
+
# END {}
|
2660
|
+
# ^^^^^^
|
2661
|
+
def visit_post_execution_node(node)
|
2662
|
+
statements =
|
2663
|
+
if node.statements.nil?
|
2664
|
+
bounds(node.location)
|
2665
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
2666
|
+
else
|
2667
|
+
visit(node.statements)
|
2668
|
+
end
|
2669
|
+
|
2670
|
+
bounds(node.location)
|
2671
|
+
on_END(statements)
|
2672
|
+
end
|
2673
|
+
|
2674
|
+
# BEGIN {}
|
2675
|
+
# ^^^^^^^^
|
2676
|
+
def visit_pre_execution_node(node)
|
2677
|
+
statements =
|
2678
|
+
if node.statements.nil?
|
2679
|
+
bounds(node.location)
|
2680
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
2681
|
+
else
|
2682
|
+
visit(node.statements)
|
2683
|
+
end
|
2684
|
+
|
2685
|
+
bounds(node.location)
|
2686
|
+
on_BEGIN(statements)
|
2687
|
+
end
|
2688
|
+
|
2689
|
+
# The top-level program node.
|
2690
|
+
def visit_program_node(node)
|
2691
|
+
body = node.statements.body
|
2692
|
+
body << nil if body.empty?
|
2693
|
+
statements = visit_statements_node_body(body)
|
2694
|
+
|
2695
|
+
bounds(node.location)
|
2696
|
+
on_program(statements)
|
2697
|
+
end
|
2698
|
+
|
2699
|
+
# 0..5
|
2700
|
+
# ^^^^
|
2701
|
+
def visit_range_node(node)
|
2702
|
+
left = visit(node.left)
|
2703
|
+
right = visit(node.right)
|
2704
|
+
|
2705
|
+
bounds(node.location)
|
2706
|
+
if node.exclude_end?
|
2707
|
+
on_dot3(left, right)
|
2708
|
+
else
|
2709
|
+
on_dot2(left, right)
|
2710
|
+
end
|
2711
|
+
end
|
2712
|
+
|
2713
|
+
# 1r
|
2714
|
+
# ^^
|
2715
|
+
def visit_rational_node(node)
|
2716
|
+
visit_number_node(node) { |text| on_rational(text) }
|
2717
|
+
end
|
2718
|
+
|
2719
|
+
# redo
|
2720
|
+
# ^^^^
|
2721
|
+
def visit_redo_node(node)
|
2722
|
+
bounds(node.location)
|
2723
|
+
on_redo
|
2724
|
+
end
|
2725
|
+
|
2726
|
+
# /foo/
|
2727
|
+
# ^^^^^
|
2728
|
+
def visit_regular_expression_node(node)
|
2729
|
+
bounds(node.opening_loc)
|
2730
|
+
on_regexp_beg(node.opening)
|
2731
|
+
|
2732
|
+
if node.content.empty?
|
2733
|
+
bounds(node.closing_loc)
|
2734
|
+
closing = on_regexp_end(node.closing)
|
2735
|
+
|
2736
|
+
on_regexp_literal(on_regexp_new, closing)
|
2737
|
+
else
|
2738
|
+
bounds(node.content_loc)
|
2739
|
+
tstring_content = on_tstring_content(node.content)
|
2740
|
+
|
2741
|
+
bounds(node.closing_loc)
|
2742
|
+
closing = on_regexp_end(node.closing)
|
2743
|
+
|
2744
|
+
on_regexp_literal(on_regexp_add(on_regexp_new, tstring_content), closing)
|
2745
|
+
end
|
2746
|
+
end
|
2747
|
+
|
2748
|
+
# def foo(bar:); end
|
2749
|
+
# ^^^^
|
2750
|
+
def visit_required_keyword_parameter_node(node)
|
2751
|
+
bounds(node.name_loc)
|
2752
|
+
[on_label("#{node.name}:"), false]
|
2753
|
+
end
|
2754
|
+
|
2755
|
+
# def foo(bar); end
|
2756
|
+
# ^^^
|
2757
|
+
def visit_required_parameter_node(node)
|
2758
|
+
bounds(node.location)
|
2759
|
+
on_ident(node.name.to_s)
|
2760
|
+
end
|
2761
|
+
|
2762
|
+
# foo rescue bar
|
2763
|
+
# ^^^^^^^^^^^^^^
|
2764
|
+
def visit_rescue_modifier_node(node)
|
2765
|
+
expression = visit_write_value(node.expression)
|
2766
|
+
rescue_expression = visit(node.rescue_expression)
|
2767
|
+
|
2768
|
+
bounds(node.location)
|
2769
|
+
on_rescue_mod(expression, rescue_expression)
|
2770
|
+
end
|
2771
|
+
|
2772
|
+
# begin; rescue; end
|
2773
|
+
# ^^^^^^^
|
2774
|
+
def visit_rescue_node(node)
|
2775
|
+
exceptions =
|
2776
|
+
case node.exceptions.length
|
2777
|
+
when 0
|
2778
|
+
nil
|
2779
|
+
when 1
|
2780
|
+
if (exception = node.exceptions.first).is_a?(SplatNode)
|
2781
|
+
bounds(exception.location)
|
2782
|
+
on_mrhs_add_star(on_mrhs_new, visit(exception))
|
2783
|
+
else
|
2784
|
+
[visit(node.exceptions.first)]
|
2785
|
+
end
|
2786
|
+
else
|
2787
|
+
bounds(node.location)
|
2788
|
+
length = node.exceptions.length
|
2789
|
+
|
2790
|
+
node.exceptions.each_with_index.inject(on_args_new) do |mrhs, (exception, index)|
|
2791
|
+
arg = visit(exception)
|
2792
|
+
|
2793
|
+
bounds(exception.location)
|
2794
|
+
mrhs = on_mrhs_new_from_args(mrhs) if index == length - 1
|
2795
|
+
|
2796
|
+
if exception.is_a?(SplatNode)
|
2797
|
+
if index == length - 1
|
2798
|
+
on_mrhs_add_star(mrhs, arg)
|
2799
|
+
else
|
2800
|
+
on_args_add_star(mrhs, arg)
|
2801
|
+
end
|
2802
|
+
else
|
2803
|
+
if index == length - 1
|
2804
|
+
on_mrhs_add(mrhs, arg)
|
2805
|
+
else
|
2806
|
+
on_args_add(mrhs, arg)
|
2807
|
+
end
|
2808
|
+
end
|
2809
|
+
end
|
2810
|
+
end
|
2811
|
+
|
2812
|
+
reference = visit(node.reference)
|
2813
|
+
statements =
|
2814
|
+
if node.statements.nil?
|
2815
|
+
bounds(node.location)
|
2816
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
440
2817
|
else
|
441
|
-
|
442
|
-
return on_command(ident_val, nil)
|
443
|
-
else
|
444
|
-
args = on_args_add_block(visit_elements(node.arguments.arguments), false)
|
445
|
-
return on_command(ident_val, args)
|
446
|
-
end
|
2818
|
+
visit(node.statements)
|
447
2819
|
end
|
2820
|
+
|
2821
|
+
subsequent = visit(node.subsequent)
|
2822
|
+
|
2823
|
+
bounds(node.location)
|
2824
|
+
on_rescue(exceptions, reference, statements, subsequent)
|
2825
|
+
end
|
2826
|
+
|
2827
|
+
# def foo(*bar); end
|
2828
|
+
# ^^^^
|
2829
|
+
#
|
2830
|
+
# def foo(*); end
|
2831
|
+
# ^
|
2832
|
+
def visit_rest_parameter_node(node)
|
2833
|
+
if node.name_loc.nil?
|
2834
|
+
bounds(node.location)
|
2835
|
+
on_rest_param(nil)
|
448
2836
|
else
|
449
|
-
|
450
|
-
|
451
|
-
|
2837
|
+
bounds(node.name_loc)
|
2838
|
+
on_rest_param(visit_token(node.name.to_s))
|
2839
|
+
end
|
2840
|
+
end
|
452
2841
|
|
453
|
-
|
454
|
-
|
2842
|
+
# retry
|
2843
|
+
# ^^^^^
|
2844
|
+
def visit_retry_node(node)
|
2845
|
+
bounds(node.location)
|
2846
|
+
on_retry
|
2847
|
+
end
|
455
2848
|
|
456
|
-
|
457
|
-
|
2849
|
+
# return
|
2850
|
+
# ^^^^^^
|
2851
|
+
#
|
2852
|
+
# return 1
|
2853
|
+
# ^^^^^^^^
|
2854
|
+
def visit_return_node(node)
|
2855
|
+
if node.arguments.nil?
|
2856
|
+
bounds(node.location)
|
2857
|
+
on_return0
|
2858
|
+
else
|
2859
|
+
arguments = visit(node.arguments)
|
458
2860
|
|
459
|
-
|
2861
|
+
bounds(node.location)
|
2862
|
+
on_return(arguments)
|
2863
|
+
end
|
2864
|
+
end
|
460
2865
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
2866
|
+
# self
|
2867
|
+
# ^^^^
|
2868
|
+
def visit_self_node(node)
|
2869
|
+
bounds(node.location)
|
2870
|
+
on_var_ref(on_kw("self"))
|
2871
|
+
end
|
2872
|
+
|
2873
|
+
# A shareable constant.
|
2874
|
+
def visit_shareable_constant_node(node)
|
2875
|
+
visit(node.write)
|
2876
|
+
end
|
2877
|
+
|
2878
|
+
# class << self; end
|
2879
|
+
# ^^^^^^^^^^^^^^^^^^
|
2880
|
+
def visit_singleton_class_node(node)
|
2881
|
+
expression = visit(node.expression)
|
2882
|
+
bodystmt = visit_body_node(node.body&.location || node.end_keyword_loc, node.body)
|
2883
|
+
|
2884
|
+
bounds(node.location)
|
2885
|
+
on_sclass(expression, bodystmt)
|
2886
|
+
end
|
2887
|
+
|
2888
|
+
# __ENCODING__
|
2889
|
+
# ^^^^^^^^^^^^
|
2890
|
+
def visit_source_encoding_node(node)
|
2891
|
+
bounds(node.location)
|
2892
|
+
on_var_ref(on_kw("__ENCODING__"))
|
2893
|
+
end
|
2894
|
+
|
2895
|
+
# __FILE__
|
2896
|
+
# ^^^^^^^^
|
2897
|
+
def visit_source_file_node(node)
|
2898
|
+
bounds(node.location)
|
2899
|
+
on_var_ref(on_kw("__FILE__"))
|
2900
|
+
end
|
2901
|
+
|
2902
|
+
# __LINE__
|
2903
|
+
# ^^^^^^^^
|
2904
|
+
def visit_source_line_node(node)
|
2905
|
+
bounds(node.location)
|
2906
|
+
on_var_ref(on_kw("__LINE__"))
|
2907
|
+
end
|
2908
|
+
|
2909
|
+
# foo(*bar)
|
2910
|
+
# ^^^^
|
2911
|
+
#
|
2912
|
+
# def foo((bar, *baz)); end
|
2913
|
+
# ^^^^
|
2914
|
+
#
|
2915
|
+
# def foo(*); bar(*); end
|
2916
|
+
# ^
|
2917
|
+
def visit_splat_node(node)
|
2918
|
+
visit(node.expression)
|
2919
|
+
end
|
2920
|
+
|
2921
|
+
# A list of statements.
|
2922
|
+
def visit_statements_node(node)
|
2923
|
+
bounds(node.location)
|
2924
|
+
visit_statements_node_body(node.body)
|
2925
|
+
end
|
2926
|
+
|
2927
|
+
# Visit the list of statements of a statements node. We support nil
|
2928
|
+
# statements in the list. This would normally not be allowed by the
|
2929
|
+
# structure of the prism parse tree, but we manually add them here so that
|
2930
|
+
# we can mirror Ripper's void stmt.
|
2931
|
+
private def visit_statements_node_body(body)
|
2932
|
+
body.inject(on_stmts_new) do |stmts, stmt|
|
2933
|
+
on_stmts_add(stmts, stmt.nil? ? on_void_stmt : visit(stmt))
|
2934
|
+
end
|
2935
|
+
end
|
2936
|
+
|
2937
|
+
# "foo"
|
2938
|
+
# ^^^^^
|
2939
|
+
def visit_string_node(node)
|
2940
|
+
if (content = node.content).empty?
|
2941
|
+
bounds(node.location)
|
2942
|
+
on_string_literal(on_string_content)
|
2943
|
+
elsif (opening = node.opening) == "?"
|
2944
|
+
bounds(node.location)
|
2945
|
+
on_CHAR("?#{node.content}")
|
2946
|
+
elsif opening.start_with?("<<~")
|
2947
|
+
heredoc = visit_heredoc_string_node(node.to_interpolated)
|
2948
|
+
|
2949
|
+
bounds(node.location)
|
2950
|
+
on_string_literal(heredoc)
|
2951
|
+
else
|
2952
|
+
bounds(node.content_loc)
|
2953
|
+
tstring_content = on_tstring_content(content)
|
2954
|
+
|
2955
|
+
bounds(node.location)
|
2956
|
+
on_string_literal(on_string_add(on_string_content, tstring_content))
|
2957
|
+
end
|
2958
|
+
end
|
2959
|
+
|
2960
|
+
# Ripper gives back the escaped string content but strips out the common
|
2961
|
+
# leading whitespace. Prism gives back the unescaped string content and
|
2962
|
+
# a location for the escaped string content. Unfortunately these don't
|
2963
|
+
# work well together, so here we need to re-derive the common leading
|
2964
|
+
# whitespace.
|
2965
|
+
private def visit_heredoc_node_whitespace(parts)
|
2966
|
+
common_whitespace = nil
|
2967
|
+
dedent_next = true
|
2968
|
+
|
2969
|
+
parts.each do |part|
|
2970
|
+
if part.is_a?(StringNode)
|
2971
|
+
if dedent_next && !(content = part.content).chomp.empty?
|
2972
|
+
common_whitespace = [
|
2973
|
+
common_whitespace || Float::INFINITY,
|
2974
|
+
content[/\A\s*/].each_char.inject(0) do |part_whitespace, char|
|
2975
|
+
char == "\t" ? ((part_whitespace / 8 + 1) * 8) : (part_whitespace + 1)
|
2976
|
+
end
|
2977
|
+
].min
|
466
2978
|
end
|
2979
|
+
|
2980
|
+
dedent_next = true
|
467
2981
|
else
|
468
|
-
|
2982
|
+
dedent_next = false
|
469
2983
|
end
|
470
2984
|
end
|
2985
|
+
|
2986
|
+
common_whitespace || 0
|
471
2987
|
end
|
472
2988
|
|
473
|
-
# Visit a
|
474
|
-
def
|
475
|
-
|
476
|
-
|
477
|
-
|
2989
|
+
# Visit a string that is expressed using a <<~ heredoc.
|
2990
|
+
private def visit_heredoc_node(parts, base)
|
2991
|
+
common_whitespace = visit_heredoc_node_whitespace(parts)
|
2992
|
+
|
2993
|
+
if common_whitespace == 0
|
2994
|
+
bounds(parts.first.location)
|
2995
|
+
|
2996
|
+
string = []
|
2997
|
+
result = base
|
2998
|
+
|
2999
|
+
parts.each do |part|
|
3000
|
+
if part.is_a?(StringNode)
|
3001
|
+
if string.empty?
|
3002
|
+
string = [part]
|
3003
|
+
else
|
3004
|
+
string << part
|
3005
|
+
end
|
3006
|
+
else
|
3007
|
+
unless string.empty?
|
3008
|
+
bounds(string[0].location)
|
3009
|
+
result = yield result, on_tstring_content(string.map(&:content).join)
|
3010
|
+
string = []
|
3011
|
+
end
|
3012
|
+
|
3013
|
+
result = yield result, visit(part)
|
3014
|
+
end
|
3015
|
+
end
|
3016
|
+
|
3017
|
+
unless string.empty?
|
3018
|
+
bounds(string[0].location)
|
3019
|
+
result = yield result, on_tstring_content(string.map(&:content).join)
|
3020
|
+
end
|
3021
|
+
|
3022
|
+
result
|
3023
|
+
else
|
3024
|
+
bounds(parts.first.location)
|
3025
|
+
result =
|
3026
|
+
parts.inject(base) do |string_content, part|
|
3027
|
+
yield string_content, visit_string_content(part)
|
3028
|
+
end
|
3029
|
+
|
3030
|
+
bounds(parts.first.location)
|
3031
|
+
on_heredoc_dedent(result, common_whitespace)
|
478
3032
|
end
|
479
3033
|
end
|
480
3034
|
|
481
|
-
# Visit
|
482
|
-
def
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
3035
|
+
# Visit a heredoc node that is representing a string.
|
3036
|
+
private def visit_heredoc_string_node(node)
|
3037
|
+
bounds(node.opening_loc)
|
3038
|
+
on_heredoc_beg(node.opening)
|
3039
|
+
|
3040
|
+
bounds(node.location)
|
3041
|
+
result =
|
3042
|
+
visit_heredoc_node(node.parts, on_string_content) do |parts, part|
|
3043
|
+
on_string_add(parts, part)
|
3044
|
+
end
|
3045
|
+
|
3046
|
+
bounds(node.closing_loc)
|
3047
|
+
on_heredoc_end(node.closing)
|
3048
|
+
|
3049
|
+
result
|
3050
|
+
end
|
3051
|
+
|
3052
|
+
# Visit a heredoc node that is representing an xstring.
|
3053
|
+
private def visit_heredoc_x_string_node(node)
|
3054
|
+
bounds(node.opening_loc)
|
3055
|
+
on_heredoc_beg(node.opening)
|
3056
|
+
|
3057
|
+
bounds(node.location)
|
3058
|
+
result =
|
3059
|
+
visit_heredoc_node(node.parts, on_xstring_new) do |parts, part|
|
3060
|
+
on_xstring_add(parts, part)
|
492
3061
|
end
|
3062
|
+
|
3063
|
+
bounds(node.closing_loc)
|
3064
|
+
on_heredoc_end(node.closing)
|
3065
|
+
|
3066
|
+
result
|
3067
|
+
end
|
3068
|
+
|
3069
|
+
# super(foo)
|
3070
|
+
# ^^^^^^^^^^
|
3071
|
+
def visit_super_node(node)
|
3072
|
+
arguments, block = visit_call_node_arguments(node.arguments, node.block, trailing_comma?(node.arguments&.location || node.location, node.rparen_loc || node.location))
|
3073
|
+
|
3074
|
+
if !node.lparen_loc.nil?
|
3075
|
+
bounds(node.lparen_loc)
|
3076
|
+
arguments = on_arg_paren(arguments)
|
493
3077
|
end
|
494
3078
|
|
495
|
-
|
496
|
-
|
3079
|
+
bounds(node.location)
|
3080
|
+
call = on_super(arguments)
|
3081
|
+
|
3082
|
+
if block.nil?
|
3083
|
+
call
|
3084
|
+
else
|
3085
|
+
bounds(node.block.location)
|
3086
|
+
on_method_add_block(call, block)
|
497
3087
|
end
|
498
3088
|
end
|
499
3089
|
|
500
|
-
#
|
501
|
-
|
502
|
-
|
503
|
-
|
3090
|
+
# :foo
|
3091
|
+
# ^^^^
|
3092
|
+
def visit_symbol_node(node)
|
3093
|
+
if (opening = node.opening)&.match?(/^%s|['"]:?$/)
|
3094
|
+
bounds(node.value_loc)
|
3095
|
+
content = on_string_content
|
504
3096
|
|
505
|
-
|
506
|
-
|
3097
|
+
if !(value = node.value).empty?
|
3098
|
+
content = on_string_add(content, on_tstring_content(value))
|
3099
|
+
end
|
507
3100
|
|
508
|
-
|
3101
|
+
on_dyna_symbol(content)
|
3102
|
+
elsif (closing = node.closing) == ":"
|
3103
|
+
bounds(node.location)
|
3104
|
+
on_label("#{node.value}:")
|
3105
|
+
elsif opening.nil? && node.closing_loc.nil?
|
3106
|
+
bounds(node.value_loc)
|
3107
|
+
on_symbol_literal(visit_token(node.value))
|
3108
|
+
else
|
3109
|
+
bounds(node.value_loc)
|
3110
|
+
on_symbol_literal(on_symbol(visit_token(node.value)))
|
3111
|
+
end
|
509
3112
|
end
|
510
3113
|
|
511
|
-
#
|
512
|
-
#
|
513
|
-
def
|
514
|
-
|
515
|
-
|
516
|
-
on_aref(visit(node.receiver), args_val)
|
3114
|
+
# true
|
3115
|
+
# ^^^^
|
3116
|
+
def visit_true_node(node)
|
3117
|
+
bounds(node.location)
|
3118
|
+
on_var_ref(on_kw("true"))
|
517
3119
|
end
|
518
3120
|
|
519
|
-
#
|
520
|
-
#
|
521
|
-
def
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
3121
|
+
# undef foo
|
3122
|
+
# ^^^^^^^^^
|
3123
|
+
def visit_undef_node(node)
|
3124
|
+
names = visit_all(node.names)
|
3125
|
+
|
3126
|
+
bounds(node.location)
|
3127
|
+
on_undef(names)
|
526
3128
|
end
|
527
3129
|
|
528
|
-
#
|
529
|
-
#
|
530
|
-
#
|
531
|
-
#
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
"elsif",
|
545
|
-
"end",
|
546
|
-
"END",
|
547
|
-
"ensure",
|
548
|
-
"false",
|
549
|
-
"for",
|
550
|
-
"if",
|
551
|
-
"in",
|
552
|
-
"module",
|
553
|
-
"next",
|
554
|
-
"nil",
|
555
|
-
"not",
|
556
|
-
"or",
|
557
|
-
"redo",
|
558
|
-
"rescue",
|
559
|
-
"retry",
|
560
|
-
"return",
|
561
|
-
"self",
|
562
|
-
"super",
|
563
|
-
"then",
|
564
|
-
"true",
|
565
|
-
"undef",
|
566
|
-
"unless",
|
567
|
-
"until",
|
568
|
-
"when",
|
569
|
-
"while",
|
570
|
-
"yield",
|
571
|
-
"__ENCODING__",
|
572
|
-
"__FILE__",
|
573
|
-
"__LINE__",
|
574
|
-
]
|
3130
|
+
# unless foo; bar end
|
3131
|
+
# ^^^^^^^^^^^^^^^^^^^
|
3132
|
+
#
|
3133
|
+
# bar unless foo
|
3134
|
+
# ^^^^^^^^^^^^^^
|
3135
|
+
def visit_unless_node(node)
|
3136
|
+
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
|
3137
|
+
predicate = visit(node.predicate)
|
3138
|
+
statements =
|
3139
|
+
if node.statements.nil?
|
3140
|
+
bounds(node.location)
|
3141
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
3142
|
+
else
|
3143
|
+
visit(node.statements)
|
3144
|
+
end
|
3145
|
+
else_clause = visit(node.else_clause)
|
575
3146
|
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
bounds(node.
|
583
|
-
|
584
|
-
|
585
|
-
|
3147
|
+
bounds(node.location)
|
3148
|
+
on_unless(predicate, statements, else_clause)
|
3149
|
+
else
|
3150
|
+
statements = visit(node.statements.body.first)
|
3151
|
+
predicate = visit(node.predicate)
|
3152
|
+
|
3153
|
+
bounds(node.location)
|
3154
|
+
on_unless_mod(predicate, statements)
|
3155
|
+
end
|
3156
|
+
end
|
3157
|
+
|
3158
|
+
# until foo; bar end
|
3159
|
+
# ^^^^^^^^^^^^^^^^^
|
3160
|
+
#
|
3161
|
+
# bar until foo
|
3162
|
+
# ^^^^^^^^^^^^^
|
3163
|
+
def visit_until_node(node)
|
3164
|
+
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
|
3165
|
+
predicate = visit(node.predicate)
|
3166
|
+
statements =
|
3167
|
+
if node.statements.nil?
|
3168
|
+
bounds(node.location)
|
3169
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
3170
|
+
else
|
3171
|
+
visit(node.statements)
|
3172
|
+
end
|
3173
|
+
|
3174
|
+
bounds(node.location)
|
3175
|
+
on_until(predicate, statements)
|
3176
|
+
else
|
3177
|
+
statements = visit(node.statements.body.first)
|
3178
|
+
predicate = visit(node.predicate)
|
3179
|
+
|
3180
|
+
bounds(node.location)
|
3181
|
+
on_until_mod(predicate, statements)
|
3182
|
+
end
|
3183
|
+
end
|
3184
|
+
|
3185
|
+
# case foo; when bar; end
|
3186
|
+
# ^^^^^^^^^^^^^
|
3187
|
+
def visit_when_node(node)
|
3188
|
+
# This is a special case where we're not going to call on_when directly
|
3189
|
+
# because we don't have access to the subsequent. Instead, we'll return
|
3190
|
+
# the component parts and let the parent node handle it.
|
3191
|
+
conditions = visit_arguments(node.conditions)
|
3192
|
+
statements =
|
3193
|
+
if node.statements.nil?
|
3194
|
+
bounds(node.location)
|
3195
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
586
3196
|
else
|
587
|
-
|
588
|
-
|
3197
|
+
visit(node.statements)
|
3198
|
+
end
|
3199
|
+
|
3200
|
+
[conditions, statements]
|
3201
|
+
end
|
3202
|
+
|
3203
|
+
# while foo; bar end
|
3204
|
+
# ^^^^^^^^^^^^^^^^^^
|
3205
|
+
#
|
3206
|
+
# bar while foo
|
3207
|
+
# ^^^^^^^^^^^^^
|
3208
|
+
def visit_while_node(node)
|
3209
|
+
if node.statements.nil? || (node.predicate.location.start_offset < node.statements.location.start_offset)
|
3210
|
+
predicate = visit(node.predicate)
|
3211
|
+
statements =
|
3212
|
+
if node.statements.nil?
|
3213
|
+
bounds(node.location)
|
3214
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
3215
|
+
else
|
3216
|
+
visit(node.statements)
|
3217
|
+
end
|
3218
|
+
|
3219
|
+
bounds(node.location)
|
3220
|
+
on_while(predicate, statements)
|
3221
|
+
else
|
3222
|
+
statements = visit(node.statements.body.first)
|
3223
|
+
predicate = visit(node.predicate)
|
3224
|
+
|
3225
|
+
bounds(node.location)
|
3226
|
+
on_while_mod(predicate, statements)
|
3227
|
+
end
|
3228
|
+
end
|
3229
|
+
|
3230
|
+
# `foo`
|
3231
|
+
# ^^^^^
|
3232
|
+
def visit_x_string_node(node)
|
3233
|
+
if node.unescaped.empty?
|
3234
|
+
bounds(node.location)
|
3235
|
+
on_xstring_literal(on_xstring_new)
|
3236
|
+
elsif node.opening.start_with?("<<~")
|
3237
|
+
heredoc = visit_heredoc_x_string_node(node.to_interpolated)
|
3238
|
+
|
3239
|
+
bounds(node.location)
|
3240
|
+
on_xstring_literal(heredoc)
|
3241
|
+
else
|
3242
|
+
bounds(node.content_loc)
|
3243
|
+
content = on_tstring_content(node.content)
|
3244
|
+
|
3245
|
+
bounds(node.location)
|
3246
|
+
on_xstring_literal(on_xstring_add(on_xstring_new, content))
|
3247
|
+
end
|
3248
|
+
end
|
3249
|
+
|
3250
|
+
# yield
|
3251
|
+
# ^^^^^
|
3252
|
+
#
|
3253
|
+
# yield 1
|
3254
|
+
# ^^^^^^^
|
3255
|
+
def visit_yield_node(node)
|
3256
|
+
if node.arguments.nil? && node.lparen_loc.nil?
|
3257
|
+
bounds(node.location)
|
3258
|
+
on_yield0
|
3259
|
+
else
|
3260
|
+
arguments =
|
3261
|
+
if node.arguments.nil?
|
3262
|
+
bounds(node.location)
|
3263
|
+
on_args_new
|
3264
|
+
else
|
3265
|
+
visit(node.arguments)
|
3266
|
+
end
|
3267
|
+
|
3268
|
+
unless node.lparen_loc.nil?
|
3269
|
+
bounds(node.lparen_loc)
|
3270
|
+
arguments = on_paren(arguments)
|
589
3271
|
end
|
3272
|
+
|
3273
|
+
bounds(node.location)
|
3274
|
+
on_yield(arguments)
|
590
3275
|
end
|
3276
|
+
end
|
3277
|
+
|
3278
|
+
private
|
3279
|
+
|
3280
|
+
# Lazily initialize the parse result.
|
3281
|
+
def result
|
3282
|
+
@result ||= Prism.parse(source, partial_script: true)
|
3283
|
+
end
|
3284
|
+
|
3285
|
+
##########################################################################
|
3286
|
+
# Helpers
|
3287
|
+
##########################################################################
|
3288
|
+
|
3289
|
+
# Returns true if there is a comma between the two locations.
|
3290
|
+
def trailing_comma?(left, right)
|
3291
|
+
source.byteslice(left.end_offset...right.start_offset).include?(",")
|
3292
|
+
end
|
3293
|
+
|
3294
|
+
# Returns true if there is a semicolon between the two locations.
|
3295
|
+
def void_stmt?(left, right, allow_newline)
|
3296
|
+
pattern = allow_newline ? /[;\n]/ : /;/
|
3297
|
+
source.byteslice(left.end_offset...right.start_offset).match?(pattern)
|
3298
|
+
end
|
591
3299
|
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
3300
|
+
# Visit the string content of a particular node. This method is used to
|
3301
|
+
# split into the various token types.
|
3302
|
+
def visit_token(token, allow_keywords = true)
|
3303
|
+
case token
|
3304
|
+
when "."
|
3305
|
+
on_period(token)
|
3306
|
+
when "`"
|
3307
|
+
on_backtick(token)
|
3308
|
+
when *(allow_keywords ? KEYWORDS : [])
|
3309
|
+
on_kw(token)
|
3310
|
+
when /^_/
|
3311
|
+
on_ident(token)
|
3312
|
+
when /^[[:upper:]]\w*$/
|
3313
|
+
on_const(token)
|
3314
|
+
when /^@@/
|
3315
|
+
on_cvar(token)
|
3316
|
+
when /^@/
|
3317
|
+
on_ivar(token)
|
3318
|
+
when /^\$/
|
3319
|
+
on_gvar(token)
|
3320
|
+
when /^[[:punct:]]/
|
3321
|
+
on_op(token)
|
602
3322
|
else
|
603
|
-
|
3323
|
+
on_ident(token)
|
604
3324
|
end
|
605
|
-
sym_val = no_symbol_wrapper ? token_val : on_symbol(token_val)
|
606
|
-
on_symbol_literal(sym_val)
|
607
3325
|
end
|
608
3326
|
|
609
3327
|
# Visit a node that represents a number. We need to explicitly handle the
|
610
3328
|
# unary - operator.
|
611
|
-
def
|
3329
|
+
def visit_number_node(node)
|
612
3330
|
slice = node.slice
|
613
3331
|
location = node.location
|
614
3332
|
|
615
3333
|
if slice[0] == "-"
|
616
|
-
|
3334
|
+
bounds(location.copy(start_offset: location.start_offset + 1))
|
617
3335
|
value = yield slice[1..-1]
|
618
3336
|
|
619
3337
|
bounds(node.location)
|
620
|
-
on_unary(
|
3338
|
+
on_unary(:-@, value)
|
621
3339
|
else
|
622
3340
|
bounds(location)
|
623
3341
|
yield slice
|
624
3342
|
end
|
625
3343
|
end
|
626
3344
|
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
3345
|
+
# Visit a node that represents a write value. This is used to handle the
|
3346
|
+
# special case of an implicit array that is generated without brackets.
|
3347
|
+
def visit_write_value(node)
|
3348
|
+
if node.is_a?(ArrayNode) && node.opening_loc.nil?
|
3349
|
+
elements = node.elements
|
3350
|
+
length = elements.length
|
3351
|
+
|
3352
|
+
bounds(elements.first.location)
|
3353
|
+
elements.each_with_index.inject((elements.first.is_a?(SplatNode) && length == 1) ? on_mrhs_new : on_args_new) do |args, (element, index)|
|
3354
|
+
arg = visit(element)
|
3355
|
+
bounds(element.location)
|
3356
|
+
|
3357
|
+
if index == length - 1
|
3358
|
+
if element.is_a?(SplatNode)
|
3359
|
+
mrhs = index == 0 ? args : on_mrhs_new_from_args(args)
|
3360
|
+
on_mrhs_add_star(mrhs, arg)
|
3361
|
+
else
|
3362
|
+
on_mrhs_add(on_mrhs_new_from_args(args), arg)
|
3363
|
+
end
|
3364
|
+
else
|
3365
|
+
case element
|
3366
|
+
when BlockArgumentNode
|
3367
|
+
on_args_add_block(args, arg)
|
3368
|
+
when SplatNode
|
3369
|
+
on_args_add_star(args, arg)
|
3370
|
+
else
|
3371
|
+
on_args_add(args, arg)
|
3372
|
+
end
|
3373
|
+
end
|
3374
|
+
end
|
3375
|
+
else
|
3376
|
+
visit(node)
|
648
3377
|
end
|
649
3378
|
end
|
650
3379
|
|
651
|
-
# Visit a binary operator node like an AndNode or OrNode
|
652
|
-
def visit_binary_operator(node)
|
653
|
-
left_val = visit(node.left)
|
654
|
-
right_val = visit(node.right)
|
655
|
-
on_binary(left_val, node.operator.to_sym, right_val)
|
656
|
-
end
|
657
|
-
|
658
3380
|
# This method is responsible for updating lineno and column information
|
659
3381
|
# to reflect the current node.
|
660
3382
|
#
|
@@ -665,31 +3387,71 @@ module Prism
|
|
665
3387
|
@column = location.start_column
|
666
3388
|
end
|
667
3389
|
|
668
|
-
|
669
|
-
#
|
670
|
-
|
671
|
-
|
672
|
-
|
3390
|
+
##########################################################################
|
3391
|
+
# Ripper interface
|
3392
|
+
##########################################################################
|
3393
|
+
|
3394
|
+
# :stopdoc:
|
3395
|
+
def _dispatch_0; end
|
3396
|
+
def _dispatch_1(_); end
|
3397
|
+
def _dispatch_2(_, _); end
|
3398
|
+
def _dispatch_3(_, _, _); end
|
3399
|
+
def _dispatch_4(_, _, _, _); end
|
3400
|
+
def _dispatch_5(_, _, _, _, _); end
|
3401
|
+
def _dispatch_7(_, _, _, _, _, _, _); end
|
3402
|
+
# :startdoc:
|
3403
|
+
|
3404
|
+
#
|
3405
|
+
# Parser Events
|
3406
|
+
#
|
3407
|
+
|
3408
|
+
PARSER_EVENT_TABLE.each do |id, arity|
|
3409
|
+
alias_method "on_#{id}", "_dispatch_#{arity}"
|
673
3410
|
end
|
674
3411
|
|
675
|
-
#
|
676
|
-
|
677
|
-
|
3412
|
+
# This method is called when weak warning is produced by the parser.
|
3413
|
+
# +fmt+ and +args+ is printf style.
|
3414
|
+
def warn(fmt, *args)
|
3415
|
+
end
|
3416
|
+
|
3417
|
+
# This method is called when strong warning is produced by the parser.
|
3418
|
+
# +fmt+ and +args+ is printf style.
|
3419
|
+
def warning(fmt, *args)
|
3420
|
+
end
|
3421
|
+
|
3422
|
+
# This method is called when the parser found syntax error.
|
3423
|
+
def compile_error(msg)
|
678
3424
|
end
|
679
3425
|
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
3426
|
+
#
|
3427
|
+
# Scanner Events
|
3428
|
+
#
|
3429
|
+
|
3430
|
+
SCANNER_EVENTS.each do |id|
|
3431
|
+
alias_method "on_#{id}", :_dispatch_1
|
3432
|
+
end
|
687
3433
|
|
688
|
-
|
689
|
-
|
3434
|
+
# This method is provided by the Ripper C extension. It is called when a
|
3435
|
+
# string needs to be dedented because of a tilde heredoc. It is expected
|
3436
|
+
# that it will modify the string in place and return the number of bytes
|
3437
|
+
# that were removed.
|
3438
|
+
def dedent_string(string, width)
|
3439
|
+
whitespace = 0
|
3440
|
+
cursor = 0
|
3441
|
+
|
3442
|
+
while cursor < string.length && string[cursor].match?(/\s/) && whitespace < width
|
3443
|
+
if string[cursor] == "\t"
|
3444
|
+
whitespace = ((whitespace / 8 + 1) * 8)
|
3445
|
+
break if whitespace > width
|
3446
|
+
else
|
3447
|
+
whitespace += 1
|
3448
|
+
end
|
3449
|
+
|
3450
|
+
cursor += 1
|
3451
|
+
end
|
690
3452
|
|
691
|
-
|
692
|
-
|
3453
|
+
string.replace(string[cursor..])
|
3454
|
+
cursor
|
693
3455
|
end
|
694
3456
|
end
|
695
3457
|
end
|