jruby-prism-parser 0.23.0.pre.SNAPSHOT-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +401 -0
  3. data/CODE_OF_CONDUCT.md +76 -0
  4. data/CONTRIBUTING.md +62 -0
  5. data/LICENSE.md +7 -0
  6. data/Makefile +101 -0
  7. data/README.md +98 -0
  8. data/config.yml +2902 -0
  9. data/docs/build_system.md +91 -0
  10. data/docs/configuration.md +64 -0
  11. data/docs/cruby_compilation.md +27 -0
  12. data/docs/design.md +53 -0
  13. data/docs/encoding.md +121 -0
  14. data/docs/fuzzing.md +88 -0
  15. data/docs/heredocs.md +36 -0
  16. data/docs/javascript.md +118 -0
  17. data/docs/local_variable_depth.md +229 -0
  18. data/docs/mapping.md +117 -0
  19. data/docs/parser_translation.md +34 -0
  20. data/docs/parsing_rules.md +19 -0
  21. data/docs/releasing.md +98 -0
  22. data/docs/ripper.md +36 -0
  23. data/docs/ruby_api.md +43 -0
  24. data/docs/ruby_parser_translation.md +19 -0
  25. data/docs/serialization.md +209 -0
  26. data/docs/testing.md +55 -0
  27. data/ext/prism/api_node.c +5098 -0
  28. data/ext/prism/api_pack.c +267 -0
  29. data/ext/prism/extconf.rb +110 -0
  30. data/ext/prism/extension.c +1155 -0
  31. data/ext/prism/extension.h +18 -0
  32. data/include/prism/ast.h +5807 -0
  33. data/include/prism/defines.h +102 -0
  34. data/include/prism/diagnostic.h +339 -0
  35. data/include/prism/encoding.h +265 -0
  36. data/include/prism/node.h +57 -0
  37. data/include/prism/options.h +230 -0
  38. data/include/prism/pack.h +152 -0
  39. data/include/prism/parser.h +732 -0
  40. data/include/prism/prettyprint.h +26 -0
  41. data/include/prism/regexp.h +33 -0
  42. data/include/prism/util/pm_buffer.h +155 -0
  43. data/include/prism/util/pm_char.h +205 -0
  44. data/include/prism/util/pm_constant_pool.h +209 -0
  45. data/include/prism/util/pm_list.h +97 -0
  46. data/include/prism/util/pm_memchr.h +29 -0
  47. data/include/prism/util/pm_newline_list.h +93 -0
  48. data/include/prism/util/pm_state_stack.h +42 -0
  49. data/include/prism/util/pm_string.h +150 -0
  50. data/include/prism/util/pm_string_list.h +44 -0
  51. data/include/prism/util/pm_strncasecmp.h +32 -0
  52. data/include/prism/util/pm_strpbrk.h +46 -0
  53. data/include/prism/version.h +29 -0
  54. data/include/prism.h +289 -0
  55. data/jruby-prism.jar +0 -0
  56. data/lib/prism/compiler.rb +486 -0
  57. data/lib/prism/debug.rb +206 -0
  58. data/lib/prism/desugar_compiler.rb +207 -0
  59. data/lib/prism/dispatcher.rb +2150 -0
  60. data/lib/prism/dot_visitor.rb +4634 -0
  61. data/lib/prism/dsl.rb +785 -0
  62. data/lib/prism/ffi.rb +346 -0
  63. data/lib/prism/lex_compat.rb +908 -0
  64. data/lib/prism/mutation_compiler.rb +753 -0
  65. data/lib/prism/node.rb +17864 -0
  66. data/lib/prism/node_ext.rb +212 -0
  67. data/lib/prism/node_inspector.rb +68 -0
  68. data/lib/prism/pack.rb +224 -0
  69. data/lib/prism/parse_result/comments.rb +177 -0
  70. data/lib/prism/parse_result/newlines.rb +64 -0
  71. data/lib/prism/parse_result.rb +498 -0
  72. data/lib/prism/pattern.rb +250 -0
  73. data/lib/prism/serialize.rb +1354 -0
  74. data/lib/prism/translation/parser/compiler.rb +1838 -0
  75. data/lib/prism/translation/parser/lexer.rb +335 -0
  76. data/lib/prism/translation/parser/rubocop.rb +37 -0
  77. data/lib/prism/translation/parser.rb +178 -0
  78. data/lib/prism/translation/ripper.rb +577 -0
  79. data/lib/prism/translation/ruby_parser.rb +1521 -0
  80. data/lib/prism/translation.rb +11 -0
  81. data/lib/prism/version.rb +3 -0
  82. data/lib/prism/visitor.rb +495 -0
  83. data/lib/prism.rb +99 -0
  84. data/prism.gemspec +135 -0
  85. data/rbi/prism.rbi +7767 -0
  86. data/rbi/prism_static.rbi +207 -0
  87. data/sig/prism.rbs +4773 -0
  88. data/sig/prism_static.rbs +201 -0
  89. data/src/diagnostic.c +400 -0
  90. data/src/encoding.c +5132 -0
  91. data/src/node.c +2786 -0
  92. data/src/options.c +213 -0
  93. data/src/pack.c +493 -0
  94. data/src/prettyprint.c +8881 -0
  95. data/src/prism.c +18406 -0
  96. data/src/regexp.c +638 -0
  97. data/src/serialize.c +1554 -0
  98. data/src/token_type.c +700 -0
  99. data/src/util/pm_buffer.c +190 -0
  100. data/src/util/pm_char.c +318 -0
  101. data/src/util/pm_constant_pool.c +322 -0
  102. data/src/util/pm_list.c +49 -0
  103. data/src/util/pm_memchr.c +35 -0
  104. data/src/util/pm_newline_list.c +84 -0
  105. data/src/util/pm_state_stack.c +25 -0
  106. data/src/util/pm_string.c +203 -0
  107. data/src/util/pm_string_list.c +28 -0
  108. data/src/util/pm_strncasecmp.c +24 -0
  109. data/src/util/pm_strpbrk.c +180 -0
  110. metadata +156 -0
