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