prism 0.17.1 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +60 -1
- data/Makefile +5 -5
- data/README.md +4 -3
- data/config.yml +214 -68
- data/docs/build_system.md +6 -6
- data/docs/building.md +10 -3
- data/docs/configuration.md +11 -9
- data/docs/encoding.md +92 -88
- data/docs/heredocs.md +1 -1
- data/docs/javascript.md +29 -1
- data/docs/local_variable_depth.md +229 -0
- data/docs/ruby_api.md +16 -0
- data/docs/serialization.md +18 -13
- data/ext/prism/api_node.c +411 -240
- data/ext/prism/extconf.rb +97 -127
- data/ext/prism/extension.c +97 -33
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +377 -159
- data/include/prism/defines.h +17 -0
- data/include/prism/diagnostic.h +38 -6
- data/include/prism/{enc/pm_encoding.h → encoding.h} +126 -64
- data/include/prism/options.h +2 -2
- data/include/prism/parser.h +62 -36
- data/include/prism/regexp.h +2 -2
- data/include/prism/util/pm_buffer.h +9 -1
- data/include/prism/util/pm_memchr.h +2 -2
- data/include/prism/util/pm_strpbrk.h +3 -3
- data/include/prism/version.h +3 -3
- data/include/prism.h +13 -15
- data/lib/prism/compiler.rb +15 -3
- data/lib/prism/debug.rb +13 -4
- data/lib/prism/desugar_compiler.rb +4 -3
- data/lib/prism/dispatcher.rb +70 -14
- data/lib/prism/dot_visitor.rb +4612 -0
- data/lib/prism/dsl.rb +77 -57
- data/lib/prism/ffi.rb +19 -6
- data/lib/prism/lex_compat.rb +19 -9
- data/lib/prism/mutation_compiler.rb +26 -6
- data/lib/prism/node.rb +1314 -522
- data/lib/prism/node_ext.rb +102 -19
- data/lib/prism/parse_result.rb +58 -27
- data/lib/prism/ripper_compat.rb +49 -34
- data/lib/prism/serialize.rb +251 -227
- data/lib/prism/visitor.rb +15 -3
- data/lib/prism.rb +21 -4
- data/prism.gemspec +7 -9
- data/rbi/prism.rbi +688 -284
- data/rbi/prism_static.rbi +3 -0
- data/sig/prism.rbs +426 -156
- data/sig/prism_static.rbs +1 -0
- data/src/diagnostic.c +280 -216
- data/src/encoding.c +5137 -0
- data/src/node.c +99 -21
- data/src/options.c +21 -2
- data/src/prettyprint.c +1743 -1241
- data/src/prism.c +1774 -831
- data/src/regexp.c +15 -15
- data/src/serialize.c +261 -164
- data/src/util/pm_buffer.c +10 -1
- data/src/util/pm_memchr.c +1 -1
- data/src/util/pm_strpbrk.c +4 -4
- metadata +8 -10
- data/src/enc/pm_big5.c +0 -53
- data/src/enc/pm_euc_jp.c +0 -59
- data/src/enc/pm_gbk.c +0 -62
- data/src/enc/pm_shift_jis.c +0 -57
- data/src/enc/pm_tables.c +0 -743
- data/src/enc/pm_unicode.c +0 -2369
- data/src/enc/pm_windows_31j.c +0 -57
data/lib/prism/node_ext.rb
CHANGED
@@ -14,8 +14,49 @@ module Prism
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
class InterpolatedMatchLastLineNode < Node
|
18
|
+
include RegularExpressionOptions
|
19
|
+
end
|
20
|
+
|
21
|
+
class InterpolatedRegularExpressionNode < Node
|
22
|
+
include RegularExpressionOptions
|
23
|
+
end
|
24
|
+
|
25
|
+
class MatchLastLineNode < Node
|
26
|
+
include RegularExpressionOptions
|
27
|
+
end
|
28
|
+
|
29
|
+
class RegularExpressionNode < Node
|
30
|
+
include RegularExpressionOptions
|
31
|
+
end
|
32
|
+
|
17
33
|
private_constant :RegularExpressionOptions
|
18
34
|
|
35
|
+
module HeredocQuery # :nodoc:
|
36
|
+
# Returns true if this node was represented as a heredoc in the source code.
|
37
|
+
def heredoc?
|
38
|
+
opening&.start_with?("<<")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class InterpolatedStringNode < Node
|
43
|
+
include HeredocQuery
|
44
|
+
end
|
45
|
+
|
46
|
+
class InterpolatedXStringNode < Node
|
47
|
+
include HeredocQuery
|
48
|
+
end
|
49
|
+
|
50
|
+
class StringNode < Node
|
51
|
+
include HeredocQuery
|
52
|
+
end
|
53
|
+
|
54
|
+
class XStringNode < Node
|
55
|
+
include HeredocQuery
|
56
|
+
end
|
57
|
+
|
58
|
+
private_constant :HeredocQuery
|
59
|
+
|
19
60
|
class FloatNode < Node
|
20
61
|
# Returns the value of the node as a Ruby Float.
|
21
62
|
def value
|
@@ -37,18 +78,6 @@ module Prism
|
|
37
78
|
end
|
38
79
|
end
|
39
80
|
|
40
|
-
class InterpolatedMatchLastLineNode < Node
|
41
|
-
include RegularExpressionOptions
|
42
|
-
end
|
43
|
-
|
44
|
-
class InterpolatedRegularExpressionNode < Node
|
45
|
-
include RegularExpressionOptions
|
46
|
-
end
|
47
|
-
|
48
|
-
class MatchLastLineNode < Node
|
49
|
-
include RegularExpressionOptions
|
50
|
-
end
|
51
|
-
|
52
81
|
class RationalNode < Node
|
53
82
|
# Returns the value of the node as a Ruby Rational.
|
54
83
|
def value
|
@@ -56,12 +85,9 @@ module Prism
|
|
56
85
|
end
|
57
86
|
end
|
58
87
|
|
59
|
-
class RegularExpressionNode < Node
|
60
|
-
include RegularExpressionOptions
|
61
|
-
end
|
62
|
-
|
63
88
|
class ConstantReadNode < Node
|
64
|
-
# Returns the list of parts for the full name of this constant.
|
89
|
+
# Returns the list of parts for the full name of this constant.
|
90
|
+
# For example: [:Foo]
|
65
91
|
def full_name_parts
|
66
92
|
[name]
|
67
93
|
end
|
@@ -73,7 +99,16 @@ module Prism
|
|
73
99
|
end
|
74
100
|
|
75
101
|
class ConstantPathNode < Node
|
76
|
-
#
|
102
|
+
# An error class raised when dynamic parts are found while computing a
|
103
|
+
# constant path's full name. For example:
|
104
|
+
# Foo::Bar::Baz -> does not raise because all parts of the constant path are
|
105
|
+
# simple constants
|
106
|
+
# var::Bar::Baz -> raises because the first part of the constant path is a
|
107
|
+
# local variable
|
108
|
+
class DynamicPartsInConstantPathError < StandardError; end
|
109
|
+
|
110
|
+
# Returns the list of parts for the full name of this constant path.
|
111
|
+
# For example: [:Foo, :Bar]
|
77
112
|
def full_name_parts
|
78
113
|
parts = [child.name]
|
79
114
|
current = parent
|
@@ -83,6 +118,10 @@ module Prism
|
|
83
118
|
current = current.parent
|
84
119
|
end
|
85
120
|
|
121
|
+
unless current.is_a?(ConstantReadNode)
|
122
|
+
raise DynamicPartsInConstantPathError, "Constant path contains dynamic parts. Cannot compute full name"
|
123
|
+
end
|
124
|
+
|
86
125
|
parts.unshift(current&.name || :"")
|
87
126
|
end
|
88
127
|
|
@@ -93,7 +132,8 @@ module Prism
|
|
93
132
|
end
|
94
133
|
|
95
134
|
class ConstantPathTargetNode < Node
|
96
|
-
# Returns the list of parts for the full name of this constant path.
|
135
|
+
# Returns the list of parts for the full name of this constant path.
|
136
|
+
# For example: [:Foo, :Bar]
|
97
137
|
def full_name_parts
|
98
138
|
(parent&.full_name_parts || [:""]).push(child.name)
|
99
139
|
end
|
@@ -103,4 +143,47 @@ module Prism
|
|
103
143
|
full_name_parts.join("::")
|
104
144
|
end
|
105
145
|
end
|
146
|
+
|
147
|
+
class ParametersNode < Node
|
148
|
+
# Mirrors the Method#parameters method.
|
149
|
+
def signature
|
150
|
+
names = []
|
151
|
+
|
152
|
+
requireds.each do |param|
|
153
|
+
names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
|
154
|
+
end
|
155
|
+
|
156
|
+
optionals.each { |param| names << [:opt, param.name] }
|
157
|
+
names << [:rest, rest.name || :*] if rest
|
158
|
+
|
159
|
+
posts.each do |param|
|
160
|
+
names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
|
161
|
+
end
|
162
|
+
|
163
|
+
# Regardless of the order in which the keywords were defined, the required
|
164
|
+
# keywords always come first followed by the optional keywords.
|
165
|
+
keyopt = []
|
166
|
+
keywords.each do |param|
|
167
|
+
if param.is_a?(OptionalKeywordParameterNode)
|
168
|
+
keyopt << param
|
169
|
+
else
|
170
|
+
names << [:keyreq, param.name]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
keyopt.each { |param| names << [:key, param.name] }
|
175
|
+
|
176
|
+
case keyword_rest
|
177
|
+
when ForwardingParameterNode
|
178
|
+
names.concat([[:rest, :*], [:keyrest, :**], [:block, :&]])
|
179
|
+
when KeywordRestParameterNode
|
180
|
+
names << [:keyrest, keyword_rest.name || :**]
|
181
|
+
when NoKeywordsParameterNode
|
182
|
+
names << [:nokey]
|
183
|
+
end
|
184
|
+
|
185
|
+
names << [:block, block.name || :&] if block
|
186
|
+
names
|
187
|
+
end
|
188
|
+
end
|
106
189
|
end
|
data/lib/prism/parse_result.rb
CHANGED
@@ -25,40 +25,50 @@ module Prism
|
|
25
25
|
|
26
26
|
# Perform a byteslice on the source code using the given byte offset and
|
27
27
|
# byte length.
|
28
|
-
def slice(
|
29
|
-
source.byteslice(
|
28
|
+
def slice(byte_offset, length)
|
29
|
+
source.byteslice(byte_offset, length)
|
30
30
|
end
|
31
31
|
|
32
32
|
# Binary search through the offsets to find the line number for the given
|
33
33
|
# byte offset.
|
34
|
-
def line(
|
35
|
-
start_line + find_line(
|
34
|
+
def line(byte_offset)
|
35
|
+
start_line + find_line(byte_offset)
|
36
36
|
end
|
37
37
|
|
38
38
|
# Return the byte offset of the start of the line corresponding to the given
|
39
39
|
# byte offset.
|
40
|
-
def
|
41
|
-
offsets[find_line(
|
40
|
+
def line_start(byte_offset)
|
41
|
+
offsets[find_line(byte_offset)]
|
42
42
|
end
|
43
43
|
|
44
44
|
# Return the column number for the given byte offset.
|
45
|
-
def column(
|
46
|
-
|
45
|
+
def column(byte_offset)
|
46
|
+
byte_offset - line_start(byte_offset)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Return the character offset for the given byte offset.
|
50
|
+
def character_offset(byte_offset)
|
51
|
+
source.byteslice(0, byte_offset).length
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return the column number in characters for the given byte offset.
|
55
|
+
def character_column(byte_offset)
|
56
|
+
character_offset(byte_offset) - character_offset(line_start(byte_offset))
|
47
57
|
end
|
48
58
|
|
49
59
|
private
|
50
60
|
|
51
61
|
# Binary search through the offsets to find the line number for the given
|
52
62
|
# byte offset.
|
53
|
-
def find_line(
|
63
|
+
def find_line(byte_offset)
|
54
64
|
left = 0
|
55
65
|
right = offsets.length - 1
|
56
66
|
|
57
67
|
while left <= right
|
58
68
|
mid = left + (right - left) / 2
|
59
|
-
return mid if offsets[mid] ==
|
69
|
+
return mid if offsets[mid] == byte_offset
|
60
70
|
|
61
|
-
if offsets[mid] <
|
71
|
+
if offsets[mid] < byte_offset
|
62
72
|
left = mid + 1
|
63
73
|
else
|
64
74
|
right = mid - 1
|
@@ -121,11 +131,23 @@ module Prism
|
|
121
131
|
source.slice(start_offset, length)
|
122
132
|
end
|
123
133
|
|
134
|
+
# The character offset from the beginning of the source where this location
|
135
|
+
# starts.
|
136
|
+
def start_character_offset
|
137
|
+
source.character_offset(start_offset)
|
138
|
+
end
|
139
|
+
|
124
140
|
# The byte offset from the beginning of the source where this location ends.
|
125
141
|
def end_offset
|
126
142
|
start_offset + length
|
127
143
|
end
|
128
144
|
|
145
|
+
# The character offset from the beginning of the source where this location
|
146
|
+
# ends.
|
147
|
+
def end_character_offset
|
148
|
+
source.character_offset(end_offset)
|
149
|
+
end
|
150
|
+
|
129
151
|
# The line number where this location starts.
|
130
152
|
def start_line
|
131
153
|
source.line(start_offset)
|
@@ -133,7 +155,7 @@ module Prism
|
|
133
155
|
|
134
156
|
# The content of the line where this location starts before this location.
|
135
157
|
def start_line_slice
|
136
|
-
offset = source.
|
158
|
+
offset = source.line_start(start_offset)
|
137
159
|
source.slice(offset, start_offset - offset)
|
138
160
|
end
|
139
161
|
|
@@ -148,12 +170,24 @@ module Prism
|
|
148
170
|
source.column(start_offset)
|
149
171
|
end
|
150
172
|
|
173
|
+
# The column number in characters where this location ends from the start of
|
174
|
+
# the line.
|
175
|
+
def start_character_column
|
176
|
+
source.character_column(start_offset)
|
177
|
+
end
|
178
|
+
|
151
179
|
# The column number in bytes where this location ends from the start of the
|
152
180
|
# line.
|
153
181
|
def end_column
|
154
182
|
source.column(end_offset)
|
155
183
|
end
|
156
184
|
|
185
|
+
# The column number in characters where this location ends from the start of
|
186
|
+
# the line.
|
187
|
+
def end_character_column
|
188
|
+
source.character_column(end_offset)
|
189
|
+
end
|
190
|
+
|
157
191
|
# Implement the hash pattern matching interface for Location.
|
158
192
|
def deconstruct_keys(keys)
|
159
193
|
{ start_offset: start_offset, end_offset: end_offset }
|
@@ -204,11 +238,6 @@ module Prism
|
|
204
238
|
def deconstruct_keys(keys)
|
205
239
|
{ location: location }
|
206
240
|
end
|
207
|
-
|
208
|
-
# This can only be true for inline comments.
|
209
|
-
def trailing?
|
210
|
-
false
|
211
|
-
end
|
212
241
|
end
|
213
242
|
|
214
243
|
# InlineComment objects are the most common. They correspond to comments in
|
@@ -229,18 +258,14 @@ module Prism
|
|
229
258
|
# EmbDocComment objects correspond to comments that are surrounded by =begin
|
230
259
|
# and =end.
|
231
260
|
class EmbDocComment < Comment
|
232
|
-
#
|
233
|
-
def
|
234
|
-
|
261
|
+
# This can only be true for inline comments.
|
262
|
+
def trailing?
|
263
|
+
false
|
235
264
|
end
|
236
|
-
end
|
237
265
|
|
238
|
-
# DATAComment objects correspond to comments that are after the __END__
|
239
|
-
# keyword in a source file.
|
240
|
-
class DATAComment < Comment
|
241
266
|
# Returns a string representation of this comment.
|
242
267
|
def inspect
|
243
|
-
"#<Prism::
|
268
|
+
"#<Prism::EmbDocComment @location=#{location.inspect}>"
|
244
269
|
end
|
245
270
|
end
|
246
271
|
|
@@ -344,6 +369,11 @@ module Prism
|
|
344
369
|
# The list of magic comments that were encountered during parsing.
|
345
370
|
attr_reader :magic_comments
|
346
371
|
|
372
|
+
# An optional location that represents the location of the content after the
|
373
|
+
# __END__ marker. This content is loaded into the DATA constant when the
|
374
|
+
# file being parsed is the main file being executed.
|
375
|
+
attr_reader :data_loc
|
376
|
+
|
347
377
|
# The list of errors that were generated during parsing.
|
348
378
|
attr_reader :errors
|
349
379
|
|
@@ -354,10 +384,11 @@ module Prism
|
|
354
384
|
attr_reader :source
|
355
385
|
|
356
386
|
# Create a new parse result object with the given values.
|
357
|
-
def initialize(value, comments, magic_comments, errors, warnings, source)
|
387
|
+
def initialize(value, comments, magic_comments, data_loc, errors, warnings, source)
|
358
388
|
@value = value
|
359
389
|
@comments = comments
|
360
390
|
@magic_comments = magic_comments
|
391
|
+
@data_loc = data_loc
|
361
392
|
@errors = errors
|
362
393
|
@warnings = warnings
|
363
394
|
@source = source
|
@@ -365,7 +396,7 @@ module Prism
|
|
365
396
|
|
366
397
|
# Implement the hash pattern matching interface for ParseResult.
|
367
398
|
def deconstruct_keys(keys)
|
368
|
-
{ value: value, comments: comments, magic_comments: magic_comments, errors: errors, warnings: warnings }
|
399
|
+
{ value: value, comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
|
369
400
|
end
|
370
401
|
|
371
402
|
# Returns true if there were no errors during parsing and false if there
|
data/lib/prism/ripper_compat.rb
CHANGED
@@ -3,6 +3,10 @@
|
|
3
3
|
require "ripper"
|
4
4
|
|
5
5
|
module Prism
|
6
|
+
# Note: This integration is not finished, and therefore still has many
|
7
|
+
# inconsistencies with Ripper. If you'd like to help out, pull requests would
|
8
|
+
# be greatly appreciated!
|
9
|
+
#
|
6
10
|
# This class is meant to provide a compatibility layer between prism and
|
7
11
|
# Ripper. It functions by parsing the entire tree first and then walking it
|
8
12
|
# and executing each of the Ripper callbacks as it goes.
|
@@ -10,7 +14,10 @@ module Prism
|
|
10
14
|
# This class is going to necessarily be slower than the native Ripper API. It
|
11
15
|
# is meant as a stopgap until developers migrate to using prism. It is also
|
12
16
|
# meant as a test harness for the prism parser.
|
13
|
-
|
17
|
+
#
|
18
|
+
# To use this class, you treat `Prism::RipperCompat` effectively as you would
|
19
|
+
# treat the `Ripper` class.
|
20
|
+
class RipperCompat < Visitor
|
14
21
|
# This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
|
15
22
|
# returns the arrays of [type, *children].
|
16
23
|
class SexpBuilder < RipperCompat
|
@@ -77,43 +84,63 @@ module Prism
|
|
77
84
|
|
78
85
|
# True if the parser encountered an error during parsing.
|
79
86
|
def error?
|
80
|
-
result.
|
87
|
+
result.failure?
|
81
88
|
end
|
82
89
|
|
83
90
|
# Parse the source and return the result.
|
84
91
|
def parse
|
85
|
-
result.
|
92
|
+
result.magic_comments.each do |magic_comment|
|
93
|
+
on_magic_comment(magic_comment.key, magic_comment.value)
|
94
|
+
end
|
95
|
+
|
96
|
+
if error?
|
97
|
+
result.errors.each do |error|
|
98
|
+
on_parse_error(error.message)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
result.value.accept(self)
|
102
|
+
end
|
86
103
|
end
|
87
104
|
|
88
105
|
############################################################################
|
89
106
|
# Visitor methods
|
90
107
|
############################################################################
|
91
108
|
|
92
|
-
# This method is responsible for dispatching to the correct visitor method
|
93
|
-
# based on the type of the node.
|
94
|
-
def visit(node)
|
95
|
-
node&.accept(self)
|
96
|
-
end
|
97
|
-
|
98
109
|
# Visit a CallNode node.
|
99
110
|
def visit_call_node(node)
|
100
|
-
if !node.opening_loc && node.arguments
|
101
|
-
bounds(node.receiver.location)
|
111
|
+
if !node.message.match?(/^[[:alpha:]_]/) && node.opening_loc.nil? && node.arguments&.arguments&.length == 1
|
102
112
|
left = visit(node.receiver)
|
103
|
-
|
104
|
-
bounds(node.arguments.arguments.first.location)
|
105
113
|
right = visit(node.arguments.arguments.first)
|
106
114
|
|
107
|
-
|
115
|
+
bounds(node.location)
|
116
|
+
on_binary(left, node.name, right)
|
108
117
|
else
|
109
118
|
raise NotImplementedError
|
110
119
|
end
|
111
120
|
end
|
112
121
|
|
122
|
+
# Visit a FloatNode node.
|
123
|
+
def visit_float_node(node)
|
124
|
+
bounds(node.location)
|
125
|
+
on_float(node.slice)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Visit a ImaginaryNode node.
|
129
|
+
def visit_imaginary_node(node)
|
130
|
+
bounds(node.location)
|
131
|
+
on_imaginary(node.slice)
|
132
|
+
end
|
133
|
+
|
113
134
|
# Visit an IntegerNode node.
|
114
135
|
def visit_integer_node(node)
|
115
136
|
bounds(node.location)
|
116
|
-
on_int(
|
137
|
+
on_int(node.slice)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Visit a RationalNode node.
|
141
|
+
def visit_rational_node(node)
|
142
|
+
bounds(node.location)
|
143
|
+
on_rational(node.slice)
|
117
144
|
end
|
118
145
|
|
119
146
|
# Visit a StatementsNode node.
|
@@ -124,24 +151,11 @@ module Prism
|
|
124
151
|
end
|
125
152
|
end
|
126
153
|
|
127
|
-
# Visit a token found during parsing.
|
128
|
-
def visit_token(node)
|
129
|
-
bounds(node.location)
|
130
|
-
|
131
|
-
case node.type
|
132
|
-
when :MINUS
|
133
|
-
on_op(node.value)
|
134
|
-
when :PLUS
|
135
|
-
on_op(node.value)
|
136
|
-
else
|
137
|
-
raise NotImplementedError, "Unknown token: #{node.type}"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
154
|
# Visit a ProgramNode node.
|
142
155
|
def visit_program_node(node)
|
156
|
+
statements = visit(node.statements)
|
143
157
|
bounds(node.location)
|
144
|
-
on_program(
|
158
|
+
on_program(statements)
|
145
159
|
end
|
146
160
|
|
147
161
|
############################################################################
|
@@ -166,10 +180,8 @@ module Prism
|
|
166
180
|
# This method could be drastically improved with some caching on the start
|
167
181
|
# of every line, but for now it's good enough.
|
168
182
|
def bounds(location)
|
169
|
-
|
170
|
-
|
171
|
-
@lineno = source[0..start_offset].count("\n") + 1
|
172
|
-
@column = start_offset - (source.rindex("\n", start_offset) || 0)
|
183
|
+
@lineno = location.start_line
|
184
|
+
@column = location.start_column
|
173
185
|
end
|
174
186
|
|
175
187
|
# Lazily initialize the parse result.
|
@@ -185,6 +197,9 @@ module Prism
|
|
185
197
|
def _dispatch5(_, _, _, _, _); end # :nodoc:
|
186
198
|
def _dispatch7(_, _, _, _, _, _, _); end # :nodoc:
|
187
199
|
|
200
|
+
alias_method :on_parse_error, :_dispatch1
|
201
|
+
alias_method :on_magic_comment, :_dispatch2
|
202
|
+
|
188
203
|
(Ripper::SCANNER_EVENT_TABLE.merge(Ripper::PARSER_EVENT_TABLE)).each do |event, arity|
|
189
204
|
alias_method :"on_#{event}", :"_dispatch#{arity}"
|
190
205
|
end
|