@@ -0,0 +1,1521 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ruby_parser"
4
+
5
+ module Prism
6
+ module Translation
7
+ # This module is the entry-point for converting a prism syntax tree into the
8
+ # seattlerb/ruby_parser gem's syntax tree.
9
+ module RubyParser
10
+ # A prism visitor that builds Sexp objects.
11
+ class Compiler < ::Prism::Compiler
12
+ # This is the name of the file that we are compiling. We set it on every
13
+ # Sexp object that is generated, and also use it to compile __FILE__
14
+ # nodes.
15
+ attr_reader :file
16
+
17
+ # Class variables will change their type based on if they are inside of
18
+ # a method definition or not, so we need to track that state.
19
+ attr_reader :in_def
20
+
21
+ # Some nodes will change their representation if they are inside of a
22
+ # pattern, so we need to track that state.
23
+ attr_reader :in_pattern
24
+
25
+ # Initialize a new compiler with the given file name.
26
+ def initialize(file, in_def: false, in_pattern: false)
27
+ @file = file
28
+ @in_def = in_def
29
+ @in_pattern = in_pattern
30
+ end
31
+
32
+ # alias foo bar
33
+ # ^^^^^^^^^^^^^
34
+ def visit_alias_method_node(node)
35
+ s(node, :alias, visit(node.new_name), visit(node.old_name))
36
+ end
37
+
38
+ # alias $foo $bar
39
+ # ^^^^^^^^^^^^^^^
40
+ def visit_alias_global_variable_node(node)
41
+ s(node, :valias, node.new_name.name, node.old_name.name)
42
+ end
43
+
44
+ # foo => bar | baz
45
+ # ^^^^^^^^^
46
+ def visit_alternation_pattern_node(node)
47
+ s(node, :or, visit(node.left), visit(node.right))
48
+ end
49
+
50
+ # a and b
51
+ # ^^^^^^^
52
+ def visit_and_node(node)
53
+ s(node, :and, visit(node.left), visit(node.right))
54
+ end
55
+
56
+ # []
57
+ # ^^
58
+ def visit_array_node(node)
59
+ if in_pattern
60
+ s(node, :array_pat, nil).concat(visit_all(node.elements))
61
+ else
62
+ s(node, :array).concat(visit_all(node.elements))
63
+ end
64
+ end
65
+
66
+ # foo => [bar]
67
+ # ^^^^^
68
+ def visit_array_pattern_node(node)
69
+ if node.constant.nil? && node.requireds.empty? && node.rest.nil? && node.posts.empty?
70
+ s(node, :array_pat)
71
+ else
72
+ result = s(node, :array_pat, visit_pattern_constant(node.constant)).concat(visit_all(node.requireds))
73
+
74
+ case node.rest
75
+ when SplatNode
76
+ result << :"*#{node.rest.expression&.name}"
77
+ when ImplicitRestNode
78
+ result << :*
79
+
80
+ # This doesn't make any sense at all, but since we're trying to
81
+ # replicate the behavior directly, we'll copy it.
82
+ result.line(666)
83
+ end
84
+
85
+ result.concat(visit_all(node.posts))
86
+ end
87
+ end
88
+
89
+ # foo(bar)
90
+ # ^^^
91
+ def visit_arguments_node(node)
92
+ raise "Cannot visit arguments directly"
93
+ end
94
+
95
+ # { a: 1 }
96
+ # ^^^^
97
+ def visit_assoc_node(node)
98
+ [visit(node.key), visit(node.value)]
99
+ end
100
+
101
+ # def foo(**); bar(**); end
102
+ # ^^
103
+ #
104
+ # { **foo }
105
+ # ^^^^^
106
+ def visit_assoc_splat_node(node)
107
+ if node.value.nil?
108
+ [s(node, :kwsplat)]
109
+ else
110
+ [s(node, :kwsplat, visit(node.value))]
111
+ end
112
+ end
113
+
114
+ # $+
115
+ # ^^
116
+ def visit_back_reference_read_node(node)
117
+ s(node, :back_ref, node.name.name.delete_prefix("$").to_sym)
118
+ end
119
+
120
+ # begin end
121
+ # ^^^^^^^^^
122
+ def visit_begin_node(node)
123
+ result = node.statements.nil? ? s(node, :nil) : visit(node.statements)
124
+
125
+ if !node.rescue_clause.nil?
126
+ if !node.statements.nil?
127
+ result = s(node.statements, :rescue, result, visit(node.rescue_clause))
128
+ else
129
+ result = s(node.rescue_clause, :rescue, visit(node.rescue_clause))
130
+ end
131
+
132
+ current = node.rescue_clause
133
+ until (current = current.consequent).nil?
134
+ result << visit(current)
135
+ end
136
+ end
137
+
138
+ if !node.else_clause&.statements.nil?
139
+ result << visit(node.else_clause)
140
+ end
141
+
142
+ if !node.ensure_clause.nil?
143
+ if !node.statements.nil? || !node.rescue_clause.nil? || !node.else_clause.nil?
144
+ result = s(node.statements || node.rescue_clause || node.else_clause || node.ensure_clause, :ensure, result, visit(node.ensure_clause))
145
+ else
146
+ result = s(node.ensure_clause, :ensure, visit(node.ensure_clause))
147
+ end
148
+ end
149
+
150
+ result
151
+ end
152
+
153
+ # foo(&bar)
154
+ # ^^^^
155
+ def visit_block_argument_node(node)
156
+ s(node, :block_pass).tap do |result|
157
+ result << visit(node.expression) unless node.expression.nil?
158
+ end
159
+ end
160
+
161
+ # foo { |; bar| }
162
+ # ^^^
163
+ def visit_block_local_variable_node(node)
164
+ node.name
165
+ end
166
+
167
+ # A block on a keyword or method call.
168
+ def visit_block_node(node)
169
+ s(node, :block_pass, visit(node.expression))
170
+ end
171
+
172
+ # def foo(&bar); end
173
+ # ^^^^
174
+ def visit_block_parameter_node(node)
175
+ :"&#{node.name}"
176
+ end
177
+
178
+ # A block's parameters.
179
+ def visit_block_parameters_node(node)
180
+ # If this block parameters has no parameters and is using pipes, then
181
+ # it inherits its location from its shadow locals, even if they're not
182
+ # on the same lines as the pipes.
183
+ shadow_loc = true
184
+
185
+ result =
186
+ if node.parameters.nil?
187
+ s(node, :args)
188
+ else
189
+ shadow_loc = false
190
+ visit(node.parameters)
191
+ end
192
+
193
+ if node.opening == "("
194
+ result.line = node.opening_loc.start_line
195
+ result.max_line = node.closing_loc.end_line
196
+ shadow_loc = false
197
+ end
198
+
199
+ if node.locals.any?
200
+ shadow = s(node, :shadow).concat(visit_all(node.locals))
201
+ shadow.line = node.locals.first.location.start_line
202
+ shadow.max_line = node.locals.last.location.end_line
203
+ result << shadow
204
+
205
+ if shadow_loc
206
+ result.line = shadow.line
207
+ result.max_line = shadow.max_line
208
+ end
209
+ end
210
+
211
+ result
212
+ end
213
+
214
+ # break
215
+ # ^^^^^
216
+ #
217
+ # break foo
218
+ # ^^^^^^^^^
219
+ def visit_break_node(node)
220
+ if node.arguments.nil?
221
+ s(node, :break)
222
+ elsif node.arguments.arguments.length == 1
223
+ s(node, :break, visit(node.arguments.arguments.first))
224
+ else
225
+ s(node, :break, s(node.arguments, :array).concat(visit_all(node.arguments.arguments)))
226
+ end
227
+ end
228
+
229
+ # foo
230
+ # ^^^
231
+ #
232
+ # foo.bar
233
+ # ^^^^^^^
234
+ #
235
+ # foo.bar() {}
236
+ # ^^^^^^^^^^^^
237
+ def visit_call_node(node)
238
+ case node.name
239
+ when :!~
240
+ return s(node, :not, visit(node.copy(name: :"=~")))
241
+ when :=~
242
+ if node.arguments&.arguments&.length == 1 && node.block.nil?
243
+ case node.receiver
244
+ when StringNode
245
+ return s(node, :match3, visit(node.arguments.arguments.first), visit(node.receiver))
246
+ when RegularExpressionNode, InterpolatedRegularExpressionNode
247
+ return s(node, :match2, visit(node.receiver), visit(node.arguments.arguments.first))
248
+ end
249
+ end
250
+ end
251
+
252
+ type = node.attribute_write? ? :attrasgn : :call
253
+ type = :"safe_#{type}" if node.safe_navigation?
254
+
255
+ arguments = node.arguments&.arguments || []
256
+ write_value = arguments.pop if type == :attrasgn
257
+ block = node.block
258
+
259
+ if block.is_a?(BlockArgumentNode)
260
+ arguments << block
261
+ block = nil
262
+ end
263
+
264
+ result = s(node, type, visit(node.receiver), node.name).concat(visit_all(arguments))
265
+ result << visit_write_value(write_value) unless write_value.nil?
266
+
267
+ visit_block(node, result, block)
268
+ end
269
+
270
+ # foo.bar += baz
271
+ # ^^^^^^^^^^^^^^^
272
+ def visit_call_operator_write_node(node)
273
+ if op_asgn?(node)
274
+ s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, node.operator)
275
+ else
276
+ s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, node.operator, visit_write_value(node.value))
277
+ end
278
+ end
279
+
280
+ # foo.bar &&= baz
281
+ # ^^^^^^^^^^^^^^^
282
+ def visit_call_and_write_node(node)
283
+ if op_asgn?(node)
284
+ s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, :"&&")
285
+ else
286
+ s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, :"&&", visit_write_value(node.value))
287
+ end
288
+ end
289
+
290
+ # foo.bar ||= baz
291
+ # ^^^^^^^^^^^^^^^
292
+ def visit_call_or_write_node(node)
293
+ if op_asgn?(node)
294
+ s(node, op_asgn_type(node, :op_asgn), visit(node.receiver), visit_write_value(node.value), node.read_name, :"||")
295
+ else
296
+ s(node, op_asgn_type(node, :op_asgn2), visit(node.receiver), node.write_name, :"||", visit_write_value(node.value))
297
+ end
298
+ end
299
+
300
+ # Call nodes with operators following them will either be op_asgn or
301
+ # op_asgn2 nodes. That is determined by their call operator and their
302
+ # right-hand side.
303
+ private def op_asgn?(node)
304
+ node.call_operator == "::" || (node.value.is_a?(CallNode) && node.value.opening_loc.nil? && !node.value.arguments.nil?)
305
+ end
306
+
307
+ # Call nodes with operators following them can use &. as an operator,
308
+ # which changes their type by prefixing "safe_".
309
+ private def op_asgn_type(node, type)
310
+ node.safe_navigation? ? :"safe_#{type}" : type
311
+ end
312
+
313
+ # foo.bar, = 1
314
+ # ^^^^^^^
315
+ def visit_call_target_node(node)
316
+ s(node, :attrasgn, visit(node.receiver), node.name)
317
+ end
318
+
319
+ # foo => bar => baz
320
+ # ^^^^^^^^^^
321
+ def visit_capture_pattern_node(node)
322
+ visit(node.target) << visit(node.value)
323
+ end
324
+
325
+ # case foo; when bar; end
326
+ # ^^^^^^^^^^^^^^^^^^^^^^^
327
+ def visit_case_node(node)
328
+ s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.consequent)
329
+ end
330
+
331
+ # case foo; in bar; end
332
+ # ^^^^^^^^^^^^^^^^^^^^^
333
+ def visit_case_match_node(node)
334
+ s(node, :case, visit(node.predicate)).concat(visit_all(node.conditions)) << visit(node.consequent)
335
+ end
336
+
337
+ # class Foo; end
338
+ # ^^^^^^^^^^^^^^
339
+ def visit_class_node(node)
340
+ name =
341
+ if node.constant_path.is_a?(ConstantReadNode)
342
+ node.name
343
+ else
344
+ visit(node.constant_path)
345
+ end
346
+
347
+ if node.body.nil?
348
+ s(node, :class, name, visit(node.superclass))
349
+ elsif node.body.is_a?(StatementsNode)
350
+ compiler = copy_compiler(in_def: false)
351
+ s(node, :class, name, visit(node.superclass)).concat(node.body.body.map { |child| child.accept(compiler) })
352
+ else
353
+ s(node, :class, name, visit(node.superclass), node.body.accept(copy_compiler(in_def: false)))
354
+ end
355
+ end
356
+
357
+ # @@foo
358
+ # ^^^^^
359
+ def visit_class_variable_read_node(node)
360
+ s(node, :cvar, node.name)
361
+ end
362
+
363
+ # @@foo = 1
364
+ # ^^^^^^^^^
365
+ #
366
+ # @@foo, @@bar = 1
367
+ # ^^^^^ ^^^^^
368
+ def visit_class_variable_write_node(node)
369
+ s(node, class_variable_write_type, node.name, visit_write_value(node.value))
370
+ end
371
+
372
+ # @@foo += bar
373
+ # ^^^^^^^^^^^^
374
+ def visit_class_variable_operator_write_node(node)
375
+ s(node, class_variable_write_type, node.name, s(node, :call, s(node, :cvar, node.name), node.operator, visit_write_value(node.value)))
376
+ end
377
+
378
+ # @@foo &&= bar
379
+ # ^^^^^^^^^^^^^
380
+ def visit_class_variable_and_write_node(node)
381
+ s(node, :op_asgn_and, s(node, :cvar, node.name), s(node, class_variable_write_type, node.name, visit_write_value(node.value)))
382
+ end
383
+
384
+ # @@foo ||= bar
385
+ # ^^^^^^^^^^^^^
386
+ def visit_class_variable_or_write_node(node)
387
+ s(node, :op_asgn_or, s(node, :cvar, node.name), s(node, class_variable_write_type, node.name, visit_write_value(node.value)))
388
+ end
389
+
390
+ # @@foo, = bar
391
+ # ^^^^^
392
+ def visit_class_variable_target_node(node)
393
+ s(node, class_variable_write_type, node.name)
394
+ end
395
+
396
+ # If a class variable is written within a method definition, it has a
397
+ # different type than everywhere else.
398
+ private def class_variable_write_type
399
+ in_def ? :cvasgn : :cvdecl
400
+ end
401
+
402
+ # Foo
403
+ # ^^^
404
+ def visit_constant_read_node(node)
405
+ s(node, :const, node.name)
406
+ end
407
+
408
+ # Foo = 1
409
+ # ^^^^^^^
410
+ #
411
+ # Foo, Bar = 1
412
+ # ^^^ ^^^
413
+ def visit_constant_write_node(node)
414
+ s(node, :cdecl, node.name, visit_write_value(node.value))
415
+ end
416
+
417
+ # Foo += bar
418
+ # ^^^^^^^^^^^
419
+ def visit_constant_operator_write_node(node)
420
+ s(node, :cdecl, node.name, s(node, :call, s(node, :const, node.name), node.operator, visit_write_value(node.value)))
421
+ end
422
+
423
+ # Foo &&= bar
424
+ # ^^^^^^^^^^^^
425
+ def visit_constant_and_write_node(node)
426
+ s(node, :op_asgn_and, s(node, :const, node.name), s(node, :cdecl, node.name, visit(node.value)))
427
+ end
428
+
429
+ # Foo ||= bar
430
+ # ^^^^^^^^^^^^
431
+ def visit_constant_or_write_node(node)
432
+ s(node, :op_asgn_or, s(node, :const, node.name), s(node, :cdecl, node.name, visit(node.value)))
433
+ end
434
+
435
+ # Foo, = bar
436
+ # ^^^
437
+ def visit_constant_target_node(node)
438
+ s(node, :cdecl, node.name)
439
+ end
440
+
441
+ # Foo::Bar
442
+ # ^^^^^^^^
443
+ def visit_constant_path_node(node)
444
+ if node.parent.nil?
445
+ s(node, :colon3, node.child.name)
446
+ else
447
+ s(node, :colon2, visit(node.parent), node.child.name)
448
+ end
449
+ end
450
+
451
+ # Foo::Bar = 1
452
+ # ^^^^^^^^^^^^
453
+ #
454
+ # Foo::Foo, Bar::Bar = 1
455
+ # ^^^^^^^^ ^^^^^^^^
456
+ def visit_constant_path_write_node(node)
457
+ s(node, :cdecl, visit(node.target), visit_write_value(node.value))
458
+ end
459
+
460
+ # Foo::Bar += baz
461
+ # ^^^^^^^^^^^^^^^
462
+ def visit_constant_path_operator_write_node(node)
463
+ s(node, :op_asgn, visit(node.target), node.operator, visit_write_value(node.value))
464
+ end
465
+
466
+ # Foo::Bar &&= baz
467
+ # ^^^^^^^^^^^^^^^^
468
+ def visit_constant_path_and_write_node(node)
469
+ s(node, :op_asgn_and, visit(node.target), visit_write_value(node.value))
470
+ end
471
+
472
+ # Foo::Bar ||= baz
473
+ # ^^^^^^^^^^^^^^^^
474
+ def visit_constant_path_or_write_node(node)
475
+ s(node, :op_asgn_or, visit(node.target), visit_write_value(node.value))
476
+ end
477
+
478
+ # Foo::Bar, = baz
479
+ # ^^^^^^^^
480
+ def visit_constant_path_target_node(node)
481
+ inner =
482
+ if node.parent.nil?
483
+ s(node, :colon3, node.child.name)
484
+ else
485
+ s(node, :colon2, visit(node.parent), node.child.name)
486
+ end
487
+
488
+ s(node, :const, inner)
489
+ end
490
+
491
+ # def foo; end
492
+ # ^^^^^^^^^^^^
493
+ #
494
+ # def self.foo; end
495
+ # ^^^^^^^^^^^^^^^^^
496
+ def visit_def_node(node)
497
+ name = node.name_loc.slice.to_sym
498
+ result =
499
+ if node.receiver.nil?
500
+ s(node, :defn, name)
501
+ else
502
+ s(node, :defs, visit(node.receiver), name)
503
+ end
504
+
505
+ result.line(node.name_loc.start_line)
506
+ if node.parameters.nil?
507
+ result << s(node, :args).line(node.name_loc.start_line)
508
+ else
509
+ result << visit(node.parameters)
510
+ end
511
+
512
+ if node.body.nil?
513
+ result << s(node, :nil)
514
+ elsif node.body.is_a?(StatementsNode)
515
+ compiler = copy_compiler(in_def: true)
516
+ result.concat(node.body.body.map { |child| child.accept(compiler) })
517
+ else
518
+ result << node.body.accept(copy_compiler(in_def: true))
519
+ end
520
+ end
521
+
522
+ # defined? a
523
+ # ^^^^^^^^^^
524
+ #
525
+ # defined?(a)
526
+ # ^^^^^^^^^^^
527
+ def visit_defined_node(node)
528
+ s(node, :defined, visit(node.value))
529
+ end
530
+
531
+ # if foo then bar else baz end
532
+ # ^^^^^^^^^^^^
533
+ def visit_else_node(node)
534
+ visit(node.statements)
535
+ end
536
+
537
+ # "foo #{bar}"
538
+ # ^^^^^^
539
+ def visit_embedded_statements_node(node)
540
+ result = s(node, :evstr)
541
+ result << visit(node.statements) unless node.statements.nil?
542
+ result
543
+ end
544
+
545
+ # "foo #@bar"
546
+ # ^^^^^
547
+ def visit_embedded_variable_node(node)
548
+ s(node, :evstr, visit(node.variable))
549
+ end
550
+
551
+ # begin; foo; ensure; bar; end
552
+ # ^^^^^^^^^^^^
553
+ def visit_ensure_node(node)
554
+ node.statements.nil? ? s(node, :nil) : visit(node.statements)
555
+ end
556
+
557
+ # false
558
+ # ^^^^^
559
+ def visit_false_node(node)
560
+ s(node, :false)
561
+ end
562
+
563
+ # foo => [*, bar, *]
564
+ # ^^^^^^^^^^^
565
+ def visit_find_pattern_node(node)
566
+ s(node, :find_pat, visit_pattern_constant(node.constant), :"*#{node.left.expression&.name}", *visit_all(node.requireds), :"*#{node.right.expression&.name}")
567
+ end
568
+
569
+ # if foo .. bar; end
570
+ # ^^^^^^^^^^
571
+ def visit_flip_flop_node(node)
572
+ if node.left.is_a?(IntegerNode) && node.right.is_a?(IntegerNode)
573
+ s(node, :lit, Range.new(node.left.value, node.right.value, node.exclude_end?))
574
+ else
575
+ s(node, node.exclude_end? ? :flip3 : :flip2, visit(node.left), visit(node.right))
576
+ end
577
+ end
578
+
579
+ # 1.0
580
+ # ^^^
581
+ def visit_float_node(node)
582
+ s(node, :lit, node.value)
583
+ end
584
+
585
+ # for foo in bar do end
586
+ # ^^^^^^^^^^^^^^^^^^^^^
587
+ def visit_for_node(node)
588
+ s(node, :for, visit(node.collection), visit(node.index), visit(node.statements))
589
+ end
590
+
591
+ # def foo(...); bar(...); end
592
+ # ^^^
593
+ def visit_forwarding_arguments_node(node)
594
+ s(node, :forward_args)
595
+ end
596
+
597
+ # def foo(...); end
598
+ # ^^^
599
+ def visit_forwarding_parameter_node(node)
600
+ s(node, :forward_args)
601
+ end
602
+
603
+ # super
604
+ # ^^^^^
605
+ #
606
+ # super {}
607
+ # ^^^^^^^^
608
+ def visit_forwarding_super_node(node)
609
+ visit_block(node, s(node, :zsuper), node.block)
610
+ end
611
+
612
+ # $foo
613
+ # ^^^^
614
+ def visit_global_variable_read_node(node)
615
+ s(node, :gvar, node.name)
616
+ end
617
+
618
+ # $foo = 1
619
+ # ^^^^^^^^
620
+ #
621
+ # $foo, $bar = 1
622
+ # ^^^^ ^^^^
623
+ def visit_global_variable_write_node(node)
624
+ s(node, :gasgn, node.name, visit_write_value(node.value))
625
+ end
626
+
627
+ # $foo += bar
628
+ # ^^^^^^^^^^^
629
+ def visit_global_variable_operator_write_node(node)
630
+ s(node, :gasgn, node.name, s(node, :call, s(node, :gvar, node.name), node.operator, visit(node.value)))
631
+ end
632
+
633
+ # $foo &&= bar
634
+ # ^^^^^^^^^^^^
635
+ def visit_global_variable_and_write_node(node)
636
+ s(node, :op_asgn_and, s(node, :gvar, node.name), s(node, :gasgn, node.name, visit_write_value(node.value)))
637
+ end
638
+
639
+ # $foo ||= bar
640
+ # ^^^^^^^^^^^^
641
+ def visit_global_variable_or_write_node(node)
642
+ s(node, :op_asgn_or, s(node, :gvar, node.name), s(node, :gasgn, node.name, visit_write_value(node.value)))
643
+ end
644
+
645
+ # $foo, = bar
646
+ # ^^^^
647
+ def visit_global_variable_target_node(node)
648
+ s(node, :gasgn, node.name)
649
+ end
650
+
651
+ # {}
652
+ # ^^
653
+ def visit_hash_node(node)
654
+ s(node, :hash).concat(node.elements.flat_map { |element| visit(element) })
655
+ end
656
+
657
+ # foo => {}
658
+ # ^^
659
+ def visit_hash_pattern_node(node)
660
+ result = s(node, :hash_pat, visit_pattern_constant(node.constant)).concat(node.elements.flat_map { |element| visit(element) })
661
+
662
+ case node.rest
663
+ when AssocSplatNode
664
+ result << s(node.rest, :kwrest, :"**#{node.rest.value&.name}")
665
+ when NoKeywordsParameterNode
666
+ result << visit(node.rest)
667
+ end
668
+
669
+ result
670
+ end
671
+
672
+ # if foo then bar end
673
+ # ^^^^^^^^^^^^^^^^^^^
674
+ #
675
+ # bar if foo
676
+ # ^^^^^^^^^^
677
+ #
678
+ # foo ? bar : baz
679
+ # ^^^^^^^^^^^^^^^
680
+ def visit_if_node(node)
681
+ s(node, :if, visit(node.predicate), visit(node.statements), visit(node.consequent))
682
+ end
683
+
684
+ # 1i
685
+ def visit_imaginary_node(node)
686
+ s(node, :lit, node.value)
687
+ end
688
+
689
+ # { foo: }
690
+ # ^^^^
691
+ def visit_implicit_node(node)
692
+ end
693
+
694
+ # foo { |bar,| }
695
+ # ^
696
+ def visit_implicit_rest_node(node)
697
+ end
698
+
699
+ # case foo; in bar; end
700
+ # ^^^^^^^^^^^^^^^^^^^^^
701
+ def visit_in_node(node)
702
+ pattern =
703
+ if node.pattern.is_a?(ConstantPathNode)
704
+ s(node.pattern, :const, visit(node.pattern))
705
+ else
706
+ node.pattern.accept(copy_compiler(in_pattern: true))
707
+ end
708
+
709
+ s(node, :in, pattern).concat(node.statements.nil? ? [nil] : visit_all(node.statements.body))
710
+ end
711
+
712
+ # foo[bar] += baz
713
+ # ^^^^^^^^^^^^^^^
714
+ def visit_index_operator_write_node(node)
715
+ arglist = nil
716
+
717
+ if !node.arguments.nil? || !node.block.nil?
718
+ arglist = s(node, :arglist).concat(visit_all(node.arguments&.arguments || []))
719
+ arglist << visit(node.block) if !node.block.nil?
720
+ end
721
+
722
+ s(node, :op_asgn1, visit(node.receiver), arglist, node.operator, visit_write_value(node.value))
723
+ end
724
+
725
+ # foo[bar] &&= baz
726
+ # ^^^^^^^^^^^^^^^^
727
+ def visit_index_and_write_node(node)
728
+ arglist = nil
729
+
730
+ if !node.arguments.nil? || !node.block.nil?
731
+ arglist = s(node, :arglist).concat(visit_all(node.arguments&.arguments || []))
732
+ arglist << visit(node.block) if !node.block.nil?
733
+ end
734
+
735
+ s(node, :op_asgn1, visit(node.receiver), arglist, :"&&", visit_write_value(node.value))
736
+ end
737
+
738
+ # foo[bar] ||= baz
739
+ # ^^^^^^^^^^^^^^^^
740
+ def visit_index_or_write_node(node)
741
+ arglist = nil
742
+
743
+ if !node.arguments.nil? || !node.block.nil?
744
+ arglist = s(node, :arglist).concat(visit_all(node.arguments&.arguments || []))
745
+ arglist << visit(node.block) if !node.block.nil?
746
+ end
747
+
748
+ s(node, :op_asgn1, visit(node.receiver), arglist, :"||", visit_write_value(node.value))
749
+ end
750
+
751
+ # foo[bar], = 1
752
+ # ^^^^^^^^
753
+ def visit_index_target_node(node)
754
+ arguments = visit_all(node.arguments&.arguments || [])
755
+ arguments << visit(node.block) unless node.block.nil?
756
+
757
+ s(node, :attrasgn, visit(node.receiver), :[]=).concat(arguments)
758
+ end
759
+
760
+ # @foo
761
+ # ^^^^
762
+ def visit_instance_variable_read_node(node)
763
+ s(node, :ivar, node.name)
764
+ end
765
+
766
+ # @foo = 1
767
+ # ^^^^^^^^
768
+ #
769
+ # @foo, @bar = 1
770
+ # ^^^^ ^^^^
771
+ def visit_instance_variable_write_node(node)
772
+ s(node, :iasgn, node.name, visit_write_value(node.value))
773
+ end
774
+
775
+ # @foo += bar
776
+ # ^^^^^^^^^^^
777
+ def visit_instance_variable_operator_write_node(node)
778
+ s(node, :iasgn, node.name, s(node, :call, s(node, :ivar, node.name), node.operator, visit_write_value(node.value)))
779
+ end
780
+
781
+ # @foo &&= bar
782
+ # ^^^^^^^^^^^^
783
+ def visit_instance_variable_and_write_node(node)
784
+ s(node, :op_asgn_and, s(node, :ivar, node.name), s(node, :iasgn, node.name, visit(node.value)))
785
+ end
786
+
787
+ # @foo ||= bar
788
+ # ^^^^^^^^^^^^
789
+ def visit_instance_variable_or_write_node(node)
790
+ s(node, :op_asgn_or, s(node, :ivar, node.name), s(node, :iasgn, node.name, visit(node.value)))
791
+ end
792
+
793
+ # @foo, = bar
794
+ # ^^^^
795
+ def visit_instance_variable_target_node(node)
796
+ s(node, :iasgn, node.name)
797
+ end
798
+
799
+ # 1
800
+ # ^
801
+ def visit_integer_node(node)
802
+ s(node, :lit, node.value)
803
+ end
804
+
805
+ # if /foo #{bar}/ then end
806
+ # ^^^^^^^^^^^^
807
+ def visit_interpolated_match_last_line_node(node)
808
+ s(node, :match, s(node, :dregx).concat(visit_interpolated_parts(node.parts)))
809
+ end
810
+
811
+ # /foo #{bar}/
812
+ # ^^^^^^^^^^^^
813
+ def visit_interpolated_regular_expression_node(node)
814
+ if node.parts.all? { |part| part.is_a?(StringNode) || (part.is_a?(EmbeddedStatementsNode) && part.statements&.body&.length == 1 && part.statements.body.first.is_a?(StringNode)) }
815
+ unescaped = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : part.statements.body.first.unescaped }.join
816
+ s(node, :lit, Regexp.new(unescaped, node.options))
817
+ else
818
+ s(node, :dregx).concat(visit_interpolated_parts(node.parts)).tap do |result|
819
+ options = node.options
820
+ result << options if options != 0
821
+ end
822
+ end
823
+ end
824
+
825
+ # "foo #{bar}"
826
+ # ^^^^^^^^^^^^
827
+ def visit_interpolated_string_node(node)
828
+ if (node.parts.all? { |part| part.is_a?(StringNode) || (part.is_a?(EmbeddedStatementsNode) && part.statements&.body&.length == 1 && part.statements.body.first.is_a?(StringNode)) }) ||
829
+ (node.opening.nil? && node.parts.all? { |part| part.is_a?(StringNode) && !part.opening_loc.nil? })
830
+ unescaped = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : part.statements.body.first.unescaped }.join
831
+ s(node, :str, unescaped)
832
+ else
833
+ s(node, :dstr).concat(visit_interpolated_parts(node.parts))
834
+ end
835
+ end
836
+
837
+ # :"foo #{bar}"
838
+ # ^^^^^^^^^^^^^
839
+ def visit_interpolated_symbol_node(node)
840
+ if node.parts.all? { |part| part.is_a?(StringNode) || (part.is_a?(EmbeddedStatementsNode) && part.statements&.body&.length == 1 && part.statements.body.first.is_a?(StringNode)) }
841
+ unescaped = node.parts.map { |part| part.is_a?(StringNode) ? part.unescaped : part.statements.body.first.unescaped }.join
842
+ s(node, :lit, unescaped.to_sym)
843
+ else
844
+ s(node, :dsym).concat(visit_interpolated_parts(node.parts))
845
+ end
846
+ end
847
+
848
+ # `foo #{bar}`
849
+ # ^^^^^^^^^^^^
850
+ def visit_interpolated_x_string_node(node)
851
+ children = visit_interpolated_parts(node.parts)
852
+ s(node.heredoc? ? node.parts.first : node, :dxstr).concat(children)
853
+ end
854
+
855
+ # Visit the interpolated content of the string-like node.
856
+ private def visit_interpolated_parts(parts)
857
+ parts.each_with_object([]).with_index do |(part, results), index|
858
+ if index == 0
859
+ if part.is_a?(StringNode)
860
+ results << part.unescaped
861
+ else
862
+ results << ""
863
+ results << visit(part)
864
+ end
865
+ else
866
+ results << visit(part)
867
+ end
868
+ end
869
+ end
870
+
871
+ # foo(bar: baz)
872
+ # ^^^^^^^^
873
+ def visit_keyword_hash_node(node)
874
+ s(node, :hash).concat(node.elements.flat_map { |element| visit(element) })
875
+ end
876
+
877
+ # def foo(**bar); end
878
+ # ^^^^^
879
+ #
880
+ # def foo(**); end
881
+ # ^^
882
+ def visit_keyword_rest_parameter_node(node)
883
+ :"**#{node.name}"
884
+ end
885
+
886
+ # -> {}
887
+ def visit_lambda_node(node)
888
+ parameters =
889
+ case node.parameters
890
+ when nil, NumberedParametersNode
891
+ s(node, :args)
892
+ else
893
+ visit(node.parameters)
894
+ end
895
+
896
+ if node.body.nil?
897
+ s(node, :iter, s(node, :lambda), parameters)
898
+ else
899
+ s(node, :iter, s(node, :lambda), parameters, visit(node.body))
900
+ end
901
+ end
902
+
903
+ # foo
904
+ # ^^^
905
+ def visit_local_variable_read_node(node)
906
+ if node.name.match?(/^_\d$/)
907
+ s(node, :call, nil, node.name)
908
+ else
909
+ s(node, :lvar, node.name)
910
+ end
911
+ end
912
+
913
+ # foo = 1
914
+ # ^^^^^^^
915
+ #
916
+ # foo, bar = 1
917
+ # ^^^ ^^^
918
+ def visit_local_variable_write_node(node)
919
+ s(node, :lasgn, node.name, visit_write_value(node.value))
920
+ end
921
+
922
+ # foo += bar
923
+ # ^^^^^^^^^^
924
+ def visit_local_variable_operator_write_node(node)
925
+ s(node, :lasgn, node.name, s(node, :call, s(node, :lvar, node.name), node.operator, visit_write_value(node.value)))
926
+ end
927
+
928
+ # foo &&= bar
929
+ # ^^^^^^^^^^^
930
+ def visit_local_variable_and_write_node(node)
931
+ s(node, :op_asgn_and, s(node, :lvar, node.name), s(node, :lasgn, node.name, visit_write_value(node.value)))
932
+ end
933
+
934
+ # foo ||= bar
935
+ # ^^^^^^^^^^^
936
+ def visit_local_variable_or_write_node(node)
937
+ s(node, :op_asgn_or, s(node, :lvar, node.name), s(node, :lasgn, node.name, visit_write_value(node.value)))
938
+ end
939
+
940
+ # foo, = bar
941
+ # ^^^
942
+ def visit_local_variable_target_node(node)
943
+ s(node, :lasgn, node.name)
944
+ end
945
+
946
+ # if /foo/ then end
947
+ # ^^^^^
948
+ def visit_match_last_line_node(node)
949
+ s(node, :match, s(node, :lit, Regexp.new(node.unescaped, node.options)))
950
+ end
951
+
952
+ # foo in bar
953
+ # ^^^^^^^^^^
954
+ def visit_match_predicate_node(node)
955
+ s(node, :case, visit(node.value), s(node, :in, node.pattern.accept(copy_compiler(in_pattern: true)), nil), nil)
956
+ end
957
+
958
+ # foo => bar
959
+ # ^^^^^^^^^^
960
+ def visit_match_required_node(node)
961
+ s(node, :case, visit(node.value), s(node, :in, node.pattern.accept(copy_compiler(in_pattern: true)), nil), nil)
962
+ end
963
+
964
+ # /(?<foo>foo)/ =~ bar
965
+ # ^^^^^^^^^^^^^^^^^^^^
966
+ def visit_match_write_node(node)
967
+ s(node, :match2, visit(node.call.receiver), visit(node.call.arguments.arguments.first))
968
+ end
969
+
970
+ # A node that is missing from the syntax tree. This is only used in the
971
+ # case of a syntax error. The parser gem doesn't have such a concept, so
972
+ # we invent our own here.
973
+ def visit_missing_node(node)
974
+ raise "Cannot visit missing node directly"
975
+ end
976
+
977
+ # module Foo; end
978
+ # ^^^^^^^^^^^^^^^
979
+ def visit_module_node(node)
980
+ name =
981
+ if node.constant_path.is_a?(ConstantReadNode)
982
+ node.name
983
+ else
984
+ visit(node.constant_path)
985
+ end
986
+
987
+ if node.body.nil?
988
+ s(node, :module, name)
989
+ elsif node.body.is_a?(StatementsNode)
990
+ compiler = copy_compiler(in_def: false)
991
+ s(node, :module, name).concat(node.body.body.map { |child| child.accept(compiler) })
992
+ else
993
+ s(node, :module, name, node.body.accept(copy_compiler(in_def: false)))
994
+ end
995
+ end
996
+
997
+ # foo, bar = baz
998
+ # ^^^^^^^^
999
+ def visit_multi_target_node(node)
1000
+ targets = [*node.lefts]
1001
+ targets << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
1002
+ targets.concat(node.rights)
1003
+
1004
+ s(node, :masgn, s(node, :array).concat(visit_all(targets)))
1005
+ end
1006
+
1007
+ # foo, bar = baz
1008
+ # ^^^^^^^^^^^^^^
1009
+ def visit_multi_write_node(node)
1010
+ targets = [*node.lefts]
1011
+ targets << node.rest if !node.rest.nil? && !node.rest.is_a?(ImplicitRestNode)
1012
+ targets.concat(node.rights)
1013
+
1014
+ value =
1015
+ if node.value.is_a?(ArrayNode) && node.value.opening_loc.nil?
1016
+ if node.value.elements.length == 1 && node.value.elements.first.is_a?(SplatNode)
1017
+ visit(node.value.elements.first)
1018
+ else
1019
+ visit(node.value)
1020
+ end
1021
+ else
1022
+ s(node.value, :to_ary, visit(node.value))
1023
+ end
1024
+
1025
+ s(node, :masgn, s(node, :array).concat(visit_all(targets)), value)
1026
+ end
1027
+
1028
+ # next
1029
+ # ^^^^
1030
+ #
1031
+ # next foo
1032
+ # ^^^^^^^^
1033
+ def visit_next_node(node)
1034
+ if node.arguments.nil?
1035
+ s(node, :next)
1036
+ elsif node.arguments.arguments.length == 1
1037
+ argument = node.arguments.arguments.first
1038
+ s(node, :next, argument.is_a?(SplatNode) ? s(node, :svalue, visit(argument)) : visit(argument))
1039
+ else
1040
+ s(node, :next, s(node, :array).concat(visit_all(node.arguments.arguments)))
1041
+ end
1042
+ end
1043
+
1044
+ # nil
1045
+ # ^^^
1046
+ def visit_nil_node(node)
1047
+ s(node, :nil)
1048
+ end
1049
+
1050
+ # def foo(**nil); end
1051
+ # ^^^^^
1052
+ def visit_no_keywords_parameter_node(node)
1053
+ in_pattern ? s(node, :kwrest, :"**nil") : :"**nil"
1054
+ end
1055
+
1056
+ # -> { _1 + _2 }
1057
+ # ^^^^^^^^^^^^^^
1058
+ def visit_numbered_parameters_node(node)
1059
+ raise "Cannot visit numbered parameters directly"
1060
+ end
1061
+
1062
+ # $1
1063
+ # ^^
1064
+ def visit_numbered_reference_read_node(node)
1065
+ s(node, :nth_ref, node.number)
1066
+ end
1067
+
1068
+ # def foo(bar: baz); end
1069
+ # ^^^^^^^^
1070
+ def visit_optional_keyword_parameter_node(node)
1071
+ s(node, :kwarg, node.name, visit(node.value))
1072
+ end
1073
+
1074
+ # def foo(bar = 1); end
1075
+ # ^^^^^^^
1076
+ def visit_optional_parameter_node(node)
1077
+ s(node, :lasgn, node.name, visit(node.value))
1078
+ end
1079
+
1080
+ # a or b
1081
+ # ^^^^^^
1082
+ def visit_or_node(node)
1083
+ s(node, :or, visit(node.left), visit(node.right))
1084
+ end
1085
+
1086
+ # def foo(bar, *baz); end
1087
+ # ^^^^^^^^^
1088
+ def visit_parameters_node(node)
1089
+ children =
1090
+ node.compact_child_nodes.map do |element|
1091
+ if element.is_a?(MultiTargetNode)
1092
+ visit_destructured_parameter(element)
1093
+ else
1094
+ visit(element)
1095
+ end
1096
+ end
1097
+
1098
+ s(node, :args).concat(children)
1099
+ end
1100
+
1101
+ # def foo((bar, baz)); end
1102
+ # ^^^^^^^^^^
1103
+ private def visit_destructured_parameter(node)
1104
+ children =
1105
+ [*node.lefts, *node.rest, *node.rights].map do |child|
1106
+ case child
1107
+ when RequiredParameterNode
1108
+ visit(child)
1109
+ when MultiTargetNode
1110
+ visit_destructured_parameter(child)
1111
+ when SplatNode
1112
+ :"*#{child.expression&.name}"
1113
+ else
1114
+ raise
1115
+ end
1116
+ end
1117
+
1118
+ s(node, :masgn).concat(children)
1119
+ end
1120
+
1121
+ # ()
1122
+ # ^^
1123
+ #
1124
+ # (1)
1125
+ # ^^^
1126
+ def visit_parentheses_node(node)
1127
+ if node.body.nil?
1128
+ s(node, :nil)
1129
+ else
1130
+ visit(node.body)
1131
+ end
1132
+ end
1133
+
1134
+ # foo => ^(bar)
1135
+ # ^^^^^^
1136
+ def visit_pinned_expression_node(node)
1137
+ node.expression.accept(copy_compiler(in_pattern: false))
1138
+ end
1139
+
1140
+ # foo = 1 and bar => ^foo
1141
+ # ^^^^
1142
+ def visit_pinned_variable_node(node)
1143
+ if node.variable.is_a?(LocalVariableReadNode) && node.variable.name.match?(/^_\d$/)
1144
+ s(node, :lvar, node.variable.name)
1145
+ else
1146
+ visit(node.variable)
1147
+ end
1148
+ end
1149
+
1150
+ # END {}
1151
+ def visit_post_execution_node(node)
1152
+ s(node, :iter, s(node, :postexe), 0, visit(node.statements))
1153
+ end
1154
+
1155
+ # BEGIN {}
1156
+ def visit_pre_execution_node(node)
1157
+ s(node, :iter, s(node, :preexe), 0, visit(node.statements))
1158
+ end
1159
+
1160
+ # The top-level program node.
1161
+ def visit_program_node(node)
1162
+ visit(node.statements)
1163
+ end
1164
+
1165
+ # 0..5
1166
+ # ^^^^
1167
+ def visit_range_node(node)
1168
+ if !in_pattern && !node.left.nil? && !node.right.nil? && ([node.left.type, node.right.type] - %i[nil_node integer_node]).empty?
1169
+ left = node.left.value if node.left.is_a?(IntegerNode)
1170
+ right = node.right.value if node.right.is_a?(IntegerNode)
1171
+ s(node, :lit, Range.new(left, right, node.exclude_end?))
1172
+ else
1173
+ s(node, node.exclude_end? ? :dot3 : :dot2, visit_range_bounds_node(node.left), visit_range_bounds_node(node.right))
1174
+ end
1175
+ end
1176
+
1177
+ # If the bounds of a range node are empty parentheses, then they do not
1178
+ # get replaced by their usual s(:nil), but instead are s(:begin).
1179
+ private def visit_range_bounds_node(node)
1180
+ if node.is_a?(ParenthesesNode) && node.body.nil?
1181
+ s(node, :begin)
1182
+ else
1183
+ visit(node)
1184
+ end
1185
+ end
1186
+
1187
+ # 1r
1188
+ # ^^
1189
+ def visit_rational_node(node)
1190
+ s(node, :lit, node.value)
1191
+ end
1192
+
1193
+ # redo
1194
+ # ^^^^
1195
+ def visit_redo_node(node)
1196
+ s(node, :redo)
1197
+ end
1198
+
1199
+ # /foo/
1200
+ # ^^^^^
1201
+ def visit_regular_expression_node(node)
1202
+ s(node, :lit, Regexp.new(node.unescaped, node.options))
1203
+ end
1204
+
1205
+ # def foo(bar:); end
1206
+ # ^^^^
1207
+ def visit_required_keyword_parameter_node(node)
1208
+ s(node, :kwarg, node.name)
1209
+ end
1210
+
1211
+ # def foo(bar); end
1212
+ # ^^^
1213
+ def visit_required_parameter_node(node)
1214
+ node.name
1215
+ end
1216
+
1217
+ # foo rescue bar
1218
+ # ^^^^^^^^^^^^^^
1219
+ def visit_rescue_modifier_node(node)
1220
+ s(node, :rescue, visit(node.expression), s(node.rescue_expression, :resbody, s(node.rescue_expression, :array), visit(node.rescue_expression)))
1221
+ end
1222
+
1223
+ # begin; rescue; end
1224
+ # ^^^^^^^
1225
+ def visit_rescue_node(node)
1226
+ exceptions =
1227
+ if node.exceptions.length == 1 && node.exceptions.first.is_a?(SplatNode)
1228
+ visit(node.exceptions.first)
1229
+ else
1230
+ s(node, :array).concat(visit_all(node.exceptions))
1231
+ end
1232
+
1233
+ if !node.reference.nil?
1234
+ exceptions << (visit(node.reference) << s(node.reference, :gvar, :"$!"))
1235
+ end
1236
+
1237
+ s(node, :resbody, exceptions).concat(node.statements.nil? ? [nil] : visit_all(node.statements.body))
1238
+ end
1239
+
1240
+ # def foo(*bar); end
1241
+ # ^^^^
1242
+ #
1243
+ # def foo(*); end
1244
+ # ^
1245
+ def visit_rest_parameter_node(node)
1246
+ :"*#{node.name}"
1247
+ end
1248
+
1249
+ # retry
1250
+ # ^^^^^
1251
+ def visit_retry_node(node)
1252
+ s(node, :retry)
1253
+ end
1254
+
1255
+ # return
1256
+ # ^^^^^^
1257
+ #
1258
+ # return 1
1259
+ # ^^^^^^^^
1260
+ def visit_return_node(node)
1261
+ if node.arguments.nil?
1262
+ s(node, :return)
1263
+ elsif node.arguments.arguments.length == 1
1264
+ argument = node.arguments.arguments.first
1265
+ s(node, :return, argument.is_a?(SplatNode) ? s(node, :svalue, visit(argument)) : visit(argument))
1266
+ else
1267
+ s(node, :return, s(node, :array).concat(visit_all(node.arguments.arguments)))
1268
+ end
1269
+ end
1270
+
1271
+ # self
1272
+ # ^^^^
1273
+ def visit_self_node(node)
1274
+ s(node, :self)
1275
+ end
1276
+
1277
+ # class << self; end
1278
+ # ^^^^^^^^^^^^^^^^^^
1279
+ def visit_singleton_class_node(node)
1280
+ s(node, :sclass, visit(node.expression)).tap do |sexp|
1281
+ sexp << node.body.accept(copy_compiler(in_def: false)) unless node.body.nil?
1282
+ end
1283
+ end
1284
+
1285
+ # __ENCODING__
1286
+ # ^^^^^^^^^^^^
1287
+ def visit_source_encoding_node(node)
1288
+ # TODO
1289
+ s(node, :colon2, s(node, :const, :Encoding), :UTF_8)
1290
+ end
1291
+
1292
+ # __FILE__
1293
+ # ^^^^^^^^
1294
+ def visit_source_file_node(node)
1295
+ s(node, :str, file)
1296
+ end
1297
+
1298
+ # __LINE__
1299
+ # ^^^^^^^^
1300
+ def visit_source_line_node(node)
1301
+ s(node, :lit, node.location.start_line)
1302
+ end
1303
+
1304
+ # foo(*bar)
1305
+ # ^^^^
1306
+ #
1307
+ # def foo((bar, *baz)); end
1308
+ # ^^^^
1309
+ #
1310
+ # def foo(*); bar(*); end
1311
+ # ^
1312
+ def visit_splat_node(node)
1313
+ if node.expression.nil?
1314
+ s(node, :splat)
1315
+ else
1316
+ s(node, :splat, visit(node.expression))
1317
+ end
1318
+ end
1319
+
1320
+ # A list of statements.
1321
+ def visit_statements_node(node)
1322
+ first, *rest = node.body
1323
+
1324
+ if rest.empty?
1325
+ visit(first)
1326
+ else
1327
+ s(node, :block).concat(visit_all(node.body))
1328
+ end
1329
+ end
1330
+
1331
+ # "foo"
1332
+ # ^^^^^
1333
+ def visit_string_node(node)
1334
+ s(node, :str, node.unescaped)
1335
+ end
1336
+
1337
+ # super(foo)
1338
+ # ^^^^^^^^^^
1339
+ def visit_super_node(node)
1340
+ arguments = node.arguments&.arguments || []
1341
+ block = node.block
1342
+
1343
+ if block.is_a?(BlockArgumentNode)
1344
+ arguments << block
1345
+ block = nil
1346
+ end
1347
+
1348
+ visit_block(node, s(node, :super).concat(visit_all(arguments)), block)
1349
+ end
1350
+
1351
+ # :foo
1352
+ # ^^^^
1353
+ def visit_symbol_node(node)
1354
+ node.value == "!@" ? s(node, :lit, :"!@") : s(node, :lit, node.unescaped.to_sym)
1355
+ end
1356
+
1357
+ # true
1358
+ # ^^^^
1359
+ def visit_true_node(node)
1360
+ s(node, :true)
1361
+ end
1362
+
1363
+ # undef foo
1364
+ # ^^^^^^^^^
1365
+ def visit_undef_node(node)
1366
+ names = node.names.map { |name| s(node, :undef, visit(name)) }
1367
+ names.length == 1 ? names.first : s(node, :block).concat(names)
1368
+ end
1369
+
1370
+ # unless foo; bar end
1371
+ # ^^^^^^^^^^^^^^^^^^^
1372
+ #
1373
+ # bar unless foo
1374
+ # ^^^^^^^^^^^^^^
1375
+ def visit_unless_node(node)
1376
+ s(node, :if, visit(node.predicate), visit(node.consequent), visit(node.statements))
1377
+ end
1378
+
1379
+ # until foo; bar end
1380
+ # ^^^^^^^^^^^^^^^^^
1381
+ #
1382
+ # bar until foo
1383
+ # ^^^^^^^^^^^^^
1384
+ def visit_until_node(node)
1385
+ s(node, :until, visit(node.predicate), visit(node.statements), !node.begin_modifier?)
1386
+ end
1387
+
1388
+ # case foo; when bar; end
1389
+ # ^^^^^^^^^^^^^
1390
+ def visit_when_node(node)
1391
+ s(node, :when, s(node, :array).concat(visit_all(node.conditions))).concat(node.statements.nil? ? [nil] : visit_all(node.statements.body))
1392
+ end
1393
+
1394
+ # while foo; bar end
1395
+ # ^^^^^^^^^^^^^^^^^^
1396
+ #
1397
+ # bar while foo
1398
+ # ^^^^^^^^^^^^^
1399
+ def visit_while_node(node)
1400
+ s(node, :while, visit(node.predicate), visit(node.statements), !node.begin_modifier?)
1401
+ end
1402
+
1403
+ # `foo`
1404
+ # ^^^^^
1405
+ def visit_x_string_node(node)
1406
+ result = s(node, :xstr, node.unescaped)
1407
+
1408
+ if node.heredoc?
1409
+ result.line = node.content_loc.start_line
1410
+ result.max_line = node.content_loc.end_line
1411
+ end
1412
+
1413
+ result
1414
+ end
1415
+
1416
+ # yield
1417
+ # ^^^^^
1418
+ #
1419
+ # yield 1
1420
+ # ^^^^^^^
1421
+ def visit_yield_node(node)
1422
+ s(node, :yield).concat(visit_all(node.arguments&.arguments || []))
1423
+ end
1424
+
1425
+ private
1426
+
1427
+ # Create a new compiler with the given options.
1428
+ def copy_compiler(in_def: self.in_def, in_pattern: self.in_pattern)
1429
+ Compiler.new(file, in_def: in_def, in_pattern: in_pattern)
1430
+ end
1431
+
1432
+ # Create a new Sexp object from the given prism node and arguments.
1433
+ def s(node, *arguments)
1434
+ result = Sexp.new(*arguments)
1435
+ result.file = file
1436
+ result.line = node.location.start_line
1437
+ result.max_line = node.location.end_line
1438
+ result
1439
+ end
1440
+
1441
+ # Visit a block node, which will modify the AST by wrapping the given
1442
+ # visited node in an iter node.
1443
+ def visit_block(node, sexp, block)
1444
+ if block.nil?
1445
+ sexp
1446
+ else
1447
+ parameters =
1448
+ case block.parameters
1449
+ when nil, NumberedParametersNode
1450
+ 0
1451
+ else
1452
+ visit(block.parameters)
1453
+ end
1454
+
1455
+ if block.body.nil?
1456
+ s(node, :iter, sexp, parameters)
1457
+ else
1458
+ s(node, :iter, sexp, parameters, visit(block.body))
1459
+ end
1460
+ end
1461
+ end
1462
+
1463
+ # Pattern constants get wrapped in another layer of :const.
1464
+ def visit_pattern_constant(node)
1465
+ case node
1466
+ when nil
1467
+ # nothing
1468
+ when ConstantReadNode
1469
+ visit(node)
1470
+ else
1471
+ s(node, :const, visit(node))
1472
+ end
1473
+ end
1474
+
1475
+ # Visit the value of a write, which will be on the right-hand side of
1476
+ # a write operator. Because implicit arrays can have splats, those could
1477
+ # potentially be wrapped in an svalue node.
1478
+ def visit_write_value(node)
1479
+ if node.is_a?(ArrayNode) && node.opening_loc.nil?
1480
+ if node.elements.length == 1 && node.elements.first.is_a?(SplatNode)
1481
+ s(node, :svalue, visit(node.elements.first))
1482
+ else
1483
+ s(node, :svalue, visit(node))
1484
+ end
1485
+ else
1486
+ visit(node)
1487
+ end
1488
+ end
1489
+ end
1490
+
1491
+ private_constant :Compiler
1492
+
1493
+ class << self
1494
+ # Parse the given source and translate it into the seattlerb/ruby_parser
1495
+ # gem's Sexp format.
1496
+ def parse(source, filepath = "(string)")
1497
+ translate(Prism.parse(source), filepath)
1498
+ end
1499
+
1500
+ # Parse the given file and translate it into the seattlerb/ruby_parser
1501
+ # gem's Sexp format.
1502
+ def parse_file(filepath)
1503
+ translate(Prism.parse_file(filepath), filepath)
1504
+ end
1505
+
1506
+ private
1507
+
1508
+ # Translate the given parse result and filepath into the
1509
+ # seattlerb/ruby_parser gem's Sexp format.
1510
+ def translate(result, filepath)
1511
+ if result.failure?
1512
+ error = result.errors.first
1513
+ raise ::RubyParser::SyntaxError, "#{filepath}:#{error.location.start_line} :: #{error.message}"
1514
+ end
1515
+
1516
+ result.value.accept(Compiler.new(filepath))
1517
+ end
1518
+ end
1519
+ end
1520
+ end
1521
+ end