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