syntax_tree-translator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/main.yml +34 -0
- data/.gitignore +11 -0
- data/.gitmodules +6 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +44 -0
- data/LICENSE +21 -0
- data/README.md +74 -0
- data/Rakefile +22 -0
- data/bin/compare-p +58 -0
- data/bin/compare-rp +26 -0
- data/bin/console +10 -0
- data/bin/rubocop +32 -0
- data/lib/syntax_tree/translator/parser.rb +1269 -0
- data/lib/syntax_tree/translator/rubocop.rb +13 -0
- data/lib/syntax_tree/translator/ruby_parser.rb +1055 -0
- data/lib/syntax_tree/translator/version.rb +7 -0
- data/lib/syntax_tree/translator.rb +10 -0
- data/syntax_tree-translator.gemspec +35 -0
- metadata +176 -0
@@ -0,0 +1,1269 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SyntaxTree
|
4
|
+
module Translator
|
5
|
+
class Parser < Visitor
|
6
|
+
attr_reader :buffer, :stack
|
7
|
+
|
8
|
+
def initialize(buffer)
|
9
|
+
@buffer = buffer
|
10
|
+
@stack = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def visit(node)
|
14
|
+
stack << node
|
15
|
+
result = super
|
16
|
+
stack.pop
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_alias(node)
|
21
|
+
s(:alias, [visit(node.left), visit(node.right)])
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_aref_field(node)
|
25
|
+
if ::Parser::Builders::Default.emit_index
|
26
|
+
case node
|
27
|
+
in { index: Args[parts:] }
|
28
|
+
s(:indexasgn, [visit(node.collection), *visit_all(parts)])
|
29
|
+
in { index: nil }
|
30
|
+
s(:indexasgn, [visit(node.collection), nil])
|
31
|
+
end
|
32
|
+
else
|
33
|
+
case node
|
34
|
+
in { index: Args[parts:] }
|
35
|
+
s(:send, [visit(node.collection), :[]=, *visit_all(parts)])
|
36
|
+
in { index: nil }
|
37
|
+
s(:send, [visit(node.collection), :[]=, nil])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_aref(node)
|
43
|
+
if ::Parser::Builders::Default.emit_index
|
44
|
+
case node
|
45
|
+
in { index: Args[parts:] }
|
46
|
+
s(:index, [visit(node.collection), *visit_all(parts)])
|
47
|
+
in { index: nil }
|
48
|
+
s(:index, [visit(node.collection)])
|
49
|
+
end
|
50
|
+
else
|
51
|
+
case node
|
52
|
+
in { index: Args[parts:] }
|
53
|
+
s(:send, [visit(node.collection), :[], *visit_all(parts)])
|
54
|
+
in { index: nil }
|
55
|
+
s(:send, [visit(node.collection), :[], nil])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit_arg_block(node)
|
61
|
+
s(:block_pass, [visit(node.value)])
|
62
|
+
end
|
63
|
+
|
64
|
+
def visit_arg_paren(node)
|
65
|
+
raise
|
66
|
+
end
|
67
|
+
|
68
|
+
def visit_arg_star(node)
|
69
|
+
if stack[-3] in MLHSParen[contents: MLHS]
|
70
|
+
case node
|
71
|
+
in { value: nil }
|
72
|
+
s(:restarg)
|
73
|
+
in { value: VarField[value: { value: }]}
|
74
|
+
s(:restarg, [value.to_sym])
|
75
|
+
in { value: Ident[value:] }
|
76
|
+
s(:restarg, [value.to_sym])
|
77
|
+
end
|
78
|
+
else
|
79
|
+
case node
|
80
|
+
in { value: nil }
|
81
|
+
s(:splat)
|
82
|
+
else
|
83
|
+
s(:splat, [visit(node.value)])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def visit_args(node)
|
89
|
+
raise
|
90
|
+
end
|
91
|
+
|
92
|
+
def visit_args_forward(node)
|
93
|
+
s(:forwarded_args)
|
94
|
+
end
|
95
|
+
|
96
|
+
def visit_array(node)
|
97
|
+
case node
|
98
|
+
in { contents: nil }
|
99
|
+
s(:array)
|
100
|
+
in { contents: Args[parts:] }
|
101
|
+
s(:array, visit_all(parts))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def visit_aryptn(node)
|
106
|
+
type = :array_pattern
|
107
|
+
children = visit_all(node.requireds)
|
108
|
+
|
109
|
+
case node.rest
|
110
|
+
in VarField[value: nil, location: { start_char:, end_char: ^(start_char) }] if node.posts.empty?
|
111
|
+
# Here we have an implicit rest, as in [foo,]. parser has a specific
|
112
|
+
# type for these patterns.
|
113
|
+
type = :array_pattern_with_tail
|
114
|
+
in VarField[value: nil]
|
115
|
+
children << s(:match_rest)
|
116
|
+
in VarField
|
117
|
+
children << s(:match_rest, [visit(node.rest)])
|
118
|
+
else
|
119
|
+
end
|
120
|
+
|
121
|
+
inner = s(type, children + visit_all(node.posts))
|
122
|
+
node.constant ? s(:const_pattern, [visit(node.constant), inner]) : inner
|
123
|
+
end
|
124
|
+
|
125
|
+
def visit_assign(node)
|
126
|
+
target = visit(node.target)
|
127
|
+
s(target.type, target.children + [visit(node.value)])
|
128
|
+
end
|
129
|
+
|
130
|
+
def visit_assoc(node)
|
131
|
+
case node
|
132
|
+
in { key:, value: nil } if key.value.start_with?(/[a-z]/)
|
133
|
+
s(:pair, [visit(key), s(:send, [nil, key.value.chomp(":").to_sym])])
|
134
|
+
in { key:, value: nil } if key.value.start_with?(/[A-Z]/)
|
135
|
+
s(:pair, [visit(key), s(:const, [nil, key.value.chomp(":").to_sym])])
|
136
|
+
in { key:, value: }
|
137
|
+
s(:pair, [visit(key), visit(value)])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def visit_assoc_splat(node)
|
142
|
+
s(:kwsplat, [visit(node.value)])
|
143
|
+
end
|
144
|
+
|
145
|
+
def visit_backref(node)
|
146
|
+
if node.value.match?(/^\$\d+$/)
|
147
|
+
s(:nth_ref, [node.value[1..-1].to_i])
|
148
|
+
else
|
149
|
+
s(:back_ref, [node.value.to_sym])
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def visit_backtick(node)
|
154
|
+
raise
|
155
|
+
end
|
156
|
+
|
157
|
+
def visit_bare_assoc_hash(node)
|
158
|
+
type =
|
159
|
+
if ::Parser::Builders::Default.emit_kwargs && !(stack[-2] in ArrayLiteral)
|
160
|
+
:kwargs
|
161
|
+
else
|
162
|
+
:hash
|
163
|
+
end
|
164
|
+
|
165
|
+
s(type, visit_all(node.assocs))
|
166
|
+
end
|
167
|
+
|
168
|
+
def visit_BEGIN(node)
|
169
|
+
s(:preexe, [visit(node.statements)])
|
170
|
+
end
|
171
|
+
|
172
|
+
def visit_begin(node)
|
173
|
+
if node.bodystmt.empty?
|
174
|
+
s(:kwbegin)
|
175
|
+
elsif node.bodystmt in { statements:, rescue_clause: nil, ensure_clause: nil, else_clause: nil }
|
176
|
+
visited = visit(statements)
|
177
|
+
s(:kwbegin, visited.type == :begin ? visited.children : [visited])
|
178
|
+
else
|
179
|
+
s(:kwbegin, [visit(node.bodystmt)])
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def visit_binary(node)
|
184
|
+
case node
|
185
|
+
in { operator: :| }
|
186
|
+
current = -2
|
187
|
+
current -= 1 while (stack[current] in Binary[operator: :|])
|
188
|
+
|
189
|
+
if stack[current] in In
|
190
|
+
s(:match_alt, [visit(node.left), visit(node.right)])
|
191
|
+
else
|
192
|
+
s(:send, [visit(node.left), node.operator, visit(node.right)])
|
193
|
+
end
|
194
|
+
in { operator: :"=>" }
|
195
|
+
s(:match_as, [visit(node.left), visit(node.right)])
|
196
|
+
in { operator: :"&&" | :and }
|
197
|
+
s(:and, [visit(node.left), visit(node.right)])
|
198
|
+
in { operator: :"||" | :or }
|
199
|
+
s(:or, [visit(node.left), visit(node.right)])
|
200
|
+
in { left: RegexpLiteral[parts: [TStringContent]], operator: :=~ }
|
201
|
+
s(:match_with_lvasgn, [visit(node.left), visit(node.right)])
|
202
|
+
else
|
203
|
+
s(:send, [visit(node.left), node.operator, visit(node.right)])
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def visit_blockarg(node)
|
208
|
+
case node
|
209
|
+
in { name: nil }
|
210
|
+
s(:blockarg, [nil])
|
211
|
+
else
|
212
|
+
s(:blockarg, [node.name.value.to_sym])
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def visit_block_var(node)
|
217
|
+
shadowargs = node.locals.map { |local| s(:shadowarg, [local.value.to_sym]) }
|
218
|
+
|
219
|
+
case node
|
220
|
+
in { params: { requireds: [(Ident | MLHSParen) => required], optionals: [], rest: nil, posts: [], keywords: [], keyword_rest: nil, block: nil } } if ::Parser::Builders::Default.emit_procarg0
|
221
|
+
procarg0 =
|
222
|
+
if ::Parser::Builders::Default.emit_arg_inside_procarg0 && required in Ident
|
223
|
+
s(:procarg0, [s(:arg, [required.value.to_sym])])
|
224
|
+
else
|
225
|
+
s(:procarg0, visit(required).children)
|
226
|
+
end
|
227
|
+
|
228
|
+
s(:args, [procarg0] + shadowargs)
|
229
|
+
else
|
230
|
+
s(:args, visit(node.params).children + shadowargs)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def visit_bodystmt(node)
|
235
|
+
inner = visit(node.statements)
|
236
|
+
|
237
|
+
if node.rescue_clause
|
238
|
+
children = [inner] + visit(node.rescue_clause).children
|
239
|
+
|
240
|
+
if node.else_clause
|
241
|
+
children.pop
|
242
|
+
children << visit(node.else_clause)
|
243
|
+
end
|
244
|
+
|
245
|
+
inner = s(:rescue, children)
|
246
|
+
end
|
247
|
+
|
248
|
+
if node.ensure_clause
|
249
|
+
inner = s(:ensure, [inner] + visit(node.ensure_clause).children)
|
250
|
+
end
|
251
|
+
|
252
|
+
inner
|
253
|
+
end
|
254
|
+
|
255
|
+
def visit_brace_block(node)
|
256
|
+
raise
|
257
|
+
end
|
258
|
+
|
259
|
+
def visit_break(node)
|
260
|
+
s(:break, visit_all(node.arguments.parts))
|
261
|
+
end
|
262
|
+
|
263
|
+
def visit_call(node)
|
264
|
+
type = send_type(node.operator)
|
265
|
+
|
266
|
+
case node
|
267
|
+
in { message: :call, arguments: ArgParen[arguments: nil] }
|
268
|
+
s(type, [visit(node.receiver), :call])
|
269
|
+
in { message: :call, arguments: ArgParen[arguments: { parts: }] }
|
270
|
+
s(type, [visit(node.receiver), :call, *visit_all(parts)])
|
271
|
+
in { arguments: nil | ArgParen[arguments: nil] }
|
272
|
+
s(type, [visit(node.receiver), node.message.value.to_sym])
|
273
|
+
in { arguments: Args[parts:] }
|
274
|
+
s(type, [visit(node.receiver), node.message.value.to_sym, *visit_all(parts)])
|
275
|
+
in { arguments: ArgParen[arguments: { parts: }] }
|
276
|
+
s(type, [visit(node.receiver), node.message.value.to_sym, *visit_all(parts)])
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def visit_case(node)
|
281
|
+
clauses = [node.consequent]
|
282
|
+
clauses << clauses.last.consequent while clauses.last && !(clauses.last in Else)
|
283
|
+
|
284
|
+
type = (node.consequent in In) ? :case_match : :case
|
285
|
+
s(type, [visit(node.value)] + clauses.map { |clause| visit(clause) })
|
286
|
+
end
|
287
|
+
|
288
|
+
def visit_CHAR(node)
|
289
|
+
s(:str, [node.value[1..-1]])
|
290
|
+
end
|
291
|
+
|
292
|
+
def visit_class(node)
|
293
|
+
s(:class, [visit(node.constant), visit(node.superclass), visit(node.bodystmt)])
|
294
|
+
end
|
295
|
+
|
296
|
+
def visit_comma(node)
|
297
|
+
raise
|
298
|
+
end
|
299
|
+
|
300
|
+
def visit_command(node)
|
301
|
+
s(:send, [nil, node.message.value.to_sym, *visit_all(node.arguments.parts)])
|
302
|
+
end
|
303
|
+
|
304
|
+
def visit_command_call(node)
|
305
|
+
children = [visit(node.receiver), node.message.value.to_sym]
|
306
|
+
|
307
|
+
case node.arguments
|
308
|
+
in nil
|
309
|
+
# do nothing
|
310
|
+
in Args[parts:]
|
311
|
+
children += visit_all(parts)
|
312
|
+
in ArgParen[arguments: { parts: }]
|
313
|
+
children += visit_all(parts)
|
314
|
+
end
|
315
|
+
|
316
|
+
s(send_type(node.operator), children)
|
317
|
+
end
|
318
|
+
|
319
|
+
def visit_comment(node)
|
320
|
+
raise
|
321
|
+
end
|
322
|
+
|
323
|
+
def visit_const(node)
|
324
|
+
s(:const, [nil, node.value.to_sym])
|
325
|
+
end
|
326
|
+
|
327
|
+
def visit_const_path_field(node)
|
328
|
+
if node in { parent: VarRef[value: Kw[value: "self"]] => parent, constant: Ident[value:] }
|
329
|
+
s(:send, [visit(parent), :"#{value}="])
|
330
|
+
else
|
331
|
+
s(:casgn, [visit(node.parent), node.constant.value.to_sym])
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def visit_const_path_ref(node)
|
336
|
+
s(:const, [visit(node.parent), node.constant.value.to_sym])
|
337
|
+
end
|
338
|
+
|
339
|
+
def visit_const_ref(node)
|
340
|
+
s(:const, [nil, node.constant.value.to_sym])
|
341
|
+
end
|
342
|
+
|
343
|
+
def visit_cvar(node)
|
344
|
+
s(:cvar, [node.value.to_sym])
|
345
|
+
end
|
346
|
+
|
347
|
+
def visit_def(node)
|
348
|
+
args = (node.params in Params) ? node.params : node.params.contents
|
349
|
+
s(:def, [node.name.value.to_sym, visit(args), visit(node.bodystmt)])
|
350
|
+
end
|
351
|
+
|
352
|
+
def visit_def_endless(node)
|
353
|
+
children = []
|
354
|
+
children << visit(node.target) if node.target
|
355
|
+
|
356
|
+
args = (node.paren in Params) ? node.paren : node.paren.contents
|
357
|
+
children += [node.name.value.to_sym, visit(args), visit(node.statement)]
|
358
|
+
|
359
|
+
s(node.target ? :defs : :def, children)
|
360
|
+
end
|
361
|
+
|
362
|
+
def visit_defined(node)
|
363
|
+
s(:defined?, [visit(node.value)])
|
364
|
+
end
|
365
|
+
|
366
|
+
def visit_defs(node)
|
367
|
+
args = (node.params in Params) ? node.params : node.params.contents
|
368
|
+
s(:defs, [visit(node.target), node.name.value.to_sym, visit(args), visit(node.bodystmt)])
|
369
|
+
end
|
370
|
+
|
371
|
+
def visit_do_block(node)
|
372
|
+
raise
|
373
|
+
end
|
374
|
+
|
375
|
+
def visit_dot2(node)
|
376
|
+
s(:irange, [visit(node.left), visit(node.right)])
|
377
|
+
end
|
378
|
+
|
379
|
+
def visit_dot3(node)
|
380
|
+
s(:erange, [visit(node.left), visit(node.right)])
|
381
|
+
end
|
382
|
+
|
383
|
+
def visit_dyna_symbol(node)
|
384
|
+
case node
|
385
|
+
in { parts: [TStringContent[value:]] }
|
386
|
+
s(:sym, ["\"#{value}\"".undump.to_sym])
|
387
|
+
else
|
388
|
+
s(:dsym, visit_all(node.parts))
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
def visit_else(node)
|
393
|
+
if node.statements.empty? && (stack[-2] in Case)
|
394
|
+
s(:empty_else)
|
395
|
+
else
|
396
|
+
visit(node.statements)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def visit_elsif(node)
|
401
|
+
s(:if, [visit(node.predicate), visit(node.statements), visit(node.consequent)])
|
402
|
+
end
|
403
|
+
|
404
|
+
def visit_embdoc(node)
|
405
|
+
raise
|
406
|
+
end
|
407
|
+
|
408
|
+
def visit_embexpr_beg(node)
|
409
|
+
raise
|
410
|
+
end
|
411
|
+
|
412
|
+
def visit_embexpr_end(node)
|
413
|
+
raise
|
414
|
+
end
|
415
|
+
|
416
|
+
def visit_embvar(node)
|
417
|
+
raise
|
418
|
+
end
|
419
|
+
|
420
|
+
def visit_END(node)
|
421
|
+
s(:postexe, [visit(node.statements)])
|
422
|
+
end
|
423
|
+
|
424
|
+
def visit_ensure(node)
|
425
|
+
s(:ensure, [visit(node.statements)])
|
426
|
+
end
|
427
|
+
|
428
|
+
def visit_excessed_comma(node)
|
429
|
+
raise
|
430
|
+
end
|
431
|
+
|
432
|
+
def visit_fcall(node)
|
433
|
+
case node
|
434
|
+
in { arguments: Args[parts: []] | ArgParen[arguments: nil] }
|
435
|
+
s(:send, [nil, node.value.value.to_sym])
|
436
|
+
in { arguments: ArgParen[arguments: { parts: }] }
|
437
|
+
s(:send, [nil, node.value.value.to_sym, *visit_all(parts)])
|
438
|
+
in { arguments: ArgParen[arguments: ArgsForward] }
|
439
|
+
s(:send, [nil, node.value.value.to_sym, s(:forwarded_args)])
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
def visit_field(node)
|
444
|
+
if stack[-2] in Assign | MLHS
|
445
|
+
s(send_type(node.operator), [visit(node.parent), :"#{node.name.value}="])
|
446
|
+
else
|
447
|
+
s(send_type(node.operator), [visit(node.parent), node.name.value.to_sym])
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def visit_float(node)
|
452
|
+
s(:float, [node.value.to_f])
|
453
|
+
end
|
454
|
+
|
455
|
+
def visit_fndptn(node)
|
456
|
+
children = [
|
457
|
+
s(:match_rest, (node.left in VarField[value: nil]) ? [] : [visit(node.left)]),
|
458
|
+
*visit_all(node.values),
|
459
|
+
s(:match_rest, (node.right in VarField[value: nil]) ? [] : [visit(node.right)])
|
460
|
+
]
|
461
|
+
|
462
|
+
inner = s(:find_pattern, children)
|
463
|
+
node.constant ? s(:const_pattern, [visit(node.constant), inner]) : inner
|
464
|
+
end
|
465
|
+
|
466
|
+
def visit_for(node)
|
467
|
+
s(:for, [visit(node.index), visit(node.collection), visit(node.statements)])
|
468
|
+
end
|
469
|
+
|
470
|
+
def visit_gvar(node)
|
471
|
+
s(:gvar, [node.value.to_sym])
|
472
|
+
end
|
473
|
+
|
474
|
+
def visit_hash(node)
|
475
|
+
s(:hash, visit_all(node.assocs))
|
476
|
+
end
|
477
|
+
|
478
|
+
class HeredocSegments
|
479
|
+
attr_reader :node, :segments
|
480
|
+
|
481
|
+
def initialize(node)
|
482
|
+
@node = node
|
483
|
+
@segments = []
|
484
|
+
end
|
485
|
+
|
486
|
+
def <<(segment)
|
487
|
+
if segment.type == :str && segments.last && segments.last.type == :str && !segments.last.children.first.end_with?("\n")
|
488
|
+
segments.last.children.first << segment.children.first
|
489
|
+
else
|
490
|
+
segments << segment
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
HeredocLine = Struct.new(:value, :segments)
|
495
|
+
|
496
|
+
def trim!
|
497
|
+
return unless node.beginning.value[2] == "~"
|
498
|
+
lines = [HeredocLine.new(+"", [])]
|
499
|
+
|
500
|
+
segments.each do |segment|
|
501
|
+
lines.last.segments << segment
|
502
|
+
|
503
|
+
if segment.type == :str
|
504
|
+
lines.last.value << segment.children.first
|
505
|
+
|
506
|
+
if lines.last.value.end_with?("\n")
|
507
|
+
lines << HeredocLine.new(+"", [])
|
508
|
+
end
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
lines.pop if lines.last.value.empty?
|
513
|
+
return if lines.empty?
|
514
|
+
|
515
|
+
segments.clear
|
516
|
+
lines.each do |line|
|
517
|
+
remaining = node.dedent
|
518
|
+
|
519
|
+
line.segments.each do |segment|
|
520
|
+
if segment.type == :str
|
521
|
+
if remaining > 0
|
522
|
+
whitespace = segment.children.first[/^\s{0,#{remaining}}/]
|
523
|
+
segment.children.first.sub!(/^#{whitespace}/, "")
|
524
|
+
remaining -= whitespace.length
|
525
|
+
end
|
526
|
+
|
527
|
+
if node.beginning.value[3] != "'" && segments.any? && segments.last.type == :str && segments.last.children.first.end_with?("\\\n")
|
528
|
+
segments.last.children.first.gsub!(/\\\n\z/, "")
|
529
|
+
segments.last.children.first.concat(segment.children.first)
|
530
|
+
elsif segment.children.first.length > 0
|
531
|
+
segments << segment
|
532
|
+
end
|
533
|
+
else
|
534
|
+
segments << segment
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
def visit_heredoc(node)
|
542
|
+
heredoc_segments = HeredocSegments.new(node)
|
543
|
+
|
544
|
+
node.parts.each do |part|
|
545
|
+
if (part in TStringContent[value:]) && value.count("\n") > 1
|
546
|
+
part.value.split("\n").each do |line|
|
547
|
+
heredoc_segments << s(:str, ["#{line}\n"])
|
548
|
+
end
|
549
|
+
else
|
550
|
+
heredoc_segments << visit(part)
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
heredoc_segments.trim!
|
555
|
+
|
556
|
+
if node.beginning.value.match?(/`\w+`\z/)
|
557
|
+
s(:xstr, heredoc_segments.segments)
|
558
|
+
elsif heredoc_segments.segments.length > 1
|
559
|
+
s(:dstr, heredoc_segments.segments)
|
560
|
+
elsif heredoc_segments.segments.empty?
|
561
|
+
s(:dstr)
|
562
|
+
else
|
563
|
+
heredoc_segments.segments.first
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
def visit_heredoc_beg(node)
|
568
|
+
raise
|
569
|
+
end
|
570
|
+
|
571
|
+
def visit_hshptn(node)
|
572
|
+
children =
|
573
|
+
node.keywords.map do |(keyword, value)|
|
574
|
+
next s(:pair, [visit(keyword), visit(value)]) if value
|
575
|
+
|
576
|
+
case keyword
|
577
|
+
in Label
|
578
|
+
s(:match_var, [keyword.value.chomp(":").to_sym])
|
579
|
+
in StringContent[parts: [TStringContent[value:]]]
|
580
|
+
s(:match_var, [value.to_sym])
|
581
|
+
end
|
582
|
+
end
|
583
|
+
|
584
|
+
case node.keyword_rest
|
585
|
+
in VarField[value: nil]
|
586
|
+
children << s(:match_rest)
|
587
|
+
in VarField[value: :nil]
|
588
|
+
children << s(:match_nil_pattern)
|
589
|
+
in VarField
|
590
|
+
children << s(:match_rest, [visit(node.keyword_rest)])
|
591
|
+
else
|
592
|
+
end
|
593
|
+
|
594
|
+
inner = s(:hash_pattern, children)
|
595
|
+
node.constant ? s(:const_pattern, [visit(node.constant), inner]) : inner
|
596
|
+
end
|
597
|
+
|
598
|
+
def visit_ident(node)
|
599
|
+
s(:lvar, [node.value.to_sym])
|
600
|
+
end
|
601
|
+
|
602
|
+
def visit_if(node)
|
603
|
+
predicate =
|
604
|
+
case node.predicate
|
605
|
+
in Dot2
|
606
|
+
s(:iflipflop, visit(node.predicate).children)
|
607
|
+
in Dot3
|
608
|
+
s(:eflipflop, visit(node.predicate).children)
|
609
|
+
else
|
610
|
+
visit(node.predicate)
|
611
|
+
end
|
612
|
+
|
613
|
+
s(:if, [predicate, visit(node.statements), visit(node.consequent)])
|
614
|
+
end
|
615
|
+
|
616
|
+
def visit_if_mod(node)
|
617
|
+
s(:if, [visit(node.predicate), visit(node.statement), nil])
|
618
|
+
end
|
619
|
+
|
620
|
+
def visit_if_op(node)
|
621
|
+
s(:if, [visit(node.predicate), visit(node.truthy), visit(node.falsy)])
|
622
|
+
end
|
623
|
+
|
624
|
+
def visit_imaginary(node)
|
625
|
+
# We have to do an eval here in order to get the value in case it's
|
626
|
+
# something like 42ri. to_c will not give the right value in that case.
|
627
|
+
# Maybe there's an API for this but I can't find it.
|
628
|
+
s(:complex, [eval(node.value)])
|
629
|
+
end
|
630
|
+
|
631
|
+
def visit_in(node)
|
632
|
+
case node
|
633
|
+
in { pattern: IfMod[predicate:, statement:], statements: }
|
634
|
+
s(:in_pattern, [visit(statement), s(:if_guard, [visit(predicate)]), visit(statements)])
|
635
|
+
in { pattern: UnlessMod[predicate:, statement:], statements: }
|
636
|
+
s(:in_pattern, [visit(statement), s(:unless_guard, [visit(predicate)]), visit(statements)])
|
637
|
+
else
|
638
|
+
s(:in_pattern, [visit(node.pattern), nil, visit(node.statements)])
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def visit_int(node)
|
643
|
+
s(:int, [node.value.to_i])
|
644
|
+
end
|
645
|
+
|
646
|
+
def visit_ivar(node)
|
647
|
+
s(:ivar, [node.value.to_sym])
|
648
|
+
end
|
649
|
+
|
650
|
+
def visit_kw(node)
|
651
|
+
case node.value
|
652
|
+
in "__FILE__"
|
653
|
+
s(:str, [buffer.name])
|
654
|
+
in "__LINE__"
|
655
|
+
s(:int, [node.location.start_line + buffer.first_line - 1])
|
656
|
+
in "__ENCODING__" unless ::Parser::Builders::Default.emit_encoding
|
657
|
+
s(:const, [s(:const, [nil, :Encoding]), :UTF_8])
|
658
|
+
else
|
659
|
+
s(node.value.to_sym)
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
def visit_kwrest_param(node)
|
664
|
+
case node
|
665
|
+
in { name: nil }
|
666
|
+
s(:kwrestarg)
|
667
|
+
else
|
668
|
+
s(:kwrestarg, [node.name.value.to_sym])
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
672
|
+
def visit_label(node)
|
673
|
+
s(:sym, [node.value.chomp(":").to_sym])
|
674
|
+
end
|
675
|
+
|
676
|
+
def visit_label_end(node)
|
677
|
+
raise
|
678
|
+
end
|
679
|
+
|
680
|
+
def visit_lambda(node)
|
681
|
+
args = (node.params in Params) ? node.params : node.params.contents
|
682
|
+
|
683
|
+
arguments = visit(args)
|
684
|
+
child =
|
685
|
+
if ::Parser::Builders::Default.emit_lambda
|
686
|
+
s(:lambda)
|
687
|
+
else
|
688
|
+
s(:send, [nil, :lambda])
|
689
|
+
end
|
690
|
+
|
691
|
+
type = :block
|
692
|
+
if args.empty? && (maximum = num_block_type(node.statements))
|
693
|
+
type = :numblock
|
694
|
+
arguments = maximum
|
695
|
+
end
|
696
|
+
|
697
|
+
s(type, [child, arguments, visit(node.statements)])
|
698
|
+
end
|
699
|
+
|
700
|
+
def visit_lbrace(node)
|
701
|
+
raise
|
702
|
+
end
|
703
|
+
|
704
|
+
def visit_lbracket(node)
|
705
|
+
raise
|
706
|
+
end
|
707
|
+
|
708
|
+
def visit_lparen(node)
|
709
|
+
raise
|
710
|
+
end
|
711
|
+
|
712
|
+
def visit_massign(node)
|
713
|
+
s(:masgn, [visit(node.target), visit(node.value)])
|
714
|
+
end
|
715
|
+
|
716
|
+
def visit_method_add_block(node)
|
717
|
+
statements =
|
718
|
+
if node.block in BraceBlock
|
719
|
+
node.block.statements
|
720
|
+
else
|
721
|
+
node.block.bodystmt
|
722
|
+
end
|
723
|
+
|
724
|
+
arguments =
|
725
|
+
if node.block.block_var
|
726
|
+
visit(node.block.block_var)
|
727
|
+
else
|
728
|
+
s(:args)
|
729
|
+
end
|
730
|
+
|
731
|
+
type = :block
|
732
|
+
if !node.block.block_var && (maximum = num_block_type(statements))
|
733
|
+
type = :numblock
|
734
|
+
arguments = maximum
|
735
|
+
end
|
736
|
+
|
737
|
+
if node.call in Break | Next | Return
|
738
|
+
call = visit(node.call)
|
739
|
+
s(call.type, [s(type, [*call.children, arguments, visit(statements)])])
|
740
|
+
else
|
741
|
+
s(type, [visit(node.call), arguments, visit(statements)])
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
def visit_mlhs(node)
|
746
|
+
s(:mlhs, node.parts.map { |part| (part in Ident[value:]) ? s(:arg, [value.to_sym]) : visit(part) })
|
747
|
+
end
|
748
|
+
|
749
|
+
def visit_mlhs_paren(node)
|
750
|
+
visit(node.contents)
|
751
|
+
end
|
752
|
+
|
753
|
+
def visit_module(node)
|
754
|
+
s(:module, [visit(node.constant), visit(node.bodystmt)])
|
755
|
+
end
|
756
|
+
|
757
|
+
def visit_mrhs(node)
|
758
|
+
s(:array, visit_all(node.parts))
|
759
|
+
end
|
760
|
+
|
761
|
+
def visit_next(node)
|
762
|
+
s(:next, visit_all(node.arguments.parts))
|
763
|
+
end
|
764
|
+
|
765
|
+
def visit_not(node)
|
766
|
+
case node
|
767
|
+
in { statement: nil }
|
768
|
+
s(:send, [s(:begin), :"!"])
|
769
|
+
else
|
770
|
+
s(:send, [visit(node.statement), :"!"])
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
774
|
+
def visit_op(node)
|
775
|
+
raise
|
776
|
+
end
|
777
|
+
|
778
|
+
def visit_opassign(node)
|
779
|
+
case node.operator
|
780
|
+
in { value: "||=" }
|
781
|
+
s(:or_asgn, [visit(node.target), visit(node.value)])
|
782
|
+
in { value: "&&=" }
|
783
|
+
s(:and_asgn, [visit(node.target), visit(node.value)])
|
784
|
+
else
|
785
|
+
s(:op_asgn, [visit(node.target), node.operator.value.chomp("=").to_sym, visit(node.value)])
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
789
|
+
def visit_params(node)
|
790
|
+
children = []
|
791
|
+
|
792
|
+
children +=
|
793
|
+
node.requireds.map do |required|
|
794
|
+
case required
|
795
|
+
in MLHSParen
|
796
|
+
visit(required)
|
797
|
+
else
|
798
|
+
s(:arg, [required.value.to_sym])
|
799
|
+
end
|
800
|
+
end
|
801
|
+
|
802
|
+
children += node.optionals.map { |(name, value)| s(:optarg, [name.value.to_sym, visit(value)]) }
|
803
|
+
children << visit(node.rest) if node.rest && !(node.rest in ExcessedComma)
|
804
|
+
children += node.posts.map { |post| s(:arg, [post.value.to_sym]) }
|
805
|
+
children +=
|
806
|
+
node.keywords.map do |(name, value)|
|
807
|
+
key = name.value.chomp(":").to_sym
|
808
|
+
value ? s(:kwoptarg, [key, visit(value)]) : s(:kwarg, [key])
|
809
|
+
end
|
810
|
+
|
811
|
+
case node.keyword_rest
|
812
|
+
in nil | ArgsForward
|
813
|
+
# do nothing
|
814
|
+
in :nil
|
815
|
+
children << s(:kwnilarg)
|
816
|
+
else
|
817
|
+
children << visit(node.keyword_rest)
|
818
|
+
end
|
819
|
+
|
820
|
+
children << visit(node.block) if node.block
|
821
|
+
|
822
|
+
if (node.keyword_rest in ArgsForward)
|
823
|
+
if children.empty? && !::Parser::Builders::Default.emit_forward_arg
|
824
|
+
return s(:forward_args)
|
825
|
+
end
|
826
|
+
|
827
|
+
children.insert(node.requireds.length + node.optionals.length + node.keywords.length, s(:forward_arg))
|
828
|
+
end
|
829
|
+
|
830
|
+
s(:args, children)
|
831
|
+
end
|
832
|
+
|
833
|
+
def visit_paren(node)
|
834
|
+
if node in { contents: nil | Statements[body: [VoidStmt]] }
|
835
|
+
s(:begin)
|
836
|
+
elsif stack[-2] in Defs[target: ^(node)]
|
837
|
+
visit(node.contents)
|
838
|
+
else
|
839
|
+
visited = visit(node.contents)
|
840
|
+
visited.type == :begin ? visited : s(:begin, [visited])
|
841
|
+
end
|
842
|
+
end
|
843
|
+
|
844
|
+
def visit_period(node)
|
845
|
+
raise
|
846
|
+
end
|
847
|
+
|
848
|
+
def visit_pinned_begin(node)
|
849
|
+
s(:pin, [s(:begin, [visit(node.statement)])])
|
850
|
+
end
|
851
|
+
|
852
|
+
def visit_pinned_var_ref(node)
|
853
|
+
s(:pin, [visit(node.value)])
|
854
|
+
end
|
855
|
+
|
856
|
+
def visit_program(node)
|
857
|
+
visit(node.statements)
|
858
|
+
end
|
859
|
+
|
860
|
+
def visit_qsymbols(node)
|
861
|
+
s(:array, node.elements.map { |element| s(:sym, [element.value.to_sym]) })
|
862
|
+
end
|
863
|
+
|
864
|
+
def visit_qsymbols_beg(node)
|
865
|
+
raise
|
866
|
+
end
|
867
|
+
|
868
|
+
def visit_qwords(node)
|
869
|
+
s(:array, visit_all(node.elements))
|
870
|
+
end
|
871
|
+
|
872
|
+
def visit_qwords_beg(node)
|
873
|
+
raise
|
874
|
+
end
|
875
|
+
|
876
|
+
def visit_rassign(node)
|
877
|
+
type = (node.operator in Op[value: "=>"]) ? :match_pattern : :match_pattern_p
|
878
|
+
s(type, [visit(node.value), visit(node.pattern)])
|
879
|
+
end
|
880
|
+
|
881
|
+
def visit_rational(node)
|
882
|
+
s(:rational, [node.value.to_r])
|
883
|
+
end
|
884
|
+
|
885
|
+
def visit_rbrace(node)
|
886
|
+
raise
|
887
|
+
end
|
888
|
+
|
889
|
+
def visit_rbracket(node)
|
890
|
+
raise
|
891
|
+
end
|
892
|
+
|
893
|
+
def visit_redo(node)
|
894
|
+
s(:redo)
|
895
|
+
end
|
896
|
+
|
897
|
+
def visit_regexp_beg(node)
|
898
|
+
raise
|
899
|
+
end
|
900
|
+
|
901
|
+
def visit_regexp_content(node)
|
902
|
+
raise
|
903
|
+
end
|
904
|
+
|
905
|
+
def visit_regexp_end(node)
|
906
|
+
raise
|
907
|
+
end
|
908
|
+
|
909
|
+
def visit_regexp_literal(node)
|
910
|
+
children = visit_all(node.parts)
|
911
|
+
children << s(:regopt, node.ending.scan(/[a-z]/).sort.map(&:to_sym))
|
912
|
+
regexp = s(:regexp, children)
|
913
|
+
|
914
|
+
if stack[-2] in If[predicate: ^(node)] | Unless[predicate: ^(node)]
|
915
|
+
s(:match_current_line, [regexp])
|
916
|
+
elsif stack[-3] in If[predicate: Unary[statement: ^(node), operator: "!"]] | Unless[predicate: Unary[statement: ^(node), operator: "!"]]
|
917
|
+
s(:match_current_line, [regexp])
|
918
|
+
elsif stack[-4] in Program[statements: { body: [*, Unary[statement: ^(node), operator: "!"]] }]
|
919
|
+
s(:match_current_line, [regexp])
|
920
|
+
else
|
921
|
+
regexp
|
922
|
+
end
|
923
|
+
end
|
924
|
+
|
925
|
+
def visit_rescue(node)
|
926
|
+
exceptions =
|
927
|
+
case node.exception
|
928
|
+
in nil | { exceptions: nil }
|
929
|
+
nil
|
930
|
+
in { exceptions: VarRef => part }
|
931
|
+
s(:array, [visit(part)])
|
932
|
+
in { exceptions: MRHS[parts:] }
|
933
|
+
s(:array, visit_all(parts))
|
934
|
+
else
|
935
|
+
s(:array, [visit(node.exception.exceptions)])
|
936
|
+
end
|
937
|
+
|
938
|
+
resbody =
|
939
|
+
case node.exception
|
940
|
+
in nil
|
941
|
+
s(:resbody, [nil, nil, visit(node.statements)])
|
942
|
+
in { variable: nil }
|
943
|
+
s(:resbody, [exceptions, nil, visit(node.statements)])
|
944
|
+
in { variable: VarField => variable }
|
945
|
+
s(:resbody, [exceptions, visit(variable), visit(node.statements)])
|
946
|
+
end
|
947
|
+
|
948
|
+
children = [resbody]
|
949
|
+
if node.consequent
|
950
|
+
children += visit(node.consequent).children
|
951
|
+
else
|
952
|
+
children << nil
|
953
|
+
end
|
954
|
+
|
955
|
+
s(:rescue, children)
|
956
|
+
end
|
957
|
+
|
958
|
+
def visit_rescue_ex(node)
|
959
|
+
raise
|
960
|
+
end
|
961
|
+
|
962
|
+
def visit_rescue_mod(node)
|
963
|
+
s(:rescue, [visit(node.statement), s(:resbody, [nil, nil, visit(node.value)]), nil])
|
964
|
+
end
|
965
|
+
|
966
|
+
def visit_rest_param(node)
|
967
|
+
s(:restarg, node.name ? [node.name.value.to_sym] : [])
|
968
|
+
end
|
969
|
+
|
970
|
+
def visit_retry(node)
|
971
|
+
s(:retry)
|
972
|
+
end
|
973
|
+
|
974
|
+
def visit_return(node)
|
975
|
+
s(:return, visit_all(node.arguments.parts))
|
976
|
+
end
|
977
|
+
|
978
|
+
def visit_return0(node)
|
979
|
+
s(:return)
|
980
|
+
end
|
981
|
+
|
982
|
+
def visit_rparen(node)
|
983
|
+
raise
|
984
|
+
end
|
985
|
+
|
986
|
+
def visit_sclass(node)
|
987
|
+
s(:sclass, [visit(node.target), visit(node.bodystmt)])
|
988
|
+
end
|
989
|
+
|
990
|
+
def visit_statements(node)
|
991
|
+
children = node.body.reject { |child| child in Comment | EmbDoc | EndContent | VoidStmt }
|
992
|
+
|
993
|
+
case children
|
994
|
+
in []
|
995
|
+
nil
|
996
|
+
in [statement]
|
997
|
+
visit(statement)
|
998
|
+
else
|
999
|
+
s(:begin, visit_all(children))
|
1000
|
+
end
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def visit_string_concat(node)
|
1004
|
+
s(:dstr, [visit(node.left), visit(node.right)])
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def visit_string_content(node)
|
1008
|
+
# Can get here if you're inside a hash pattern, e.g., in "a": 1
|
1009
|
+
s(:sym, [node.parts.first.value.to_sym])
|
1010
|
+
end
|
1011
|
+
|
1012
|
+
def visit_string_dvar(node)
|
1013
|
+
visit(node.variable)
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
def visit_string_embexpr(node)
|
1017
|
+
child = visit(node.statements)
|
1018
|
+
s(:begin, child ? [child] : [])
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
def visit_string_literal(node)
|
1022
|
+
case node
|
1023
|
+
in { parts: [] }
|
1024
|
+
s(:str, [""])
|
1025
|
+
in { parts: [TStringContent => part] }
|
1026
|
+
visit(part)
|
1027
|
+
else
|
1028
|
+
s(:dstr, visit_all(node.parts))
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
|
1032
|
+
def visit_super(node)
|
1033
|
+
case node.arguments
|
1034
|
+
in ArgParen[arguments: nil]
|
1035
|
+
s(:super)
|
1036
|
+
in ArgParen[arguments: ArgsForward => arguments]
|
1037
|
+
s(:super, [visit(arguments)])
|
1038
|
+
in ArgParen[arguments: { parts: }]
|
1039
|
+
s(:super, visit_all(parts))
|
1040
|
+
in Args[parts:]
|
1041
|
+
s(:super, visit_all(parts))
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def visit_symbeg(node)
|
1046
|
+
raise
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
def visit_symbol_content(node)
|
1050
|
+
raise
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def visit_symbol_literal(node)
|
1054
|
+
s(:sym, [node.value.value.to_sym])
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def visit_symbols(node)
|
1058
|
+
children =
|
1059
|
+
node.elements.map do |element|
|
1060
|
+
if element.parts.length > 1 || !(element.parts.first in TStringContent)
|
1061
|
+
s(:dsym, visit_all(element.parts))
|
1062
|
+
else
|
1063
|
+
s(:sym, [element.parts.first.value.to_sym])
|
1064
|
+
end
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
s(:array, children)
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
def visit_symbols_beg(node)
|
1071
|
+
raise
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
def visit_tlambda(node)
|
1075
|
+
raise
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
def visit_tlambeg(node)
|
1079
|
+
raise
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
def visit_top_const_field(node)
|
1083
|
+
s(:casgn, [s(:cbase), node.constant.value.to_sym])
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
def visit_top_const_ref(node)
|
1087
|
+
s(:const, [s(:cbase), node.constant.value.to_sym])
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
def visit_tstring_beg(node)
|
1091
|
+
raise
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
def visit_tstring_content(node)
|
1095
|
+
value = node.value.gsub(/([^[:ascii:]])/) { $1.dump[1...-1] }
|
1096
|
+
s(:str, ["\"#{value}\"".undump])
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
def visit_tstring_end(node)
|
1100
|
+
raise
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
def visit_unary(node)
|
1104
|
+
case node
|
1105
|
+
in { statement: Paren[contents: Statements[body: [Dot2 => contents]]], operator: "!" }
|
1106
|
+
s(:send, [s(:begin, [s(:iflipflop, visit(contents).children)]), :"!"])
|
1107
|
+
in { statement: Paren[contents: Statements[body: [Dot3 => contents]]], operator: "!" }
|
1108
|
+
s(:send, [s(:begin, [s(:eflipflop, visit(contents).children)]), :"!"])
|
1109
|
+
in { statement: Int[value:], operator: "+" }
|
1110
|
+
s(:int, [value.to_i])
|
1111
|
+
in { statement: Int[value:], operator: "-" }
|
1112
|
+
s(:int, [-value.to_i])
|
1113
|
+
in { statement: FloatLiteral[value:], operator: "+" }
|
1114
|
+
s(:float, [value.to_f])
|
1115
|
+
in { statement: FloatLiteral[value:], operator: "-" }
|
1116
|
+
s(:float, [-value.to_f])
|
1117
|
+
in { statement:, operator: "+" }
|
1118
|
+
s(:send, [visit(statement), :"+@"])
|
1119
|
+
in { statement:, operator: "-" }
|
1120
|
+
s(:send, [visit(statement), :"-@"])
|
1121
|
+
else
|
1122
|
+
s(:send, [visit(node.statement), node.operator.to_sym])
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
def visit_undef(node)
|
1127
|
+
s(:undef, visit_all(node.symbols))
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
def visit_unless(node)
|
1131
|
+
s(:if, [visit(node.predicate), visit(node.consequent), visit(node.statements)])
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
def visit_unless_mod(node)
|
1135
|
+
s(:if, [visit(node.predicate), nil, visit(node.statement)])
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
def visit_until(node)
|
1139
|
+
s(:until, [visit(node.predicate), visit(node.statements)])
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
def visit_until_mod(node)
|
1143
|
+
children = [visit(node.predicate), visit(node.statement)]
|
1144
|
+
s((node.statement in Begin) ? :until_post : :until, children)
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def visit_var_alias(node)
|
1148
|
+
s(:alias, [visit(node.left), visit(node.right)])
|
1149
|
+
end
|
1150
|
+
|
1151
|
+
def visit_var_field(node)
|
1152
|
+
if stack[-2] in AryPtn | Binary[operator: :"=>"] | FndPtn | HshPtn | In | RAssign
|
1153
|
+
return s(:match_var, [node.value.value.to_sym])
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
case node.value
|
1157
|
+
in Const[value:] then s(:casgn, [nil, value.to_sym])
|
1158
|
+
in CVar[value:] then s(:cvasgn, [value.to_sym])
|
1159
|
+
in GVar[value:] then s(:gvasgn, [value.to_sym])
|
1160
|
+
in Ident[value:] then s(:lvasgn, [value.to_sym])
|
1161
|
+
in IVar[value:] then s(:ivasgn, [value.to_sym])
|
1162
|
+
in VarRef[value:] then s(:lvasgn, [value.to_sym])
|
1163
|
+
in nil then s(:match_rest)
|
1164
|
+
end
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
def visit_var_ref(node)
|
1168
|
+
visit(node.value)
|
1169
|
+
end
|
1170
|
+
|
1171
|
+
def visit_vcall(node)
|
1172
|
+
range = ::Parser::Source::Range.new(buffer, node.location.start_char, node.location.end_char)
|
1173
|
+
location = ::Parser::Source::Map::Send.new(nil, range, nil, nil, range)
|
1174
|
+
|
1175
|
+
s(:send, [nil, node.value.value.to_sym], location: location)
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
def visit_void_stmt(node)
|
1179
|
+
raise
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
def visit_when(node)
|
1183
|
+
s(:when, visit_all(node.arguments.parts) + [visit(node.statements)])
|
1184
|
+
end
|
1185
|
+
|
1186
|
+
def visit_while(node)
|
1187
|
+
s(:while, [visit(node.predicate), visit(node.statements)])
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
def visit_while_mod(node)
|
1191
|
+
children = [visit(node.predicate), visit(node.statement)]
|
1192
|
+
s((node.statement in Begin) ? :while_post : :while, children)
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def visit_word(node)
|
1196
|
+
case node
|
1197
|
+
in { parts: [TStringContent => part] }
|
1198
|
+
visit(part)
|
1199
|
+
else
|
1200
|
+
s(:dstr, visit_all(node.parts))
|
1201
|
+
end
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
def visit_words(node)
|
1205
|
+
s(:array, visit_all(node.elements))
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
def visit_words_beg(node)
|
1209
|
+
raise
|
1210
|
+
end
|
1211
|
+
|
1212
|
+
def visit_xstring(node)
|
1213
|
+
raise
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
def visit_xstring_literal(node)
|
1217
|
+
s(:xstr, visit_all(node.parts))
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
def visit_yield(node)
|
1221
|
+
case node.arguments
|
1222
|
+
in Args[parts:]
|
1223
|
+
s(:yield, visit_all(parts))
|
1224
|
+
in Paren[contents: Args[parts:]]
|
1225
|
+
s(:yield, visit_all(parts))
|
1226
|
+
end
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
def visit_yield0(node)
|
1230
|
+
s(:yield)
|
1231
|
+
end
|
1232
|
+
|
1233
|
+
def visit_zsuper(node)
|
1234
|
+
s(:zsuper)
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
def visit___end__(node)
|
1238
|
+
raise
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
private
|
1242
|
+
|
1243
|
+
# We need to find if we should transform this block into a numblock
|
1244
|
+
# since there could be new numbered variables like _1.
|
1245
|
+
def num_block_type(statements)
|
1246
|
+
variables = []
|
1247
|
+
queue = [statements]
|
1248
|
+
|
1249
|
+
while child_node = queue.shift
|
1250
|
+
if (child_node in VarRef[value: Ident[value:]]) && (value =~ /^_(\d+)$/)
|
1251
|
+
variables << $1.to_i
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
queue += child_node.child_nodes.compact
|
1255
|
+
end
|
1256
|
+
|
1257
|
+
variables.max
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
def s(type, children = [], opts = {})
|
1261
|
+
::Parser::AST::Node.new(type, children, opts)
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
def send_type(operator)
|
1265
|
+
(operator in Op[value: "&."]) ? :csend : :send
|
1266
|
+
end
|
1267
|
+
end
|
1268
|
+
end
|
1269
|
+
end
|