jruby-prism-parser 0.23.0.pre.SNAPSHOT-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 +284 -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 +9 -11
- 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 +3841 -2000
- 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 +23 -3
- 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 +264 -80
- data/lib/prism/dispatcher.rb +45 -1
- data/lib/prism/dot_visitor.rb +201 -77
- data/lib/prism/dsl.rb +672 -457
- data/lib/prism/ffi.rb +308 -94
- 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 +9712 -8931
- 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 +458 -46
- 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 -902
- 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 +188 -11
- data/lib/prism/translation/parser33.rb +12 -0
- data/lib/prism/translation/parser34.rb +12 -0
- 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 +3267 -386
- 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 +59 -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 +1546 -1488
- data/src/prism.c +7822 -3044
- 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 +49 -8
- 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 +59 -21
- 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 -37
- 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
|
-
|
26
|
-
|
27
|
-
::Ripper::PARSER_EVENTS.each do |event|
|
28
|
-
define_method(:"on_#{event}") do |*args|
|
29
|
-
[event, *args]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
::Ripper::SCANNER_EVENTS.each do |event|
|
34
|
-
define_method(:"on_#{event}") do |value|
|
35
|
-
[:"@#{event}", value, [lineno, column]]
|
36
|
-
end
|
37
|
-
end
|
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
|
38
48
|
end
|
39
49
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
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)
|
45
74
|
|
46
|
-
|
47
|
-
|
75
|
+
if result.failure? && raise_errors
|
76
|
+
raise SyntaxError, result.errors.first.message
|
77
|
+
else
|
78
|
+
result.value
|
48
79
|
end
|
80
|
+
end
|
49
81
|
|
50
|
-
|
51
|
-
|
52
|
-
|
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
|
+
]
|
360
|
+
|
361
|
+
private_constant :KEYWORDS, :BINARY_OPERATORS
|
362
|
+
|
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,472 +542,2916 @@ 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
|
603
|
+
# a and b
|
604
|
+
# ^^^^^^^
|
605
|
+
def visit_and_node(node)
|
606
|
+
left = visit(node.left)
|
607
|
+
right = visit(node.right)
|
166
608
|
|
167
|
-
|
168
|
-
|
169
|
-
visit_binary_op_assign(node)
|
609
|
+
bounds(node.location)
|
610
|
+
on_binary(left, node.operator.to_sym, right)
|
170
611
|
end
|
171
612
|
|
172
|
-
#
|
173
|
-
|
174
|
-
|
175
|
-
|
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)
|
176
621
|
|
177
|
-
|
178
|
-
|
179
|
-
visit_binary_op_assign(node, operator: "#{node.operator}=")
|
180
|
-
end
|
622
|
+
elements = on_qwords_new
|
623
|
+
previous = nil
|
181
624
|
|
182
|
-
|
183
|
-
|
184
|
-
bounds(node.location)
|
185
|
-
ident_val = on_ident(node.slice)
|
625
|
+
node.elements.each do |element|
|
626
|
+
visit_words_sep(opening_loc, previous, element)
|
186
627
|
|
187
|
-
|
188
|
-
|
628
|
+
bounds(element.location)
|
629
|
+
elements = on_qwords_add(elements, on_tstring_content(element.content))
|
189
630
|
|
190
|
-
|
191
|
-
|
192
|
-
params_val = node.parameters.nil? ? nil : visit(node.parameters)
|
631
|
+
previous = element
|
632
|
+
end
|
193
633
|
|
194
|
-
|
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)
|
195
640
|
|
196
|
-
|
197
|
-
|
641
|
+
elements = on_qsymbols_new
|
642
|
+
previous = nil
|
198
643
|
|
199
|
-
|
200
|
-
|
201
|
-
on_block_var(visit(node.parameters), no_block_value)
|
202
|
-
end
|
644
|
+
node.elements.each do |element|
|
645
|
+
visit_words_sep(opening_loc, previous, element)
|
203
646
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
647
|
+
bounds(element.location)
|
648
|
+
elements = on_qsymbols_add(elements, on_tstring_content(element.value))
|
649
|
+
|
650
|
+
previous = element
|
651
|
+
end
|
652
|
+
|
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
|
689
|
+
|
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
|
726
|
+
|
727
|
+
bounds(node.closing_loc)
|
728
|
+
on_tstring_end(node.closing)
|
729
|
+
else
|
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)
|
737
|
+
end
|
210
738
|
|
211
|
-
# Visit a RequiredParameterNode.
|
212
|
-
def visit_required_parameter_node(node)
|
213
739
|
bounds(node.location)
|
214
|
-
|
740
|
+
on_array(elements)
|
215
741
|
end
|
216
742
|
|
217
|
-
#
|
218
|
-
|
219
|
-
|
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
|
220
748
|
|
221
|
-
|
222
|
-
|
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
|
223
753
|
end
|
224
754
|
|
225
|
-
# Visit an
|
226
|
-
def
|
227
|
-
|
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
|
228
771
|
end
|
229
772
|
|
230
|
-
#
|
231
|
-
|
232
|
-
|
233
|
-
|
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
|
234
787
|
|
235
|
-
|
236
|
-
def visit_true_node(node)
|
237
|
-
bounds(node.location)
|
238
|
-
on_var_ref(on_kw("true"))
|
239
|
-
end
|
788
|
+
posts = visit_all(node.posts) if node.posts.any?
|
240
789
|
|
241
|
-
# Visit a FalseNode.
|
242
|
-
def visit_false_node(node)
|
243
790
|
bounds(node.location)
|
244
|
-
|
791
|
+
on_aryptn(constant, requireds, rest, posts)
|
245
792
|
end
|
246
793
|
|
247
|
-
#
|
248
|
-
|
249
|
-
|
794
|
+
# foo(bar)
|
795
|
+
# ^^^
|
796
|
+
def visit_arguments_node(node)
|
797
|
+
arguments, _ = visit_call_node_arguments(node, nil, false)
|
798
|
+
arguments
|
250
799
|
end
|
251
800
|
|
252
|
-
#
|
253
|
-
|
254
|
-
|
255
|
-
|
801
|
+
# { a: 1 }
|
802
|
+
# ^^^^
|
803
|
+
def visit_assoc_node(node)
|
804
|
+
key = visit(node.key)
|
805
|
+
value = visit(node.value)
|
256
806
|
|
257
|
-
|
258
|
-
|
259
|
-
visit_number(node) { |text| on_int(text) }
|
807
|
+
bounds(node.location)
|
808
|
+
on_assoc_new(key, value)
|
260
809
|
end
|
261
810
|
|
262
|
-
#
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
end
|
811
|
+
# def foo(**); bar(**); end
|
812
|
+
# ^^
|
813
|
+
#
|
814
|
+
# { **foo }
|
815
|
+
# ^^^^^
|
816
|
+
def visit_assoc_splat_node(node)
|
817
|
+
value = visit(node.value)
|
270
818
|
|
271
819
|
bounds(node.location)
|
272
|
-
|
820
|
+
on_assoc_splat(value)
|
273
821
|
end
|
274
822
|
|
275
|
-
#
|
276
|
-
#
|
277
|
-
def
|
278
|
-
|
279
|
-
|
280
|
-
on_begin(on_bodystmt(visit(node.statements), rescue_val, nil, ensure_val))
|
823
|
+
# $+
|
824
|
+
# ^^
|
825
|
+
def visit_back_reference_read_node(node)
|
826
|
+
bounds(node.location)
|
827
|
+
on_backref(node.slice)
|
281
828
|
end
|
282
829
|
|
283
|
-
#
|
284
|
-
|
285
|
-
|
286
|
-
|
830
|
+
# begin end
|
831
|
+
# ^^^^^^^^^
|
832
|
+
def visit_begin_node(node)
|
833
|
+
clauses = visit_begin_node_clauses(node.begin_keyword_loc, node, false)
|
287
834
|
|
288
|
-
# Visit a ProgramNode node.
|
289
|
-
def visit_program_node(node)
|
290
|
-
statements = visit(node.statements)
|
291
835
|
bounds(node.location)
|
292
|
-
|
836
|
+
on_begin(clauses)
|
293
837
|
end
|
294
838
|
|
295
|
-
# Visit a
|
296
|
-
def
|
297
|
-
|
298
|
-
|
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?
|
843
|
+
on_stmts_add(on_stmts_new, on_void_stmt)
|
844
|
+
else
|
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)
|
850
|
+
end
|
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)
|
299
868
|
|
300
869
|
bounds(node.location)
|
301
|
-
|
302
|
-
|
870
|
+
on_bodystmt(statements, rescue_clause, else_clause, ensure_clause)
|
871
|
+
end
|
872
|
+
|
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)
|
303
889
|
else
|
304
|
-
|
890
|
+
raise
|
305
891
|
end
|
306
892
|
end
|
307
893
|
|
308
|
-
#
|
309
|
-
|
310
|
-
|
894
|
+
# foo(&bar)
|
895
|
+
# ^^^^
|
896
|
+
def visit_block_argument_node(node)
|
897
|
+
visit(node.expression)
|
311
898
|
end
|
312
899
|
|
313
|
-
#
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
900
|
+
# foo { |; bar| }
|
901
|
+
# ^^^
|
902
|
+
def visit_block_local_variable_node(node)
|
903
|
+
bounds(node.location)
|
904
|
+
on_ident(node.name.to_s)
|
318
905
|
end
|
319
906
|
|
320
|
-
# Visit
|
321
|
-
def
|
322
|
-
|
323
|
-
|
324
|
-
on_xstring_literal(on_xstring_add(on_xstring_new, tstring_val))
|
325
|
-
end
|
907
|
+
# Visit a BlockNode.
|
908
|
+
def visit_block_node(node)
|
909
|
+
braces = node.opening == "{"
|
910
|
+
parameters = visit(node.parameters)
|
326
911
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
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)
|
336
929
|
else
|
337
|
-
raise
|
930
|
+
raise
|
338
931
|
end
|
339
|
-
end
|
340
932
|
|
341
|
-
|
342
|
-
|
933
|
+
if braces
|
934
|
+
bounds(node.location)
|
935
|
+
on_brace_block(parameters, body)
|
936
|
+
else
|
937
|
+
bounds(node.location)
|
938
|
+
on_do_block(parameters, body)
|
343
939
|
end
|
344
|
-
|
345
|
-
on_string_literal(string_list)
|
346
940
|
end
|
347
941
|
|
348
|
-
#
|
349
|
-
|
350
|
-
|
351
|
-
|
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)
|
352
951
|
|
353
|
-
|
354
|
-
|
355
|
-
if (opening = node.opening) && (['"', "'"].include?(opening[-1]) || opening.start_with?("%s"))
|
356
|
-
bounds(node.value_loc)
|
357
|
-
tstring_val = on_tstring_content(node.value.to_s)
|
358
|
-
return on_dyna_symbol(on_string_add(on_string_content, tstring_val))
|
952
|
+
bounds(node.location)
|
953
|
+
on_blockarg(name)
|
359
954
|
end
|
360
|
-
|
361
|
-
bounds(node.value_loc)
|
362
|
-
ident_val = on_ident(node.value.to_s)
|
363
|
-
on_symbol_literal(on_symbol(ident_val))
|
364
955
|
end
|
365
956
|
|
366
|
-
#
|
367
|
-
def
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
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
|
373
965
|
|
374
|
-
|
375
|
-
|
376
|
-
|
966
|
+
locals =
|
967
|
+
if node.locals.any?
|
968
|
+
visit_all(node.locals)
|
969
|
+
else
|
970
|
+
false
|
971
|
+
end
|
377
972
|
|
378
|
-
|
379
|
-
|
380
|
-
SexpBuilder.new(source).parse
|
973
|
+
bounds(node.location)
|
974
|
+
on_block_var(parameters, locals)
|
381
975
|
end
|
382
976
|
|
383
|
-
#
|
384
|
-
|
385
|
-
|
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)
|
988
|
+
|
989
|
+
bounds(node.location)
|
990
|
+
on_break(arguments)
|
991
|
+
end
|
386
992
|
end
|
387
993
|
|
388
|
-
|
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))
|
389
1008
|
|
390
|
-
|
391
|
-
|
392
|
-
# No opening_loc can mean an operator. It can also mean a
|
393
|
-
# method call with no parentheses.
|
394
|
-
if node.message.match?(/^[[:punct:]]/)
|
395
|
-
left = visit(node.receiver)
|
396
|
-
if node.arguments&.arguments&.length == 1
|
397
|
-
right = visit(node.arguments.arguments.first)
|
398
|
-
|
399
|
-
return on_binary(left, node.name, right)
|
400
|
-
elsif !node.arguments || node.arguments.empty?
|
401
|
-
return on_unary(node.name, left)
|
402
|
-
else
|
403
|
-
raise NotImplementedError, "More than two arguments for operator"
|
404
|
-
end
|
405
|
-
elsif node.call_operator_loc.nil?
|
406
|
-
# In Ripper a method call like "puts myvar" with no parentheses is a "command".
|
407
|
-
bounds(node.message_loc)
|
408
|
-
ident_val = on_ident(node.message)
|
1009
|
+
bounds(node.location)
|
1010
|
+
call = on_aref(receiver, arguments)
|
409
1011
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
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)
|
416
1056
|
else
|
417
|
-
|
1057
|
+
receiver = visit(node.receiver)
|
1058
|
+
|
1059
|
+
bounds(node.location)
|
1060
|
+
on_unary(:!, receiver)
|
418
1061
|
end
|
419
|
-
|
420
|
-
|
1062
|
+
when *BINARY_OPERATORS
|
1063
|
+
receiver = visit(node.receiver)
|
1064
|
+
value = visit(node.arguments.arguments.first)
|
1065
|
+
|
1066
|
+
bounds(node.location)
|
1067
|
+
on_binary(receiver, node.name, value)
|
421
1068
|
else
|
422
|
-
|
423
|
-
|
1069
|
+
bounds(node.message_loc)
|
1070
|
+
message = visit_token(node.message, false)
|
1071
|
+
|
1072
|
+
if node.variable_call?
|
1073
|
+
on_vcall(message)
|
424
1074
|
else
|
425
|
-
|
426
|
-
|
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
|
427
1094
|
end
|
428
1095
|
end
|
429
1096
|
else
|
430
|
-
|
431
|
-
if operator == "." || operator == "&."
|
432
|
-
left_val = visit(node.receiver)
|
1097
|
+
receiver = visit(node.receiver)
|
433
1098
|
|
434
|
-
|
435
|
-
|
1099
|
+
bounds(node.call_operator_loc)
|
1100
|
+
call_operator = visit_token(node.call_operator)
|
436
1101
|
|
437
|
-
|
438
|
-
|
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
|
439
1109
|
|
440
|
-
|
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)
|
441
1112
|
|
442
|
-
|
443
|
-
|
444
|
-
|
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
|
445
1136
|
else
|
446
|
-
|
1137
|
+
bounds(node.block.location)
|
1138
|
+
on_method_add_block(call, block)
|
447
1139
|
end
|
448
|
-
else
|
449
|
-
raise NotImplementedError, "operator other than . or &. for call: #{operator.inspect}"
|
450
1140
|
end
|
451
1141
|
end
|
452
1142
|
end
|
453
1143
|
|
454
|
-
# Visit
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
end
|
460
|
-
end
|
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
|
461
1149
|
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
1150
|
+
if block.is_a?(BlockArgumentNode)
|
1151
|
+
arguments << block
|
1152
|
+
block = nil
|
1153
|
+
end
|
466
1154
|
|
467
|
-
|
468
|
-
|
1155
|
+
[
|
1156
|
+
if arguments.length == 1 && arguments.first.is_a?(ForwardingArgumentsNode)
|
1157
|
+
visit(arguments.first)
|
1158
|
+
elsif arguments.any?
|
1159
|
+
args = visit_arguments(arguments)
|
469
1160
|
|
470
|
-
|
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
|
+
]
|
471
1170
|
end
|
472
1171
|
|
473
|
-
#
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
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)
|
479
1178
|
end
|
480
1179
|
|
481
|
-
#
|
482
|
-
#
|
483
|
-
def
|
484
|
-
|
485
|
-
args_val = on_args_add_block(on_args_add(on_args_new, first_arg_val), false)
|
486
|
-
assign_val = visit(node.arguments.arguments[1])
|
487
|
-
on_assign(on_aref_field(visit(node.receiver), args_val), assign_val)
|
488
|
-
end
|
1180
|
+
# foo.bar += baz
|
1181
|
+
# ^^^^^^^^^^^^^^^
|
1182
|
+
def visit_call_operator_write_node(node)
|
1183
|
+
receiver = visit(node.receiver)
|
489
1184
|
|
490
|
-
|
491
|
-
|
492
|
-
def visit_number(node)
|
493
|
-
slice = node.slice
|
494
|
-
location = node.location
|
1185
|
+
bounds(node.call_operator_loc)
|
1186
|
+
call_operator = visit_token(node.call_operator)
|
495
1187
|
|
496
|
-
|
497
|
-
|
498
|
-
value = yield slice[1..-1]
|
1188
|
+
bounds(node.message_loc)
|
1189
|
+
message = visit_token(node.message)
|
499
1190
|
|
500
|
-
|
501
|
-
|
502
|
-
else
|
503
|
-
bounds(location)
|
504
|
-
yield slice
|
505
|
-
end
|
506
|
-
end
|
1191
|
+
bounds(node.location)
|
1192
|
+
target = on_field(receiver, call_operator, message)
|
507
1193
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
value == :-@ ? :- : value
|
512
|
-
end
|
513
|
-
else
|
514
|
-
# For most Rubies and JRuby after 9.4.6.0 this is a no-op.
|
515
|
-
def visit_unary_operator(value)
|
516
|
-
value
|
517
|
-
end
|
518
|
-
end
|
1194
|
+
bounds(node.binary_operator_loc)
|
1195
|
+
operator = on_op("#{node.binary_operator}=")
|
1196
|
+
value = visit_write_value(node.value)
|
519
1197
|
|
520
|
-
|
521
|
-
|
522
|
-
def no_block_value
|
523
|
-
nil
|
524
|
-
end
|
525
|
-
else
|
526
|
-
# For CRuby et al, "no block" in an on_block_var is false
|
527
|
-
def no_block_value
|
528
|
-
false
|
529
|
-
end
|
1198
|
+
bounds(node.location)
|
1199
|
+
on_opassign(target, operator, value)
|
530
1200
|
end
|
531
1201
|
|
532
|
-
#
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
on_binary(left_val, node.operator.to_sym, right_val)
|
537
|
-
end
|
1202
|
+
# foo.bar &&= baz
|
1203
|
+
# ^^^^^^^^^^^^^^^
|
1204
|
+
def visit_call_and_write_node(node)
|
1205
|
+
receiver = visit(node.receiver)
|
538
1206
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
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)
|
2817
|
+
else
|
2818
|
+
visit(node.statements)
|
2819
|
+
end
|
2820
|
+
|
2821
|
+
subsequent = visit(node.subsequent)
|
2822
|
+
|
2823
|
+
bounds(node.location)
|
2824
|
+
on_rescue(exceptions, reference, statements, subsequent)
|
547
2825
|
end
|
548
2826
|
|
549
|
-
#
|
550
|
-
#
|
551
|
-
|
552
|
-
|
553
|
-
|
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)
|
2836
|
+
else
|
2837
|
+
bounds(node.name_loc)
|
2838
|
+
on_rest_param(visit_token(node.name.to_s))
|
2839
|
+
end
|
2840
|
+
end
|
2841
|
+
|
2842
|
+
# retry
|
2843
|
+
# ^^^^^
|
2844
|
+
def visit_retry_node(node)
|
2845
|
+
bounds(node.location)
|
2846
|
+
on_retry
|
2847
|
+
end
|
2848
|
+
|
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)
|
2860
|
+
|
2861
|
+
bounds(node.location)
|
2862
|
+
on_return(arguments)
|
2863
|
+
end
|
2864
|
+
end
|
2865
|
+
|
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
|
2978
|
+
end
|
2979
|
+
|
2980
|
+
dedent_next = true
|
2981
|
+
else
|
2982
|
+
dedent_next = false
|
2983
|
+
end
|
2984
|
+
end
|
2985
|
+
|
2986
|
+
common_whitespace || 0
|
2987
|
+
end
|
2988
|
+
|
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)
|
3032
|
+
end
|
3033
|
+
end
|
3034
|
+
|
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)
|
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)
|
3077
|
+
end
|
3078
|
+
|
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)
|
3087
|
+
end
|
3088
|
+
end
|
3089
|
+
|
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
|
3096
|
+
|
3097
|
+
if !(value = node.value).empty?
|
3098
|
+
content = on_string_add(content, on_tstring_content(value))
|
3099
|
+
end
|
3100
|
+
|
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
|
3112
|
+
end
|
3113
|
+
|
3114
|
+
# true
|
3115
|
+
# ^^^^
|
3116
|
+
def visit_true_node(node)
|
3117
|
+
bounds(node.location)
|
3118
|
+
on_var_ref(on_kw("true"))
|
3119
|
+
end
|
3120
|
+
|
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)
|
3128
|
+
end
|
3129
|
+
|
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)
|
3146
|
+
|
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)
|
3196
|
+
else
|
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)
|
3271
|
+
end
|
3272
|
+
|
3273
|
+
bounds(node.location)
|
3274
|
+
on_yield(arguments)
|
3275
|
+
end
|
554
3276
|
end
|
555
3277
|
|
3278
|
+
private
|
3279
|
+
|
556
3280
|
# Lazily initialize the parse result.
|
557
3281
|
def result
|
558
|
-
@result ||= Prism.parse(source)
|
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
|
3299
|
+
|
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)
|
3322
|
+
else
|
3323
|
+
on_ident(token)
|
3324
|
+
end
|
3325
|
+
end
|
3326
|
+
|
3327
|
+
# Visit a node that represents a number. We need to explicitly handle the
|
3328
|
+
# unary - operator.
|
3329
|
+
def visit_number_node(node)
|
3330
|
+
slice = node.slice
|
3331
|
+
location = node.location
|
3332
|
+
|
3333
|
+
if slice[0] == "-"
|
3334
|
+
bounds(location.copy(start_offset: location.start_offset + 1))
|
3335
|
+
value = yield slice[1..-1]
|
3336
|
+
|
3337
|
+
bounds(node.location)
|
3338
|
+
on_unary(:-@, value)
|
3339
|
+
else
|
3340
|
+
bounds(location)
|
3341
|
+
yield slice
|
3342
|
+
end
|
3343
|
+
end
|
3344
|
+
|
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)
|
3377
|
+
end
|
3378
|
+
end
|
3379
|
+
|
3380
|
+
# This method is responsible for updating lineno and column information
|
3381
|
+
# to reflect the current node.
|
3382
|
+
#
|
3383
|
+
# This method could be drastically improved with some caching on the start
|
3384
|
+
# of every line, but for now it's good enough.
|
3385
|
+
def bounds(location)
|
3386
|
+
@lineno = location.start_line
|
3387
|
+
@column = location.start_column
|
3388
|
+
end
|
3389
|
+
|
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}"
|
3410
|
+
end
|
3411
|
+
|
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)
|
559
3424
|
end
|
560
3425
|
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
3426
|
+
#
|
3427
|
+
# Scanner Events
|
3428
|
+
#
|
3429
|
+
|
3430
|
+
SCANNER_EVENTS.each do |id|
|
3431
|
+
alias_method "on_#{id}", :_dispatch_1
|
3432
|
+
end
|
568
3433
|
|
569
|
-
|
570
|
-
|
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
|
571
3452
|
|
572
|
-
|
573
|
-
|
3453
|
+
string.replace(string[cursor..])
|
3454
|
+
cursor
|
574
3455
|
end
|
575
3456
|
end
|
576
3457
|
end
|