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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +401 -0
  3. data/CODE_OF_CONDUCT.md +76 -0
  4. data/CONTRIBUTING.md +62 -0
  5. data/LICENSE.md +7 -0
  6. data/Makefile +101 -0
  7. data/README.md +98 -0
  8. data/config.yml +2902 -0
  9. data/docs/build_system.md +91 -0
  10. data/docs/configuration.md +64 -0
  11. data/docs/cruby_compilation.md +27 -0
  12. data/docs/design.md +53 -0
  13. data/docs/encoding.md +121 -0
  14. data/docs/fuzzing.md +88 -0
  15. data/docs/heredocs.md +36 -0
  16. data/docs/javascript.md +118 -0
  17. data/docs/local_variable_depth.md +229 -0
  18. data/docs/mapping.md +117 -0
  19. data/docs/parser_translation.md +34 -0
  20. data/docs/parsing_rules.md +19 -0
  21. data/docs/releasing.md +98 -0
  22. data/docs/ripper.md +36 -0
  23. data/docs/ruby_api.md +43 -0
  24. data/docs/ruby_parser_translation.md +19 -0
  25. data/docs/serialization.md +209 -0
  26. data/docs/testing.md +55 -0
  27. data/ext/prism/api_node.c +5098 -0
  28. data/ext/prism/api_pack.c +267 -0
  29. data/ext/prism/extconf.rb +110 -0
  30. data/ext/prism/extension.c +1155 -0
  31. data/ext/prism/extension.h +18 -0
  32. data/include/prism/ast.h +5807 -0
  33. data/include/prism/defines.h +102 -0
  34. data/include/prism/diagnostic.h +339 -0
  35. data/include/prism/encoding.h +265 -0
  36. data/include/prism/node.h +57 -0
  37. data/include/prism/options.h +230 -0
  38. data/include/prism/pack.h +152 -0
  39. data/include/prism/parser.h +732 -0
  40. data/include/prism/prettyprint.h +26 -0
  41. data/include/prism/regexp.h +33 -0
  42. data/include/prism/util/pm_buffer.h +155 -0
  43. data/include/prism/util/pm_char.h +205 -0
  44. data/include/prism/util/pm_constant_pool.h +209 -0
  45. data/include/prism/util/pm_list.h +97 -0
  46. data/include/prism/util/pm_memchr.h +29 -0
  47. data/include/prism/util/pm_newline_list.h +93 -0
  48. data/include/prism/util/pm_state_stack.h +42 -0
  49. data/include/prism/util/pm_string.h +150 -0
  50. data/include/prism/util/pm_string_list.h +44 -0
  51. data/include/prism/util/pm_strncasecmp.h +32 -0
  52. data/include/prism/util/pm_strpbrk.h +46 -0
  53. data/include/prism/version.h +29 -0
  54. data/include/prism.h +289 -0
  55. data/jruby-prism.jar +0 -0
  56. data/lib/prism/compiler.rb +486 -0
  57. data/lib/prism/debug.rb +206 -0
  58. data/lib/prism/desugar_compiler.rb +207 -0
  59. data/lib/prism/dispatcher.rb +2150 -0
  60. data/lib/prism/dot_visitor.rb +4634 -0
  61. data/lib/prism/dsl.rb +785 -0
  62. data/lib/prism/ffi.rb +346 -0
  63. data/lib/prism/lex_compat.rb +908 -0
  64. data/lib/prism/mutation_compiler.rb +753 -0
  65. data/lib/prism/node.rb +17864 -0
  66. data/lib/prism/node_ext.rb +212 -0
  67. data/lib/prism/node_inspector.rb +68 -0
  68. data/lib/prism/pack.rb +224 -0
  69. data/lib/prism/parse_result/comments.rb +177 -0
  70. data/lib/prism/parse_result/newlines.rb +64 -0
  71. data/lib/prism/parse_result.rb +498 -0
  72. data/lib/prism/pattern.rb +250 -0
  73. data/lib/prism/serialize.rb +1354 -0
  74. data/lib/prism/translation/parser/compiler.rb +1838 -0
  75. data/lib/prism/translation/parser/lexer.rb +335 -0
  76. data/lib/prism/translation/parser/rubocop.rb +37 -0
  77. data/lib/prism/translation/parser.rb +178 -0
  78. data/lib/prism/translation/ripper.rb +577 -0
  79. data/lib/prism/translation/ruby_parser.rb +1521 -0
  80. data/lib/prism/translation.rb +11 -0
  81. data/lib/prism/version.rb +3 -0
  82. data/lib/prism/visitor.rb +495 -0
  83. data/lib/prism.rb +99 -0
  84. data/prism.gemspec +135 -0
  85. data/rbi/prism.rbi +7767 -0
  86. data/rbi/prism_static.rbi +207 -0
  87. data/sig/prism.rbs +4773 -0
  88. data/sig/prism_static.rbs +201 -0
  89. data/src/diagnostic.c +400 -0
  90. data/src/encoding.c +5132 -0
  91. data/src/node.c +2786 -0
  92. data/src/options.c +213 -0
  93. data/src/pack.c +493 -0
  94. data/src/prettyprint.c +8881 -0
  95. data/src/prism.c +18406 -0
  96. data/src/regexp.c +638 -0
  97. data/src/serialize.c +1554 -0
  98. data/src/token_type.c +700 -0
  99. data/src/util/pm_buffer.c +190 -0
  100. data/src/util/pm_char.c +318 -0
  101. data/src/util/pm_constant_pool.c +322 -0
  102. data/src/util/pm_list.c +49 -0
  103. data/src/util/pm_memchr.c +35 -0
  104. data/src/util/pm_newline_list.c +84 -0
  105. data/src/util/pm_state_stack.c +25 -0
  106. data/src/util/pm_string.c +203 -0
  107. data/src/util/pm_string_list.c +28 -0
  108. data/src/util/pm_strncasecmp.c +24 -0
  109. data/src/util/pm_strpbrk.c +180 -0
  110. metadata +156 -0
