yarp 0.12.0 → 0.13.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -8
- data/CONTRIBUTING.md +2 -2
- data/Makefile +5 -5
- data/README.md +11 -12
- data/config.yml +6 -2
- data/docs/build_system.md +21 -21
- data/docs/building.md +4 -4
- data/docs/configuration.md +25 -21
- data/docs/design.md +2 -2
- data/docs/encoding.md +17 -17
- data/docs/fuzzing.md +4 -4
- data/docs/heredocs.md +3 -3
- data/docs/mapping.md +94 -94
- data/docs/ripper.md +4 -4
- data/docs/ruby_api.md +11 -11
- data/docs/serialization.md +17 -16
- data/docs/testing.md +6 -6
- data/ext/prism/api_node.c +4725 -0
- data/ext/{yarp → prism}/api_pack.c +82 -82
- data/ext/{yarp → prism}/extconf.rb +13 -13
- data/ext/{yarp → prism}/extension.c +175 -168
- data/ext/prism/extension.h +18 -0
- data/include/prism/ast.h +1932 -0
- data/include/prism/defines.h +45 -0
- data/include/prism/diagnostic.h +231 -0
- data/include/{yarp/enc/yp_encoding.h → prism/enc/pm_encoding.h} +40 -40
- data/include/prism/node.h +41 -0
- data/include/prism/pack.h +141 -0
- data/include/{yarp → prism}/parser.h +143 -142
- data/include/prism/regexp.h +19 -0
- data/include/prism/unescape.h +48 -0
- data/include/prism/util/pm_buffer.h +51 -0
- data/include/{yarp/util/yp_char.h → prism/util/pm_char.h} +20 -20
- data/include/{yarp/util/yp_constant_pool.h → prism/util/pm_constant_pool.h} +26 -22
- data/include/{yarp/util/yp_list.h → prism/util/pm_list.h} +21 -21
- data/include/prism/util/pm_memchr.h +14 -0
- data/include/{yarp/util/yp_newline_list.h → prism/util/pm_newline_list.h} +11 -11
- data/include/prism/util/pm_state_stack.h +24 -0
- data/include/{yarp/util/yp_string.h → prism/util/pm_string.h} +20 -20
- data/include/prism/util/pm_string_list.h +25 -0
- data/include/{yarp/util/yp_strpbrk.h → prism/util/pm_strpbrk.h} +7 -7
- data/include/prism/version.h +4 -0
- data/include/prism.h +82 -0
- data/lib/prism/compiler.rb +465 -0
- data/lib/prism/debug.rb +157 -0
- data/lib/{yarp/desugar_visitor.rb → prism/desugar_compiler.rb} +4 -2
- data/lib/prism/dispatcher.rb +2051 -0
- data/lib/prism/dsl.rb +750 -0
- data/lib/{yarp → prism}/ffi.rb +66 -67
- data/lib/{yarp → prism}/lex_compat.rb +40 -43
- data/lib/{yarp/mutation_visitor.rb → prism/mutation_compiler.rb} +3 -3
- data/lib/{yarp → prism}/node.rb +2012 -2593
- data/lib/prism/node_ext.rb +55 -0
- data/lib/prism/node_inspector.rb +68 -0
- data/lib/{yarp → prism}/pack.rb +1 -1
- data/lib/{yarp → prism}/parse_result/comments.rb +1 -1
- data/lib/{yarp → prism}/parse_result/newlines.rb +1 -1
- data/lib/prism/parse_result.rb +266 -0
- data/lib/{yarp → prism}/pattern.rb +14 -14
- data/lib/{yarp → prism}/ripper_compat.rb +5 -5
- data/lib/{yarp → prism}/serialize.rb +12 -7
- data/lib/prism/visitor.rb +470 -0
- data/lib/prism.rb +64 -0
- data/lib/yarp.rb +2 -614
- data/src/diagnostic.c +213 -208
- data/src/enc/pm_big5.c +52 -0
- data/src/enc/pm_euc_jp.c +58 -0
- data/src/enc/{yp_gbk.c → pm_gbk.c} +16 -16
- data/src/enc/pm_shift_jis.c +56 -0
- data/src/enc/{yp_tables.c → pm_tables.c} +69 -69
- data/src/enc/{yp_unicode.c → pm_unicode.c} +40 -40
- data/src/enc/pm_windows_31j.c +56 -0
- data/src/node.c +1293 -1233
- data/src/pack.c +247 -247
- data/src/prettyprint.c +1479 -1479
- data/src/{yarp.c → prism.c} +5205 -5083
- data/src/regexp.c +132 -132
- data/src/serialize.c +1121 -1121
- data/src/token_type.c +169 -167
- data/src/unescape.c +106 -87
- data/src/util/pm_buffer.c +103 -0
- data/src/util/{yp_char.c → pm_char.c} +72 -72
- data/src/util/{yp_constant_pool.c → pm_constant_pool.c} +85 -64
- data/src/util/{yp_list.c → pm_list.c} +10 -10
- data/src/util/{yp_memchr.c → pm_memchr.c} +6 -4
- data/src/util/{yp_newline_list.c → pm_newline_list.c} +21 -21
- data/src/util/{yp_state_stack.c → pm_state_stack.c} +4 -4
- data/src/util/{yp_string.c → pm_string.c} +38 -38
- data/src/util/pm_string_list.c +29 -0
- data/src/util/{yp_strncasecmp.c → pm_strncasecmp.c} +1 -1
- data/src/util/{yp_strpbrk.c → pm_strpbrk.c} +8 -8
- data/yarp.gemspec +68 -59
- metadata +70 -61
- data/ext/yarp/api_node.c +0 -4728
- data/ext/yarp/extension.h +0 -18
- data/include/yarp/ast.h +0 -1929
- data/include/yarp/defines.h +0 -45
- data/include/yarp/diagnostic.h +0 -226
- data/include/yarp/node.h +0 -42
- data/include/yarp/pack.h +0 -141
- data/include/yarp/regexp.h +0 -19
- data/include/yarp/unescape.h +0 -44
- data/include/yarp/util/yp_buffer.h +0 -51
- data/include/yarp/util/yp_memchr.h +0 -14
- data/include/yarp/util/yp_state_stack.h +0 -24
- data/include/yarp/util/yp_string_list.h +0 -25
- data/include/yarp/version.h +0 -4
- data/include/yarp.h +0 -82
- data/src/enc/yp_big5.c +0 -52
- data/src/enc/yp_euc_jp.c +0 -58
- data/src/enc/yp_shift_jis.c +0 -56
- data/src/enc/yp_windows_31j.c +0 -56
- data/src/util/yp_buffer.c +0 -101
- data/src/util/yp_string_list.c +0 -29
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Here we are reopening the prism module to provide methods on nodes that aren't
|
|
4
|
+
# templated and are meant as convenience methods.
|
|
5
|
+
module Prism
|
|
6
|
+
class FloatNode < Node
|
|
7
|
+
# Returns the value of the node as a Ruby Float.
|
|
8
|
+
def value
|
|
9
|
+
Float(slice)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ImaginaryNode < Node
|
|
14
|
+
# Returns the value of the node as a Ruby Complex.
|
|
15
|
+
def value
|
|
16
|
+
Complex(0, numeric.value)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class IntegerNode < Node
|
|
21
|
+
# Returns the value of the node as a Ruby Integer.
|
|
22
|
+
def value
|
|
23
|
+
Integer(slice)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
class InterpolatedRegularExpressionNode < Node
|
|
28
|
+
# Returns a numeric value that represents the flags that were used to create
|
|
29
|
+
# the regular expression.
|
|
30
|
+
def options
|
|
31
|
+
o = flags & (RegularExpressionFlags::IGNORE_CASE | RegularExpressionFlags::EXTENDED | RegularExpressionFlags::MULTI_LINE)
|
|
32
|
+
o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
|
|
33
|
+
o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
|
|
34
|
+
o
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class RationalNode < Node
|
|
39
|
+
# Returns the value of the node as a Ruby Rational.
|
|
40
|
+
def value
|
|
41
|
+
Rational(slice.chomp("r"))
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class RegularExpressionNode < Node
|
|
46
|
+
# Returns a numeric value that represents the flags that were used to create
|
|
47
|
+
# the regular expression.
|
|
48
|
+
def options
|
|
49
|
+
o = flags & (RegularExpressionFlags::IGNORE_CASE | RegularExpressionFlags::EXTENDED | RegularExpressionFlags::MULTI_LINE)
|
|
50
|
+
o |= Regexp::FIXEDENCODING if flags.anybits?(RegularExpressionFlags::EUC_JP | RegularExpressionFlags::WINDOWS_31J | RegularExpressionFlags::UTF_8)
|
|
51
|
+
o |= Regexp::NOENCODING if flags.anybits?(RegularExpressionFlags::ASCII_8BIT)
|
|
52
|
+
o
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prism
|
|
4
|
+
# This object is responsible for generating the output for the inspect method
|
|
5
|
+
# implementations of child nodes.
|
|
6
|
+
class NodeInspector
|
|
7
|
+
attr_reader :prefix, :output
|
|
8
|
+
|
|
9
|
+
def initialize(prefix = "")
|
|
10
|
+
@prefix = prefix
|
|
11
|
+
@output = +""
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Appends a line to the output with the current prefix.
|
|
15
|
+
def <<(line)
|
|
16
|
+
output << "#{prefix}#{line}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# This generates a string that is used as the header of the inspect output
|
|
20
|
+
# for any given node.
|
|
21
|
+
def header(node)
|
|
22
|
+
output = +"@ #{node.class.name.split("::").last} ("
|
|
23
|
+
output << "location: (#{node.location.start_line},#{node.location.start_column})-(#{node.location.end_line},#{node.location.end_column})"
|
|
24
|
+
output << ", newline: true" if node.newline?
|
|
25
|
+
output << ")\n"
|
|
26
|
+
output
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Generates a string that represents a list of nodes. It handles properly
|
|
30
|
+
# using the box drawing characters to make the output look nice.
|
|
31
|
+
def list(prefix, nodes)
|
|
32
|
+
output = +"(length: #{nodes.length})\n"
|
|
33
|
+
last_index = nodes.length - 1
|
|
34
|
+
|
|
35
|
+
nodes.each_with_index do |node, index|
|
|
36
|
+
pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "]
|
|
37
|
+
node_prefix = "#{prefix}#{preadd}"
|
|
38
|
+
output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}")
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
output
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Generates a string that represents a location field on a node.
|
|
45
|
+
def location(value)
|
|
46
|
+
if value
|
|
47
|
+
"(#{value.start_line},#{value.start_column})-(#{value.end_line},#{value.end_column}) = #{value.slice.inspect}"
|
|
48
|
+
else
|
|
49
|
+
"∅"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Generates a string that represents a child node.
|
|
54
|
+
def child_node(node, append)
|
|
55
|
+
node.inspect(child_inspector(append)).delete_prefix(prefix)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Returns a new inspector that can be used to inspect a child node.
|
|
59
|
+
def child_inspector(append)
|
|
60
|
+
NodeInspector.new("#{prefix}#{append}")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Returns the output as a string.
|
|
64
|
+
def to_str
|
|
65
|
+
output
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/{yarp → prism}/pack.rb
RENAMED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Prism
|
|
4
|
+
# This represents a source of Ruby code that has been parsed. It is used in
|
|
5
|
+
# conjunction with locations to allow them to resolve line numbers and source
|
|
6
|
+
# ranges.
|
|
7
|
+
class Source
|
|
8
|
+
attr_reader :source, :offsets
|
|
9
|
+
|
|
10
|
+
def initialize(source, offsets = compute_offsets(source))
|
|
11
|
+
@source = source
|
|
12
|
+
@offsets = offsets
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def slice(offset, length)
|
|
16
|
+
source.byteslice(offset, length)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def line(value)
|
|
20
|
+
offsets.bsearch_index { |offset| offset > value } || offsets.length
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def line_offset(value)
|
|
24
|
+
offsets[line(value) - 1]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def column(value)
|
|
28
|
+
value - offsets[line(value) - 1]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def compute_offsets(code)
|
|
34
|
+
offsets = [0]
|
|
35
|
+
code.b.scan("\n") { offsets << $~.end(0) }
|
|
36
|
+
offsets
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# This represents a location in the source.
|
|
41
|
+
class Location
|
|
42
|
+
# A Source object that is used to determine more information from the given
|
|
43
|
+
# offset and length.
|
|
44
|
+
protected attr_reader :source
|
|
45
|
+
|
|
46
|
+
# The byte offset from the beginning of the source where this location
|
|
47
|
+
# starts.
|
|
48
|
+
attr_reader :start_offset
|
|
49
|
+
|
|
50
|
+
# The length of this location in bytes.
|
|
51
|
+
attr_reader :length
|
|
52
|
+
|
|
53
|
+
# The list of comments attached to this location
|
|
54
|
+
attr_reader :comments
|
|
55
|
+
|
|
56
|
+
def initialize(source, start_offset, length)
|
|
57
|
+
@source = source
|
|
58
|
+
@start_offset = start_offset
|
|
59
|
+
@length = length
|
|
60
|
+
@comments = []
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Create a new location object with the given options.
|
|
64
|
+
def copy(**options)
|
|
65
|
+
Location.new(
|
|
66
|
+
options.fetch(:source) { source },
|
|
67
|
+
options.fetch(:start_offset) { start_offset },
|
|
68
|
+
options.fetch(:length) { length }
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns a string representation of this location.
|
|
73
|
+
def inspect
|
|
74
|
+
"#<Prism::Location @start_offset=#{@start_offset} @length=#{@length} start_line=#{start_line}>"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# The source code that this location represents.
|
|
78
|
+
def slice
|
|
79
|
+
source.slice(start_offset, length)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# The byte offset from the beginning of the source where this location ends.
|
|
83
|
+
def end_offset
|
|
84
|
+
start_offset + length
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# The line number where this location starts.
|
|
88
|
+
def start_line
|
|
89
|
+
source.line(start_offset)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# The content of the line where this location starts before this location.
|
|
93
|
+
def start_line_slice
|
|
94
|
+
offset = source.line_offset(start_offset)
|
|
95
|
+
source.slice(offset, start_offset - offset)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The line number where this location ends.
|
|
99
|
+
def end_line
|
|
100
|
+
source.line(end_offset - 1)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# The column number in bytes where this location starts from the start of
|
|
104
|
+
# the line.
|
|
105
|
+
def start_column
|
|
106
|
+
source.column(start_offset)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# The column number in bytes where this location ends from the start of the
|
|
110
|
+
# line.
|
|
111
|
+
def end_column
|
|
112
|
+
source.column(end_offset)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def deconstruct_keys(keys)
|
|
116
|
+
{ start_offset: start_offset, end_offset: end_offset }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def pretty_print(q)
|
|
120
|
+
q.text("(#{start_line},#{start_column})-(#{end_line},#{end_column}))")
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def ==(other)
|
|
124
|
+
other.is_a?(Location) &&
|
|
125
|
+
other.start_offset == start_offset &&
|
|
126
|
+
other.end_offset == end_offset
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Returns a new location that stretches from this location to the given
|
|
130
|
+
# other location. Raises an error if this location is not before the other
|
|
131
|
+
# location or if they don't share the same source.
|
|
132
|
+
def join(other)
|
|
133
|
+
raise "Incompatible sources" if source != other.source
|
|
134
|
+
raise "Incompatible locations" if start_offset > other.start_offset
|
|
135
|
+
|
|
136
|
+
Location.new(source, start_offset, other.end_offset - start_offset)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self.null
|
|
140
|
+
new(0, 0)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# This represents a comment that was encountered during parsing.
|
|
145
|
+
class Comment
|
|
146
|
+
TYPES = [:inline, :embdoc, :__END__]
|
|
147
|
+
|
|
148
|
+
attr_reader :type, :location
|
|
149
|
+
|
|
150
|
+
def initialize(type, location)
|
|
151
|
+
@type = type
|
|
152
|
+
@location = location
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def deconstruct_keys(keys)
|
|
156
|
+
{ type: type, location: location }
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Returns true if the comment happens on the same line as other code and false if the comment is by itself
|
|
160
|
+
def trailing?
|
|
161
|
+
type == :inline && !location.start_line_slice.strip.empty?
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def inspect
|
|
165
|
+
"#<Prism::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# This represents an error that was encountered during parsing.
|
|
170
|
+
class ParseError
|
|
171
|
+
attr_reader :message, :location
|
|
172
|
+
|
|
173
|
+
def initialize(message, location)
|
|
174
|
+
@message = message
|
|
175
|
+
@location = location
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def deconstruct_keys(keys)
|
|
179
|
+
{ message: message, location: location }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def inspect
|
|
183
|
+
"#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# This represents a warning that was encountered during parsing.
|
|
188
|
+
class ParseWarning
|
|
189
|
+
attr_reader :message, :location
|
|
190
|
+
|
|
191
|
+
def initialize(message, location)
|
|
192
|
+
@message = message
|
|
193
|
+
@location = location
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def deconstruct_keys(keys)
|
|
197
|
+
{ message: message, location: location }
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def inspect
|
|
201
|
+
"#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# This represents the result of a call to ::parse or ::parse_file. It contains
|
|
206
|
+
# the AST, any comments that were encounters, and any errors that were
|
|
207
|
+
# encountered.
|
|
208
|
+
class ParseResult
|
|
209
|
+
attr_reader :value, :comments, :errors, :warnings, :source
|
|
210
|
+
|
|
211
|
+
def initialize(value, comments, errors, warnings, source)
|
|
212
|
+
@value = value
|
|
213
|
+
@comments = comments
|
|
214
|
+
@errors = errors
|
|
215
|
+
@warnings = warnings
|
|
216
|
+
@source = source
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def deconstruct_keys(keys)
|
|
220
|
+
{ value: value, comments: comments, errors: errors, warnings: warnings }
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def success?
|
|
224
|
+
errors.empty?
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def failure?
|
|
228
|
+
!success?
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# This represents a token from the Ruby source.
|
|
233
|
+
class Token
|
|
234
|
+
attr_reader :type, :value, :location
|
|
235
|
+
|
|
236
|
+
def initialize(type, value, location)
|
|
237
|
+
@type = type
|
|
238
|
+
@value = value
|
|
239
|
+
@location = location
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def deconstruct_keys(keys)
|
|
243
|
+
{ type: type, value: value, location: location }
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def pretty_print(q)
|
|
247
|
+
q.group do
|
|
248
|
+
q.text(type.to_s)
|
|
249
|
+
self.location.pretty_print(q)
|
|
250
|
+
q.text("(")
|
|
251
|
+
q.nest(2) do
|
|
252
|
+
q.breakable("")
|
|
253
|
+
q.pp(value)
|
|
254
|
+
end
|
|
255
|
+
q.breakable("")
|
|
256
|
+
q.text(")")
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def ==(other)
|
|
261
|
+
other.is_a?(Token) &&
|
|
262
|
+
other.type == type &&
|
|
263
|
+
other.value == value
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
end
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module Prism
|
|
4
4
|
# A pattern is an object that wraps a Ruby pattern matching expression. The
|
|
5
5
|
# expression would normally be passed to an `in` clause within a `case`
|
|
6
6
|
# expression or a rightward assignment expression. For example, in the
|
|
7
7
|
# following snippet:
|
|
8
8
|
#
|
|
9
9
|
# case node
|
|
10
|
-
# in ConstantPathNode[ConstantReadNode[name: :
|
|
10
|
+
# in ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]
|
|
11
11
|
# end
|
|
12
12
|
#
|
|
13
13
|
# the pattern is the `ConstantPathNode[...]` expression.
|
|
14
14
|
#
|
|
15
15
|
# The pattern gets compiled into an object that responds to #call by running
|
|
16
|
-
# the #compile method. This method itself will run back through
|
|
16
|
+
# the #compile method. This method itself will run back through Prism to
|
|
17
17
|
# parse the expression into a tree, then walk the tree to generate the
|
|
18
18
|
# necessary callable objects. For example, if you wanted to compile the
|
|
19
19
|
# expression above into a callable, you would:
|
|
20
20
|
#
|
|
21
|
-
# callable =
|
|
21
|
+
# callable = Prism::Pattern.new("ConstantPathNode[ConstantReadNode[name: :Prism], ConstantReadNode[name: :Pattern]]").compile
|
|
22
22
|
# callable.call(node)
|
|
23
23
|
#
|
|
24
24
|
# The callable object returned by #compile is guaranteed to respond to #call
|
|
@@ -32,7 +32,7 @@ module YARP
|
|
|
32
32
|
#
|
|
33
33
|
# If the query given to the initializer cannot be compiled into a valid
|
|
34
34
|
# matcher (either because of a syntax error or because it is using syntax we
|
|
35
|
-
# do not yet support) then a
|
|
35
|
+
# do not yet support) then a Prism::Pattern::CompilationError will be
|
|
36
36
|
# raised.
|
|
37
37
|
class Pattern
|
|
38
38
|
# Raised when the query given to a pattern is either invalid Ruby syntax or
|
|
@@ -40,15 +40,15 @@ module YARP
|
|
|
40
40
|
class CompilationError < StandardError
|
|
41
41
|
def initialize(repr)
|
|
42
42
|
super(<<~ERROR)
|
|
43
|
-
|
|
43
|
+
prism was unable to compile the pattern you provided into a usable
|
|
44
44
|
expression. It failed on to understand the node represented by:
|
|
45
45
|
|
|
46
46
|
#{repr}
|
|
47
47
|
|
|
48
48
|
Note that not all syntax supported by Ruby's pattern matching syntax
|
|
49
|
-
is also supported by
|
|
49
|
+
is also supported by prism's patterns. If you're using some syntax
|
|
50
50
|
that you believe should be supported, please open an issue on
|
|
51
|
-
GitHub at https://github.com/ruby/
|
|
51
|
+
GitHub at https://github.com/ruby/prism/issues/new.
|
|
52
52
|
ERROR
|
|
53
53
|
end
|
|
54
54
|
end
|
|
@@ -61,7 +61,7 @@ module YARP
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def compile
|
|
64
|
-
result =
|
|
64
|
+
result = Prism.parse("case nil\nin #{query}\nend")
|
|
65
65
|
compile_node(result.value.statements.body.last.conditions.last.pattern)
|
|
66
66
|
end
|
|
67
67
|
|
|
@@ -73,7 +73,7 @@ module YARP
|
|
|
73
73
|
|
|
74
74
|
while (node = queue.shift)
|
|
75
75
|
yield node if @compiled.call(node)
|
|
76
|
-
queue.concat(node.
|
|
76
|
+
queue.concat(node.compact_child_nodes)
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
@@ -126,11 +126,11 @@ module YARP
|
|
|
126
126
|
combine_or(compile_node(node.left), compile_node(node.right))
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
# in
|
|
129
|
+
# in Prism::ConstantReadNode
|
|
130
130
|
def compile_constant_path_node(node)
|
|
131
131
|
parent = node.parent
|
|
132
132
|
|
|
133
|
-
if parent.is_a?(ConstantReadNode) && parent.slice == "
|
|
133
|
+
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
|
|
134
134
|
compile_node(node.child)
|
|
135
135
|
else
|
|
136
136
|
compile_error(node)
|
|
@@ -142,8 +142,8 @@ module YARP
|
|
|
142
142
|
def compile_constant_read_node(node)
|
|
143
143
|
value = node.slice
|
|
144
144
|
|
|
145
|
-
if
|
|
146
|
-
clazz =
|
|
145
|
+
if Prism.const_defined?(value, false)
|
|
146
|
+
clazz = Prism.const_get(value)
|
|
147
147
|
|
|
148
148
|
->(other) { clazz === other }
|
|
149
149
|
elsif Object.const_defined?(value, false)
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
require "ripper"
|
|
4
4
|
|
|
5
|
-
module
|
|
6
|
-
# This class is meant to provide a compatibility layer between
|
|
5
|
+
module Prism
|
|
6
|
+
# This class is meant to provide a compatibility layer between prism and
|
|
7
7
|
# Ripper. It functions by parsing the entire tree first and then walking it
|
|
8
8
|
# and executing each of the Ripper callbacks as it goes.
|
|
9
9
|
#
|
|
10
10
|
# This class is going to necessarily be slower than the native Ripper API. It
|
|
11
|
-
# is meant as a stopgap until developers migrate to using
|
|
12
|
-
# meant as a test harness for the
|
|
11
|
+
# is meant as a stopgap until developers migrate to using prism. It is also
|
|
12
|
+
# meant as a test harness for the prism parser.
|
|
13
13
|
class RipperCompat
|
|
14
14
|
# This class mirrors the ::Ripper::SexpBuilder subclass of ::Ripper that
|
|
15
15
|
# returns the arrays of [type, *children].
|
|
@@ -156,7 +156,7 @@ module YARP
|
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
def result
|
|
159
|
-
@result ||=
|
|
159
|
+
@result ||= Prism.parse(source)
|
|
160
160
|
end
|
|
161
161
|
|
|
162
162
|
def _dispatch0; end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
=begin
|
|
3
3
|
This file is generated by the templates/template.rb script and should not be
|
|
4
|
-
modified manually. See templates/lib/
|
|
4
|
+
modified manually. See templates/lib/prism/serialize.rb.erb
|
|
5
5
|
if you are looking to modify the template
|
|
6
6
|
=end
|
|
7
7
|
|
|
@@ -18,10 +18,10 @@ if String.instance_method(:unpack1).parameters.none? { |_, name| name == :offset
|
|
|
18
18
|
)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
module
|
|
21
|
+
module Prism
|
|
22
22
|
module Serialize
|
|
23
23
|
MAJOR_VERSION = 0
|
|
24
|
-
MINOR_VERSION =
|
|
24
|
+
MINOR_VERSION = 13
|
|
25
25
|
PATCH_VERSION = 0
|
|
26
26
|
|
|
27
27
|
def self.load(input, serialized)
|
|
@@ -74,7 +74,7 @@ module YARP
|
|
|
74
74
|
length = load_varint
|
|
75
75
|
lex_state = load_varint
|
|
76
76
|
location = Location.new(@source, start, length)
|
|
77
|
-
tokens << [
|
|
77
|
+
tokens << [Prism::Token.new(type, location.slice, location), lex_state]
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
tokens
|
|
@@ -90,12 +90,16 @@ module YARP
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
raise "Expected to consume all bytes while deserializing" unless @io.eof?
|
|
93
|
-
|
|
93
|
+
Prism::ParseResult.new(tokens, comments, errors, warnings, @source)
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def load_nodes
|
|
97
|
-
raise "Invalid serialization" if io.read(
|
|
97
|
+
raise "Invalid serialization" if io.read(5) != "PRISM"
|
|
98
98
|
raise "Invalid serialization" if io.read(3).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
|
|
99
|
+
only_semantic_fields = io.read(1).unpack1("C")
|
|
100
|
+
unless only_semantic_fields == 0
|
|
101
|
+
raise "Invalid serialization (location fields must be included but are not)"
|
|
102
|
+
end
|
|
99
103
|
|
|
100
104
|
@encoding = load_encoding
|
|
101
105
|
@input = input.force_encoding(@encoding).freeze
|
|
@@ -110,7 +114,7 @@ module YARP
|
|
|
110
114
|
|
|
111
115
|
def load_result
|
|
112
116
|
node, comments, errors, warnings = load_nodes
|
|
113
|
-
|
|
117
|
+
Prism::ParseResult.new(node, comments, errors, warnings, @source)
|
|
114
118
|
end
|
|
115
119
|
|
|
116
120
|
private
|
|
@@ -605,6 +609,7 @@ module YARP
|
|
|
605
609
|
:LESS_EQUAL_GREATER,
|
|
606
610
|
:LESS_LESS,
|
|
607
611
|
:LESS_LESS_EQUAL,
|
|
612
|
+
:METHOD_NAME,
|
|
608
613
|
:MINUS,
|
|
609
614
|
:MINUS_EQUAL,
|
|
610
615
|
:MINUS_GREATER,
|