ed-precompiled_prism 1.5.2

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