@@ -0,0 +1,577 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ripper"
4
+
5
+ module Prism
6
+ module Translation
7
+ # Note: This integration is not finished, and therefore still has many
8
+ # inconsistencies with Ripper. If you'd like to help out, pull requests would
9
+ # be greatly appreciated!
10
+ #
11
+ # This class is meant to provide a compatibility layer between prism and
12
+ # Ripper. It functions by parsing the entire tree first and then walking it
13
+ # and executing each of the Ripper callbacks as it goes.
14
+ #
15
+ # This class is going to necessarily be slower than the native Ripper API. It
16
+ # is meant as a stopgap until developers migrate to using prism. It is also
17
+ # meant as a test harness for the prism parser.
18
+ #
19
+ # To use this class, you treat `Prism::Translation::Ripper` effectively as you would
20
+ # treat the `Ripper` class.
21
+ class Ripper < Compiler
22
+ # This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
23
+ # returns the arrays of [type, *children].
24
+ class SexpBuilder < Ripper
25
+ private
26
+
27
+ ::Ripper::PARSER_EVENTS.each do |event|
28
+ define_method(:"on_#{event}") do |*args|
29
+ [event, *args]
30
+ end
31
+ end
32
+
33
+ ::Ripper::SCANNER_EVENTS.each do |event|
34
+ define_method(:"on_#{event}") do |value|
35
+ [:"@#{event}", value, [lineno, column]]
36
+ end
37
+ end
38
+ end
39
+
40
+ # This class mirrors the ::Ripper::SexpBuilderPP subclass of ::Ripper that
41
+ # returns the same values as ::Ripper::SexpBuilder except with a couple of
42
+ # niceties that flatten linked lists into arrays.
43
+ class SexpBuilderPP < SexpBuilder
44
+ private
45
+
46
+ def _dispatch_event_new # :nodoc:
47
+ []
48
+ end
49
+
50
+ def _dispatch_event_push(list, item) # :nodoc:
51
+ list << item
52
+ list
53
+ end
54
+
55
+ ::Ripper::PARSER_EVENT_TABLE.each do |event, arity|
56
+ case event
57
+ when /_new\z/
58
+ alias_method :"on_#{event}", :_dispatch_event_new if arity == 0
59
+ when /_add\z/
60
+ alias_method :"on_#{event}", :_dispatch_event_push
61
+ end
62
+ end
63
+ end
64
+
65
+ # The source that is being parsed.
66
+ attr_reader :source
67
+
68
+ # The current line number of the parser.
69
+ attr_reader :lineno
70
+
71
+ # The current column number of the parser.
72
+ attr_reader :column
73
+
74
+ # Create a new Translation::Ripper object with the given source.
75
+ def initialize(source)
76
+ @source = source
77
+ @result = nil
78
+ @lineno = nil
79
+ @column = nil
80
+ end
81
+
82
+ ############################################################################
83
+ # Public interface
84
+ ############################################################################
85
+
86
+ # True if the parser encountered an error during parsing.
87
+ def error?
88
+ result.failure?
89
+ end
90
+
91
+ # Parse the source and return the result.
92
+ def parse
93
+ result.magic_comments.each do |magic_comment|
94
+ on_magic_comment(magic_comment.key, magic_comment.value)
95
+ end
96
+
97
+ if error?
98
+ result.errors.each do |error|
99
+ on_parse_error(error.message)
100
+ end
101
+
102
+ nil
103
+ else
104
+ result.value.accept(self)
105
+ end
106
+ end
107
+
108
+ ############################################################################
109
+ # Visitor methods
110
+ ############################################################################
111
+
112
+ # Visit an ArrayNode node.
113
+ def visit_array_node(node)
114
+ elements = visit_elements(node.elements) unless node.elements.empty?
115
+ bounds(node.location)
116
+ on_array(elements)
117
+ end
118
+
119
+ # Visit a CallNode node.
120
+ # Ripper distinguishes between many different method-call
121
+ # nodes -- unary and binary operators, "command" calls with
122
+ # no parentheses, and call/fcall/vcall.
123
+ def visit_call_node(node)
124
+ return visit_aref_node(node) if node.name == :[]
125
+ return visit_aref_field_node(node) if node.name == :[]=
126
+
127
+ if node.variable_call?
128
+ raise NotImplementedError unless node.receiver.nil?
129
+
130
+ bounds(node.message_loc)
131
+ return on_vcall(on_ident(node.message))
132
+ end
133
+
134
+ if node.opening_loc.nil?
135
+ return visit_no_paren_call(node)
136
+ end
137
+
138
+ # A non-operator method call with parentheses
139
+
140
+ args = if node.arguments.nil?
141
+ on_arg_paren(nil)
142
+ else
143
+ on_arg_paren(on_args_add_block(visit_elements(node.arguments.arguments), false))
144
+ end
145
+
146
+ bounds(node.message_loc)
147
+ ident_val = on_ident(node.message)
148
+
149
+ bounds(node.location)
150
+ args_call_val = on_method_add_arg(on_fcall(ident_val), args)
151
+ if node.block
152
+ block_val = visit(node.block)
153
+
154
+ return on_method_add_block(args_call_val, block_val)
155
+ else
156
+ return args_call_val
157
+ end
158
+ end
159
+
160
+ # Visit a LocalVariableWriteNode.
161
+ def visit_local_variable_write_node(node)
162
+ bounds(node.name_loc)
163
+ ident_val = on_ident(node.name.to_s)
164
+ on_assign(on_var_field(ident_val), visit(node.value))
165
+ end
166
+
167
+ # Visit a LocalVariableAndWriteNode.
168
+ def visit_local_variable_and_write_node(node)
169
+ visit_binary_op_assign(node)
170
+ end
171
+
172
+ # Visit a LocalVariableOrWriteNode.
173
+ def visit_local_variable_or_write_node(node)
174
+ visit_binary_op_assign(node)
175
+ end
176
+
177
+ # Visit nodes for +=, *=, -=, etc., called LocalVariableOperatorWriteNodes.
178
+ def visit_local_variable_operator_write_node(node)
179
+ visit_binary_op_assign(node, operator: "#{node.operator}=")
180
+ end
181
+
182
+ # Visit a LocalVariableReadNode.
183
+ def visit_local_variable_read_node(node)
184
+ bounds(node.location)
185
+ ident_val = on_ident(node.slice)
186
+
187
+ on_var_ref(ident_val)
188
+ end
189
+
190
+ # Visit a BlockNode.
191
+ def visit_block_node(node)
192
+ params_val = node.parameters.nil? ? nil : visit(node.parameters)
193
+
194
+ body_val = node.body.nil? ? on_stmts_add(on_stmts_new, on_void_stmt) : visit(node.body)
195
+
196
+ on_brace_block(params_val, body_val)
197
+ end
198
+
199
+ # Visit a BlockParametersNode.
200
+ def visit_block_parameters_node(node)
201
+ on_block_var(visit(node.parameters), no_block_value)
202
+ end
203
+
204
+ # Visit a ParametersNode.
205
+ # This will require expanding as we support more kinds of parameters.
206
+ def visit_parameters_node(node)
207
+ #on_params(required, optional, nil, nil, nil, nil, nil)
208
+ on_params(visit_all(node.requireds), nil, nil, nil, nil, nil, nil)
209
+ end
210
+
211
+ # Visit a RequiredParameterNode.
212
+ def visit_required_parameter_node(node)
213
+ bounds(node.location)
214
+ on_ident(node.name.to_s)
215
+ end
216
+
217
+ # Visit a BreakNode.
218
+ def visit_break_node(node)
219
+ return on_break(on_args_new) if node.arguments.nil?
220
+
221
+ args_val = visit_elements(node.arguments.arguments)
222
+ on_break(on_args_add_block(args_val, false))
223
+ end
224
+
225
+ # Visit an AndNode.
226
+ def visit_and_node(node)
227
+ visit_binary_operator(node)
228
+ end
229
+
230
+ # Visit an OrNode.
231
+ def visit_or_node(node)
232
+ visit_binary_operator(node)
233
+ end
234
+
235
+ # Visit a TrueNode.
236
+ def visit_true_node(node)
237
+ bounds(node.location)
238
+ on_var_ref(on_kw("true"))
239
+ end
240
+
241
+ # Visit a FalseNode.
242
+ def visit_false_node(node)
243
+ bounds(node.location)
244
+ on_var_ref(on_kw("false"))
245
+ end
246
+
247
+ # Visit a FloatNode node.
248
+ def visit_float_node(node)
249
+ visit_number(node) { |text| on_float(text) }
250
+ end
251
+
252
+ # Visit a ImaginaryNode node.
253
+ def visit_imaginary_node(node)
254
+ visit_number(node) { |text| on_imaginary(text) }
255
+ end
256
+
257
+ # Visit an IntegerNode node.
258
+ def visit_integer_node(node)
259
+ visit_number(node) { |text| on_int(text) }
260
+ end
261
+
262
+ # Visit a ParenthesesNode node.
263
+ def visit_parentheses_node(node)
264
+ body =
265
+ if node.body.nil?
266
+ on_stmts_add(on_stmts_new, on_void_stmt)
267
+ else
268
+ visit(node.body)
269
+ end
270
+
271
+ bounds(node.location)
272
+ on_paren(body)
273
+ end
274
+
275
+ # Visit a BeginNode node.
276
+ # This is not at all bulletproof against different structures of begin/rescue/else/ensure/end.
277
+ def visit_begin_node(node)
278
+ rescue_val = node.rescue_clause ? on_rescue(nil, nil, visit(node.rescue_clause), nil) : nil
279
+ ensure_val = node.ensure_clause ? on_ensure(visit(node.ensure_clause.statements)) : nil
280
+ on_begin(on_bodystmt(visit(node.statements), rescue_val, nil, ensure_val))
281
+ end
282
+
283
+ # Visit a RescueNode node.
284
+ def visit_rescue_node(node)
285
+ visit(node.statements)
286
+ end
287
+
288
+ # Visit a ProgramNode node.
289
+ def visit_program_node(node)
290
+ statements = visit(node.statements)
291
+ bounds(node.location)
292
+ on_program(statements)
293
+ end
294
+
295
+ # Visit a RangeNode node.
296
+ def visit_range_node(node)
297
+ left = visit(node.left)
298
+ right = visit(node.right)
299
+
300
+ bounds(node.location)
301
+ if node.exclude_end?
302
+ on_dot3(left, right)
303
+ else
304
+ on_dot2(left, right)
305
+ end
306
+ end
307
+
308
+ # Visit a RationalNode node.
309
+ def visit_rational_node(node)
310
+ visit_number(node) { |text| on_rational(text) }
311
+ end
312
+
313
+ # Visit a StringNode node.
314
+ def visit_string_node(node)
315
+ bounds(node.content_loc)
316
+ tstring_val = on_tstring_content(node.unescaped.to_s)
317
+ on_string_literal(on_string_add(on_string_content, tstring_val))
318
+ end
319
+
320
+ # Visit an XStringNode node.
321
+ def visit_x_string_node(node)
322
+ bounds(node.content_loc)
323
+ tstring_val = on_tstring_content(node.unescaped.to_s)
324
+ on_xstring_literal(on_xstring_add(on_xstring_new, tstring_val))
325
+ end
326
+
327
+ # Visit an InterpolatedStringNode node.
328
+ def visit_interpolated_string_node(node)
329
+ parts = node.parts.map do |part|
330
+ case part
331
+ when StringNode
332
+ bounds(part.content_loc)
333
+ on_tstring_content(part.content)
334
+ when EmbeddedStatementsNode
335
+ on_string_embexpr(visit(part))
336
+ else
337
+ raise NotImplementedError, "Unexpected node type in InterpolatedStringNode"
338
+ end
339
+ end
340
+
341
+ string_list = parts.inject(on_string_content) do |items, item|
342
+ on_string_add(items, item)
343
+ end
344
+
345
+ on_string_literal(string_list)
346
+ end
347
+
348
+ # Visit an EmbeddedStatementsNode node.
349
+ def visit_embedded_statements_node(node)
350
+ visit(node.statements)
351
+ end
352
+
353
+ # Visit a SymbolNode node.
354
+ def visit_symbol_node(node)
355
+ if (opening = node.opening) && (['"', "'"].include?(opening[-1]) || opening.start_with?("%s"))
356
+ bounds(node.value_loc)
357
+ tstring_val = on_tstring_content(node.value.to_s)
358
+ return on_dyna_symbol(on_string_add(on_string_content, tstring_val))
359
+ end
360
+
361
+ bounds(node.value_loc)
362
+ ident_val = on_ident(node.value.to_s)
363
+ on_symbol_literal(on_symbol(ident_val))
364
+ end
365
+
366
+ # Visit a StatementsNode node.
367
+ def visit_statements_node(node)
368
+ bounds(node.location)
369
+ node.body.inject(on_stmts_new) do |stmts, stmt|
370
+ on_stmts_add(stmts, visit(stmt))
371
+ end
372
+ end
373
+
374
+ ############################################################################
375
+ # Entrypoints for subclasses
376
+ ############################################################################
377
+
378
+ # This is a convenience method that runs the SexpBuilder subclass parser.
379
+ def self.sexp_raw(source)
380
+ SexpBuilder.new(source).parse
381
+ end
382
+
383
+ # This is a convenience method that runs the SexpBuilderPP subclass parser.
384
+ def self.sexp(source)
385
+ SexpBuilderPP.new(source).parse
386
+ end
387
+
388
+ private
389
+
390
+ # Generate Ripper events for a CallNode with no opening_loc
391
+ def visit_no_paren_call(node)
392
+ # No opening_loc can mean an operator. It can also mean a
393
+ # method call with no parentheses.
394
+ if node.message.match?(/^[[:punct:]]/)
395
+ left = visit(node.receiver)
396
+ if node.arguments&.arguments&.length == 1
397
+ right = visit(node.arguments.arguments.first)
398
+
399
+ return on_binary(left, node.name, right)
400
+ elsif !node.arguments || node.arguments.empty?
401
+ return on_unary(node.name, left)
402
+ else
403
+ raise NotImplementedError, "More than two arguments for operator"
404
+ end
405
+ elsif node.call_operator_loc.nil?
406
+ # In Ripper a method call like "puts myvar" with no parentheses is a "command".
407
+ bounds(node.message_loc)
408
+ ident_val = on_ident(node.message)
409
+
410
+ # Unless it has a block, and then it's an fcall (e.g. "foo { bar }")
411
+ if node.block
412
+ block_val = visit(node.block)
413
+ # In these calls, even if node.arguments is nil, we still get an :args_new call.
414
+ args = if node.arguments.nil?
415
+ on_args_new
416
+ else
417
+ on_args_add_block(visit_elements(node.arguments.arguments))
418
+ end
419
+ method_args_val = on_method_add_arg(on_fcall(ident_val), args)
420
+ return on_method_add_block(method_args_val, block_val)
421
+ else
422
+ if node.arguments.nil?
423
+ return on_command(ident_val, nil)
424
+ else
425
+ args = on_args_add_block(visit_elements(node.arguments.arguments), false)
426
+ return on_command(ident_val, args)
427
+ end
428
+ end
429
+ else
430
+ operator = node.call_operator_loc.slice
431
+ if operator == "." || operator == "&."
432
+ left_val = visit(node.receiver)
433
+
434
+ bounds(node.call_operator_loc)
435
+ operator_val = operator == "." ? on_period(node.call_operator) : on_op(node.call_operator)
436
+
437
+ bounds(node.message_loc)
438
+ right_val = on_ident(node.message)
439
+
440
+ call_val = on_call(left_val, operator_val, right_val)
441
+
442
+ if node.block
443
+ block_val = visit(node.block)
444
+ return on_method_add_block(call_val, block_val)
445
+ else
446
+ return call_val
447
+ end
448
+ else
449
+ raise NotImplementedError, "operator other than . or &. for call: #{operator.inspect}"
450
+ end
451
+ end
452
+ end
453
+
454
+ # Visit a list of elements, like the elements of an array or arguments.
455
+ def visit_elements(elements)
456
+ bounds(elements.first.location)
457
+ elements.inject(on_args_new) do |args, element|
458
+ on_args_add(args, visit(element))
459
+ end
460
+ end
461
+
462
+ # Visit an operation-and-assign node, such as +=.
463
+ def visit_binary_op_assign(node, operator: node.operator)
464
+ bounds(node.name_loc)
465
+ ident_val = on_ident(node.name.to_s)
466
+
467
+ bounds(node.operator_loc)
468
+ op_val = on_op(operator)
469
+
470
+ on_opassign(on_var_field(ident_val), op_val, visit(node.value))
471
+ end
472
+
473
+ # In Prism this is a CallNode with :[] as the operator.
474
+ # In Ripper it's an :aref.
475
+ def visit_aref_node(node)
476
+ first_arg_val = visit(node.arguments.arguments[0])
477
+ args_val = on_args_add_block(on_args_add(on_args_new, first_arg_val), false)
478
+ on_aref(visit(node.receiver), args_val)
479
+ end
480
+
481
+ # In Prism this is a CallNode with :[]= as the operator.
482
+ # In Ripper it's an :aref_field.
483
+ def visit_aref_field_node(node)
484
+ first_arg_val = visit(node.arguments.arguments[0])
485
+ args_val = on_args_add_block(on_args_add(on_args_new, first_arg_val), false)
486
+ assign_val = visit(node.arguments.arguments[1])
487
+ on_assign(on_aref_field(visit(node.receiver), args_val), assign_val)
488
+ end
489
+
490
+ # Visit a node that represents a number. We need to explicitly handle the
491
+ # unary - operator.
492
+ def visit_number(node)
493
+ slice = node.slice
494
+ location = node.location
495
+
496
+ if slice[0] == "-"
497
+ bounds_values(location.start_line, location.start_column + 1)
498
+ value = yield slice[1..-1]
499
+
500
+ bounds(node.location)
501
+ on_unary(visit_unary_operator(:-@), value)
502
+ else
503
+ bounds(location)
504
+ yield slice
505
+ end
506
+ end
507
+
508
+ if RUBY_ENGINE == "jruby" && Gem::Version.new(JRUBY_VERSION) < Gem::Version.new("9.4.6.0")
509
+ # JRuby before 9.4.6.0 uses :- for unary minus instead of :-@
510
+ def visit_unary_operator(value)
511
+ value == :-@ ? :- : value
512
+ end
513
+ else
514
+ # For most Rubies and JRuby after 9.4.6.0 this is a no-op.
515
+ def visit_unary_operator(value)
516
+ value
517
+ end
518
+ end
519
+
520
+ if RUBY_ENGINE == "jruby"
521
+ # For JRuby, "no block" in an on_block_var is nil
522
+ def no_block_value
523
+ nil
524
+ end
525
+ else
526
+ # For CRuby et al, "no block" in an on_block_var is false
527
+ def no_block_value
528
+ false
529
+ end
530
+ end
531
+
532
+ # Visit a binary operator node like an AndNode or OrNode
533
+ def visit_binary_operator(node)
534
+ left_val = visit(node.left)
535
+ right_val = visit(node.right)
536
+ on_binary(left_val, node.operator.to_sym, right_val)
537
+ end
538
+
539
+ # This method is responsible for updating lineno and column information
540
+ # to reflect the current node.
541
+ #
542
+ # This method could be drastically improved with some caching on the start
543
+ # of every line, but for now it's good enough.
544
+ def bounds(location)
545
+ @lineno = location.start_line
546
+ @column = location.start_column
547
+ end
548
+
549
+ # If we need to do something unusual, we can directly update the line number
550
+ # and column to reflect the current node.
551
+ def bounds_values(lineno, column)
552
+ @lineno = lineno
553
+ @column = column
554
+ end
555
+
556
+ # Lazily initialize the parse result.
557
+ def result
558
+ @result ||= Prism.parse(source)
559
+ end
560
+
561
+ def _dispatch0; end # :nodoc:
562
+ def _dispatch1(_); end # :nodoc:
563
+ def _dispatch2(_, _); end # :nodoc:
564
+ def _dispatch3(_, _, _); end # :nodoc:
565
+ def _dispatch4(_, _, _, _); end # :nodoc:
566
+ def _dispatch5(_, _, _, _, _); end # :nodoc:
567
+ def _dispatch7(_, _, _, _, _, _, _); end # :nodoc:
568
+
569
+ alias_method :on_parse_error, :_dispatch1
570
+ alias_method :on_magic_comment, :_dispatch2
571
+
572
+ (::Ripper::SCANNER_EVENT_TABLE.merge(::Ripper::PARSER_EVENT_TABLE)).each do |event, arity|
573
+ alias_method :"on_#{event}", :"_dispatch#{arity}"
574
+ end
575
+ end
576
+ end
577
+ end