ed-precompiled_prism 1.5.2-arm64-darwin

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