prism 0.24.0 → 0.25.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/BSDmakefile +58 -0
- data/CHANGELOG.md +50 -1
- data/Makefile +5 -2
- data/README.md +45 -6
- data/config.yml +499 -4
- data/docs/build_system.md +31 -0
- data/docs/configuration.md +2 -0
- data/docs/cruby_compilation.md +1 -1
- data/docs/parser_translation.md +14 -9
- data/docs/releasing.md +2 -2
- data/docs/ripper_translation.md +50 -0
- data/docs/ruby_api.md +1 -0
- data/docs/serialization.md +26 -5
- data/ext/prism/api_node.c +911 -815
- data/ext/prism/api_pack.c +9 -0
- data/ext/prism/extconf.rb +27 -11
- data/ext/prism/extension.c +313 -66
- data/ext/prism/extension.h +5 -4
- data/include/prism/ast.h +213 -64
- data/include/prism/defines.h +106 -2
- data/include/prism/diagnostic.h +134 -71
- data/include/prism/encoding.h +22 -4
- data/include/prism/node.h +93 -0
- data/include/prism/options.h +82 -7
- data/include/prism/pack.h +11 -0
- data/include/prism/parser.h +198 -53
- data/include/prism/prettyprint.h +8 -0
- data/include/prism/static_literals.h +118 -0
- data/include/prism/util/pm_buffer.h +65 -2
- data/include/prism/util/pm_constant_pool.h +18 -1
- data/include/prism/util/pm_integer.h +119 -0
- data/include/prism/util/pm_list.h +1 -1
- data/include/prism/util/pm_newline_list.h +8 -0
- data/include/prism/util/pm_string.h +26 -2
- data/include/prism/version.h +2 -2
- data/include/prism.h +59 -1
- data/lib/prism/compiler.rb +8 -1
- data/lib/prism/debug.rb +46 -3
- data/lib/prism/desugar_compiler.rb +1 -1
- data/lib/prism/dispatcher.rb +29 -0
- data/lib/prism/dot_visitor.rb +87 -16
- data/lib/prism/dsl.rb +24 -12
- data/lib/prism/ffi.rb +67 -12
- data/lib/prism/lex_compat.rb +17 -15
- data/lib/prism/mutation_compiler.rb +11 -0
- data/lib/prism/node.rb +2096 -2499
- data/lib/prism/node_ext.rb +77 -29
- data/lib/prism/pack.rb +4 -0
- data/lib/prism/parse_result/comments.rb +34 -17
- data/lib/prism/parse_result/newlines.rb +3 -1
- data/lib/prism/parse_result.rb +78 -32
- data/lib/prism/pattern.rb +16 -4
- data/lib/prism/polyfill/string.rb +12 -0
- data/lib/prism/serialize.rb +439 -102
- data/lib/prism/translation/parser/compiler.rb +152 -50
- data/lib/prism/translation/parser/lexer.rb +103 -22
- data/lib/prism/translation/parser/rubocop.rb +41 -13
- data/lib/prism/translation/parser.rb +119 -7
- data/lib/prism/translation/parser33.rb +1 -1
- data/lib/prism/translation/parser34.rb +1 -1
- data/lib/prism/translation/ripper/sexp.rb +125 -0
- data/lib/prism/translation/ripper/shim.rb +5 -0
- data/lib/prism/translation/ripper.rb +3212 -462
- data/lib/prism/translation/ruby_parser.rb +35 -18
- data/lib/prism/translation.rb +3 -1
- data/lib/prism/visitor.rb +10 -0
- data/lib/prism.rb +8 -2
- data/prism.gemspec +33 -4
- data/rbi/prism/compiler.rbi +14 -0
- data/rbi/prism/desugar_compiler.rbi +5 -0
- data/rbi/prism/mutation_compiler.rbi +5 -0
- data/rbi/prism/node.rbi +8221 -0
- data/rbi/prism/node_ext.rbi +102 -0
- data/rbi/prism/parse_result.rbi +304 -0
- data/rbi/prism/translation/parser/compiler.rbi +13 -0
- data/rbi/prism/translation/ripper/ripper_compiler.rbi +5 -0
- data/rbi/prism/translation/ripper.rbi +25 -0
- data/rbi/prism/translation/ruby_parser.rbi +11 -0
- data/rbi/prism/visitor.rbi +470 -0
- data/rbi/prism.rbi +39 -7749
- data/sig/prism/compiler.rbs +9 -0
- data/sig/prism/dispatcher.rbs +16 -0
- data/sig/prism/dot_visitor.rbs +6 -0
- data/sig/prism/dsl.rbs +462 -0
- data/sig/prism/mutation_compiler.rbs +158 -0
- data/sig/prism/node.rbs +3529 -0
- data/sig/prism/node_ext.rbs +78 -0
- data/sig/prism/pack.rbs +43 -0
- data/sig/prism/parse_result.rbs +127 -0
- data/sig/prism/pattern.rbs +13 -0
- data/sig/prism/serialize.rbs +7 -0
- data/sig/prism/visitor.rbs +168 -0
- data/sig/prism.rbs +188 -4767
- data/src/diagnostic.c +575 -230
- data/src/encoding.c +211 -108
- data/src/node.c +7526 -447
- data/src/options.c +36 -12
- data/src/pack.c +33 -17
- data/src/prettyprint.c +1294 -1385
- data/src/prism.c +3628 -1099
- data/src/regexp.c +17 -2
- data/src/serialize.c +47 -28
- data/src/static_literals.c +552 -0
- data/src/token_type.c +1 -0
- data/src/util/pm_buffer.c +147 -20
- data/src/util/pm_char.c +4 -4
- data/src/util/pm_constant_pool.c +35 -11
- data/src/util/pm_integer.c +629 -0
- data/src/util/pm_list.c +1 -1
- data/src/util/pm_newline_list.c +14 -5
- data/src/util/pm_string.c +134 -5
- data/src/util/pm_string_list.c +2 -2
- metadata +35 -6
- data/docs/ripper.md +0 -36
- data/rbi/prism_static.rbi +0 -207
- data/sig/prism_static.rbs +0 -201
data/lib/prism/node_ext.rb
CHANGED
@@ -49,21 +49,39 @@ module Prism
|
|
49
49
|
|
50
50
|
class StringNode < Node
|
51
51
|
include HeredocQuery
|
52
|
+
|
53
|
+
# Occasionally it's helpful to treat a string as if it were interpolated so
|
54
|
+
# that there's a consistent interface for working with strings.
|
55
|
+
def to_interpolated
|
56
|
+
InterpolatedStringNode.new(
|
57
|
+
source,
|
58
|
+
frozen? ? InterpolatedStringNodeFlags::FROZEN : 0,
|
59
|
+
opening_loc,
|
60
|
+
[copy(opening_loc: nil, closing_loc: nil, location: content_loc)],
|
61
|
+
closing_loc,
|
62
|
+
location
|
63
|
+
)
|
64
|
+
end
|
52
65
|
end
|
53
66
|
|
54
67
|
class XStringNode < Node
|
55
68
|
include HeredocQuery
|
56
|
-
end
|
57
|
-
|
58
|
-
private_constant :HeredocQuery
|
59
69
|
|
60
|
-
|
61
|
-
#
|
62
|
-
def
|
63
|
-
|
70
|
+
# Occasionally it's helpful to treat a string as if it were interpolated so
|
71
|
+
# that there's a consistent interface for working with strings.
|
72
|
+
def to_interpolated
|
73
|
+
InterpolatedXStringNode.new(
|
74
|
+
source,
|
75
|
+
opening_loc,
|
76
|
+
[StringNode.new(source, 0, nil, content_loc, nil, unescaped, content_loc)],
|
77
|
+
closing_loc,
|
78
|
+
location
|
79
|
+
)
|
64
80
|
end
|
65
81
|
end
|
66
82
|
|
83
|
+
private_constant :HeredocQuery
|
84
|
+
|
67
85
|
class ImaginaryNode < Node
|
68
86
|
# Returns the value of the node as a Ruby Complex.
|
69
87
|
def value
|
@@ -71,13 +89,6 @@ module Prism
|
|
71
89
|
end
|
72
90
|
end
|
73
91
|
|
74
|
-
class IntegerNode < Node
|
75
|
-
# Returns the value of the node as a Ruby Integer.
|
76
|
-
def value
|
77
|
-
Integer(slice)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
92
|
class RationalNode < Node
|
82
93
|
# Returns the value of the node as a Ruby Rational.
|
83
94
|
def value
|
@@ -98,6 +109,19 @@ module Prism
|
|
98
109
|
end
|
99
110
|
end
|
100
111
|
|
112
|
+
class ConstantWriteNode < Node
|
113
|
+
# Returns the list of parts for the full name of this constant.
|
114
|
+
# For example: [:Foo]
|
115
|
+
def full_name_parts
|
116
|
+
[name]
|
117
|
+
end
|
118
|
+
|
119
|
+
# Returns the full name of this constant. For example: "Foo"
|
120
|
+
def full_name
|
121
|
+
name.to_s
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
101
125
|
class ConstantPathNode < Node
|
102
126
|
# An error class raised when dynamic parts are found while computing a
|
103
127
|
# constant path's full name. For example:
|
@@ -107,14 +131,23 @@ module Prism
|
|
107
131
|
# local variable
|
108
132
|
class DynamicPartsInConstantPathError < StandardError; end
|
109
133
|
|
134
|
+
# An error class raised when missing nodes are found while computing a
|
135
|
+
# constant path's full name. For example:
|
136
|
+
# Foo:: -> raises because the constant path is missing the last part
|
137
|
+
class MissingNodesInConstantPathError < StandardError; end
|
138
|
+
|
110
139
|
# Returns the list of parts for the full name of this constant path.
|
111
140
|
# For example: [:Foo, :Bar]
|
112
141
|
def full_name_parts
|
113
|
-
parts = [
|
114
|
-
current =
|
142
|
+
parts = [] #: Array[Symbol]
|
143
|
+
current = self #: node?
|
115
144
|
|
116
145
|
while current.is_a?(ConstantPathNode)
|
117
|
-
|
146
|
+
child = current.child
|
147
|
+
if child.is_a?(MissingNode)
|
148
|
+
raise MissingNodesInConstantPathError, "Constant path contains missing nodes. Cannot compute full name"
|
149
|
+
end
|
150
|
+
parts.unshift(child.name)
|
118
151
|
current = current.parent
|
119
152
|
end
|
120
153
|
|
@@ -135,14 +168,19 @@ module Prism
|
|
135
168
|
# Returns the list of parts for the full name of this constant path.
|
136
169
|
# For example: [:Foo, :Bar]
|
137
170
|
def full_name_parts
|
138
|
-
parts =
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
171
|
+
parts =
|
172
|
+
case parent
|
173
|
+
when ConstantPathNode, ConstantReadNode
|
174
|
+
parent.full_name_parts
|
175
|
+
when nil
|
176
|
+
[:""]
|
177
|
+
else
|
178
|
+
# e.g. self::Foo, (var)::Bar = baz
|
179
|
+
raise ConstantPathNode::DynamicPartsInConstantPathError, "Constant target path contains dynamic parts. Cannot compute full name"
|
180
|
+
end
|
181
|
+
|
182
|
+
if child.is_a?(MissingNode)
|
183
|
+
raise ConstantPathNode::MissingNodesInConstantPathError, "Constant target path contains missing nodes. Cannot compute full name"
|
146
184
|
end
|
147
185
|
|
148
186
|
parts.push(child.name)
|
@@ -170,22 +208,32 @@ module Prism
|
|
170
208
|
class ParametersNode < Node
|
171
209
|
# Mirrors the Method#parameters method.
|
172
210
|
def signature
|
173
|
-
names = []
|
211
|
+
names = [] #: Array[[Symbol, Symbol] | [Symbol]]
|
174
212
|
|
175
213
|
requireds.each do |param|
|
176
214
|
names << (param.is_a?(MultiTargetNode) ? [:req] : [:req, param.name])
|
177
215
|
end
|
178
216
|
|
179
217
|
optionals.each { |param| names << [:opt, param.name] }
|
180
|
-
|
218
|
+
|
219
|
+
if rest && rest.is_a?(RestParameterNode)
|
220
|
+
names << [:rest, rest.name || :*]
|
221
|
+
end
|
181
222
|
|
182
223
|
posts.each do |param|
|
183
|
-
|
224
|
+
if param.is_a?(MultiTargetNode)
|
225
|
+
names << [:req]
|
226
|
+
elsif param.is_a?(NoKeywordsParameterNode)
|
227
|
+
# Invalid syntax, e.g. "def f(**nil, ...)" moves the NoKeywordsParameterNode to posts
|
228
|
+
raise "Invalid syntax"
|
229
|
+
else
|
230
|
+
names << [:req, param.name]
|
231
|
+
end
|
184
232
|
end
|
185
233
|
|
186
234
|
# Regardless of the order in which the keywords were defined, the required
|
187
235
|
# keywords always come first followed by the optional keywords.
|
188
|
-
keyopt = []
|
236
|
+
keyopt = [] #: Array[OptionalKeywordParameterNode]
|
189
237
|
keywords.each do |param|
|
190
238
|
if param.is_a?(OptionalKeywordParameterNode)
|
191
239
|
keyopt << param
|
data/lib/prism/pack.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
# typed: ignore
|
2
3
|
|
3
4
|
module Prism
|
4
5
|
# A parser for the pack template language.
|
@@ -148,6 +149,8 @@ module Prism
|
|
148
149
|
end
|
149
150
|
when LENGTH_MAX
|
150
151
|
base + ", as many as possible"
|
152
|
+
else
|
153
|
+
raise
|
151
154
|
end
|
152
155
|
when UTF8
|
153
156
|
"UTF-8 character"
|
@@ -214,6 +217,7 @@ module Prism
|
|
214
217
|
else
|
215
218
|
source = directive.source
|
216
219
|
end
|
220
|
+
# @type var source_width: Integer
|
217
221
|
" #{source.ljust(source_width)} #{directive.describe}"
|
218
222
|
end
|
219
223
|
|
@@ -27,11 +27,11 @@ module Prism
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def start_offset
|
30
|
-
node.
|
30
|
+
node.start_offset
|
31
31
|
end
|
32
32
|
|
33
33
|
def end_offset
|
34
|
-
node.
|
34
|
+
node.end_offset
|
35
35
|
end
|
36
36
|
|
37
37
|
def encloses?(comment)
|
@@ -39,8 +39,12 @@ module Prism
|
|
39
39
|
comment.location.end_offset <= end_offset
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
node.location.
|
42
|
+
def leading_comment(comment)
|
43
|
+
node.location.leading_comment(comment)
|
44
|
+
end
|
45
|
+
|
46
|
+
def trailing_comment(comment)
|
47
|
+
node.location.trailing_comment(comment)
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -65,8 +69,12 @@ module Prism
|
|
65
69
|
false
|
66
70
|
end
|
67
71
|
|
68
|
-
def
|
69
|
-
location.
|
72
|
+
def leading_comment(comment)
|
73
|
+
location.leading_comment(comment)
|
74
|
+
end
|
75
|
+
|
76
|
+
def trailing_comment(comment)
|
77
|
+
location.trailing_comment(comment)
|
70
78
|
end
|
71
79
|
end
|
72
80
|
|
@@ -84,15 +92,23 @@ module Prism
|
|
84
92
|
def attach!
|
85
93
|
parse_result.comments.each do |comment|
|
86
94
|
preceding, enclosing, following = nearest_targets(parse_result.value, comment)
|
87
|
-
|
88
|
-
|
89
|
-
|
95
|
+
|
96
|
+
if comment.trailing?
|
97
|
+
if preceding
|
98
|
+
preceding.trailing_comment(comment)
|
90
99
|
else
|
91
|
-
|
92
|
-
following || preceding || enclosing || NodeTarget.new(parse_result.value)
|
100
|
+
(following || enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
|
93
101
|
end
|
94
|
-
|
95
|
-
|
102
|
+
else
|
103
|
+
# If a comment exists on its own line, prefer a leading comment.
|
104
|
+
if following
|
105
|
+
following.leading_comment(comment)
|
106
|
+
elsif preceding
|
107
|
+
preceding.trailing_comment(comment)
|
108
|
+
else
|
109
|
+
(enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
|
110
|
+
end
|
111
|
+
end
|
96
112
|
end
|
97
113
|
end
|
98
114
|
|
@@ -104,7 +120,7 @@ module Prism
|
|
104
120
|
comment_start = comment.location.start_offset
|
105
121
|
comment_end = comment.location.end_offset
|
106
122
|
|
107
|
-
targets = []
|
123
|
+
targets = [] #: Array[_Target]
|
108
124
|
node.comment_targets.map do |value|
|
109
125
|
case value
|
110
126
|
when StatementsNode
|
@@ -117,8 +133,8 @@ module Prism
|
|
117
133
|
end
|
118
134
|
|
119
135
|
targets.sort_by!(&:start_offset)
|
120
|
-
preceding = nil
|
121
|
-
following = nil
|
136
|
+
preceding = nil #: _Target?
|
137
|
+
following = nil #: _Target?
|
122
138
|
|
123
139
|
left = 0
|
124
140
|
right = targets.length
|
@@ -134,6 +150,7 @@ module Prism
|
|
134
150
|
target_end = target.end_offset
|
135
151
|
|
136
152
|
if target.encloses?(comment)
|
153
|
+
# @type var target: NodeTarget
|
137
154
|
# The comment is completely contained by this target. Abandon the
|
138
155
|
# binary search at this level.
|
139
156
|
return nearest_targets(target.node, comment)
|
@@ -171,7 +188,7 @@ module Prism
|
|
171
188
|
|
172
189
|
# Attach the list of comments to their respective locations in the tree.
|
173
190
|
def attach_comments!
|
174
|
-
Comments.new(self).attach!
|
191
|
+
Comments.new(self).attach! # steep:ignore
|
175
192
|
end
|
176
193
|
end
|
177
194
|
end
|
@@ -58,7 +58,9 @@ module Prism
|
|
58
58
|
|
59
59
|
# Walk the tree and mark nodes that are on a new line.
|
60
60
|
def mark_newlines!
|
61
|
-
value
|
61
|
+
value = self.value
|
62
|
+
raise "This method should only be called on a parse result that contains a node" unless Node === value
|
63
|
+
value.accept(Newlines.new(Array.new(1 + source.offsets.size, false))) # steep:ignore
|
62
64
|
end
|
63
65
|
end
|
64
66
|
end
|
data/lib/prism/parse_result.rb
CHANGED
@@ -21,10 +21,16 @@ module Prism
|
|
21
21
|
@offsets = offsets # set after parsing is done
|
22
22
|
end
|
23
23
|
|
24
|
+
# Returns the encoding of the source code, which is set by parameters to the
|
25
|
+
# parser or by the encoding magic comment.
|
26
|
+
def encoding
|
27
|
+
source.encoding
|
28
|
+
end
|
29
|
+
|
24
30
|
# Perform a byteslice on the source code using the given byte offset and
|
25
31
|
# byte length.
|
26
32
|
def slice(byte_offset, length)
|
27
|
-
source.byteslice(byte_offset, length)
|
33
|
+
source.byteslice(byte_offset, length) or raise
|
28
34
|
end
|
29
35
|
|
30
36
|
# Binary search through the offsets to find the line number for the given
|
@@ -46,7 +52,7 @@ module Prism
|
|
46
52
|
|
47
53
|
# Return the character offset for the given byte offset.
|
48
54
|
def character_offset(byte_offset)
|
49
|
-
source.byteslice(0, byte_offset).length
|
55
|
+
(source.byteslice(0, byte_offset) or raise).length
|
50
56
|
end
|
51
57
|
|
52
58
|
# Return the column number in characters for the given byte offset.
|
@@ -61,7 +67,7 @@ module Prism
|
|
61
67
|
# concept of code units that differs from the number of characters in other
|
62
68
|
# encodings, it is not captured here.
|
63
69
|
def code_units_offset(byte_offset, encoding)
|
64
|
-
byteslice = source.byteslice(0, byte_offset).encode(encoding)
|
70
|
+
byteslice = (source.byteslice(0, byte_offset) or raise).encode(encoding)
|
65
71
|
(encoding == Encoding::UTF_16LE || encoding == Encoding::UTF_16BE) ? (byteslice.bytesize / 2) : byteslice.length
|
66
72
|
end
|
67
73
|
|
@@ -81,9 +87,9 @@ module Prism
|
|
81
87
|
|
82
88
|
while left <= right
|
83
89
|
mid = left + (right - left) / 2
|
84
|
-
return mid if offsets[mid] == byte_offset
|
90
|
+
return mid if (offset = offsets[mid]) == byte_offset
|
85
91
|
|
86
|
-
if
|
92
|
+
if offset < byte_offset
|
87
93
|
left = mid + 1
|
88
94
|
else
|
89
95
|
right = mid - 1
|
@@ -108,25 +114,51 @@ module Prism
|
|
108
114
|
# The length of this location in bytes.
|
109
115
|
attr_reader :length
|
110
116
|
|
111
|
-
# The list of comments attached to this location
|
112
|
-
attr_reader :comments
|
113
|
-
|
114
117
|
# Create a new location object with the given source, start byte offset, and
|
115
118
|
# byte length.
|
116
119
|
def initialize(source, start_offset, length)
|
117
120
|
@source = source
|
118
121
|
@start_offset = start_offset
|
119
122
|
@length = length
|
120
|
-
|
123
|
+
|
124
|
+
# These are used to store comments that are associated with this location.
|
125
|
+
# They are initialized to `nil` to save on memory when there are no
|
126
|
+
# comments to be attached and/or the comment-related APIs are not used.
|
127
|
+
@leading_comments = nil
|
128
|
+
@trailing_comments = nil
|
129
|
+
end
|
130
|
+
|
131
|
+
# These are the comments that are associated with this location that exist
|
132
|
+
# before the start of this location.
|
133
|
+
def leading_comments
|
134
|
+
@leading_comments ||= []
|
135
|
+
end
|
136
|
+
|
137
|
+
# Attach a comment to the leading comments of this location.
|
138
|
+
def leading_comment(comment)
|
139
|
+
leading_comments << comment
|
140
|
+
end
|
141
|
+
|
142
|
+
# These are the comments that are associated with this location that exist
|
143
|
+
# after the end of this location.
|
144
|
+
def trailing_comments
|
145
|
+
@trailing_comments ||= []
|
146
|
+
end
|
147
|
+
|
148
|
+
# Attach a comment to the trailing comments of this location.
|
149
|
+
def trailing_comment(comment)
|
150
|
+
trailing_comments << comment
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns all comments that are associated with this location (both leading
|
154
|
+
# and trailing comments).
|
155
|
+
def comments
|
156
|
+
[*@leading_comments, *@trailing_comments]
|
121
157
|
end
|
122
158
|
|
123
159
|
# Create a new location object with the given options.
|
124
|
-
def copy(
|
125
|
-
Location.new(
|
126
|
-
options.fetch(:source) { source },
|
127
|
-
options.fetch(:start_offset) { start_offset },
|
128
|
-
options.fetch(:length) { length }
|
129
|
-
)
|
160
|
+
def copy(source: self.source, start_offset: self.start_offset, length: self.length)
|
161
|
+
Location.new(source, start_offset, length)
|
130
162
|
end
|
131
163
|
|
132
164
|
# Returns a string representation of this location.
|
@@ -230,7 +262,7 @@ module Prism
|
|
230
262
|
|
231
263
|
# Returns true if the given other location is equal to this location.
|
232
264
|
def ==(other)
|
233
|
-
|
265
|
+
Location === other &&
|
234
266
|
other.start_offset == start_offset &&
|
235
267
|
other.end_offset == end_offset
|
236
268
|
end
|
@@ -244,13 +276,6 @@ module Prism
|
|
244
276
|
|
245
277
|
Location.new(source, start_offset, other.end_offset - start_offset)
|
246
278
|
end
|
247
|
-
|
248
|
-
# Returns a null location that does not correspond to a source and points to
|
249
|
-
# the beginning of the file. Useful for when you want a location object but
|
250
|
-
# do not care where it points.
|
251
|
-
def self.null
|
252
|
-
new(nil, 0, 0)
|
253
|
-
end
|
254
279
|
end
|
255
280
|
|
256
281
|
# This represents a comment that was encountered during parsing. It is the
|
@@ -268,6 +293,11 @@ module Prism
|
|
268
293
|
def deconstruct_keys(keys)
|
269
294
|
{ location: location }
|
270
295
|
end
|
296
|
+
|
297
|
+
# Returns the content of the comment by slicing it from the source code.
|
298
|
+
def slice
|
299
|
+
location.slice
|
300
|
+
end
|
271
301
|
end
|
272
302
|
|
273
303
|
# InlineComment objects are the most common. They correspond to comments in
|
@@ -336,6 +366,10 @@ module Prism
|
|
336
366
|
|
337
367
|
# This represents an error that was encountered during parsing.
|
338
368
|
class ParseError
|
369
|
+
# The type of error. This is an _internal_ symbol that is used for
|
370
|
+
# communicating with translation layers. It is not meant to be public API.
|
371
|
+
attr_reader :type
|
372
|
+
|
339
373
|
# The message associated with this error.
|
340
374
|
attr_reader :message
|
341
375
|
|
@@ -346,7 +380,8 @@ module Prism
|
|
346
380
|
attr_reader :level
|
347
381
|
|
348
382
|
# Create a new error object with the given message and location.
|
349
|
-
def initialize(message, location, level)
|
383
|
+
def initialize(type, message, location, level)
|
384
|
+
@type = type
|
350
385
|
@message = message
|
351
386
|
@location = location
|
352
387
|
@level = level
|
@@ -354,17 +389,21 @@ module Prism
|
|
354
389
|
|
355
390
|
# Implement the hash pattern matching interface for ParseError.
|
356
391
|
def deconstruct_keys(keys)
|
357
|
-
{ message: message, location: location, level: level }
|
392
|
+
{ type: type, message: message, location: location, level: level }
|
358
393
|
end
|
359
394
|
|
360
395
|
# Returns a string representation of this error.
|
361
396
|
def inspect
|
362
|
-
"#<Prism::ParseError @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
|
397
|
+
"#<Prism::ParseError @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
|
363
398
|
end
|
364
399
|
end
|
365
400
|
|
366
401
|
# This represents a warning that was encountered during parsing.
|
367
402
|
class ParseWarning
|
403
|
+
# The type of warning. This is an _internal_ symbol that is used for
|
404
|
+
# communicating with translation layers. It is not meant to be public API.
|
405
|
+
attr_reader :type
|
406
|
+
|
368
407
|
# The message associated with this warning.
|
369
408
|
attr_reader :message
|
370
409
|
|
@@ -375,7 +414,8 @@ module Prism
|
|
375
414
|
attr_reader :level
|
376
415
|
|
377
416
|
# Create a new warning object with the given message and location.
|
378
|
-
def initialize(message, location, level)
|
417
|
+
def initialize(type, message, location, level)
|
418
|
+
@type = type
|
379
419
|
@message = message
|
380
420
|
@location = location
|
381
421
|
@level = level
|
@@ -383,12 +423,12 @@ module Prism
|
|
383
423
|
|
384
424
|
# Implement the hash pattern matching interface for ParseWarning.
|
385
425
|
def deconstruct_keys(keys)
|
386
|
-
{ message: message, location: location, level: level }
|
426
|
+
{ type: type, message: message, location: location, level: level }
|
387
427
|
end
|
388
428
|
|
389
429
|
# Returns a string representation of this warning.
|
390
430
|
def inspect
|
391
|
-
"#<Prism::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
|
431
|
+
"#<Prism::ParseWarning @type=#{@type.inspect} @message=#{@message.inspect} @location=#{@location.inspect} @level=#{@level.inspect}>"
|
392
432
|
end
|
393
433
|
end
|
394
434
|
|
@@ -437,6 +477,11 @@ module Prism
|
|
437
477
|
{ value: value, comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
|
438
478
|
end
|
439
479
|
|
480
|
+
# Returns the encoding of the source code that was parsed.
|
481
|
+
def encoding
|
482
|
+
source.encoding
|
483
|
+
end
|
484
|
+
|
440
485
|
# Returns true if there were no errors during parsing and false if there
|
441
486
|
# were.
|
442
487
|
def success?
|
@@ -477,8 +522,9 @@ module Prism
|
|
477
522
|
|
478
523
|
# A Location object representing the location of this token in the source.
|
479
524
|
def location
|
480
|
-
|
481
|
-
|
525
|
+
location = @location
|
526
|
+
return location if location.is_a?(Location)
|
527
|
+
@location = Location.new(source, location >> 32, location & 0xFFFFFFFF)
|
482
528
|
end
|
483
529
|
|
484
530
|
# Implement the pretty print interface for Token.
|
@@ -498,7 +544,7 @@ module Prism
|
|
498
544
|
|
499
545
|
# Returns true if the given other token is equal to this token.
|
500
546
|
def ==(other)
|
501
|
-
|
547
|
+
Token === other &&
|
502
548
|
other.type == type &&
|
503
549
|
other.value == value
|
504
550
|
end
|
data/lib/prism/pattern.rb
CHANGED
@@ -69,7 +69,14 @@ module Prism
|
|
69
69
|
# nodes.
|
70
70
|
def compile
|
71
71
|
result = Prism.parse("case nil\nin #{query}\nend")
|
72
|
-
|
72
|
+
|
73
|
+
case_match_node = result.value.statements.body.last
|
74
|
+
raise CompilationError, case_match_node.inspect unless case_match_node.is_a?(CaseMatchNode)
|
75
|
+
|
76
|
+
in_node = case_match_node.conditions.last
|
77
|
+
raise CompilationError, in_node.inspect unless in_node.is_a?(InNode)
|
78
|
+
|
79
|
+
compile_node(in_node.pattern)
|
73
80
|
end
|
74
81
|
|
75
82
|
# Scan the given node and all of its children for nodes that match the
|
@@ -77,13 +84,13 @@ module Prism
|
|
77
84
|
# matches the pattern. If no block is given, an enumerator will be returned
|
78
85
|
# that will yield each node that matches the pattern.
|
79
86
|
def scan(root)
|
80
|
-
return to_enum(
|
87
|
+
return to_enum(:scan, root) unless block_given?
|
81
88
|
|
82
89
|
@compiled ||= compile
|
83
90
|
queue = [root]
|
84
91
|
|
85
92
|
while (node = queue.shift)
|
86
|
-
yield node if @compiled.call(node)
|
93
|
+
yield node if @compiled.call(node) # steep:ignore
|
87
94
|
queue.concat(node.compact_child_nodes)
|
88
95
|
end
|
89
96
|
end
|
@@ -174,7 +181,12 @@ module Prism
|
|
174
181
|
|
175
182
|
preprocessed =
|
176
183
|
node.elements.to_h do |element|
|
177
|
-
|
184
|
+
key = element.key
|
185
|
+
if key.is_a?(SymbolNode)
|
186
|
+
[key.unescaped.to_sym, compile_node(element.value)]
|
187
|
+
else
|
188
|
+
raise CompilationError, element.inspect
|
189
|
+
end
|
178
190
|
end
|
179
191
|
|
180
192
|
compiled_keywords = ->(other) do
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Polyfill for String#unpack1 with the offset parameter.
|
4
|
+
if String.instance_method(:unpack1).parameters.none? { |_, name| name == :offset }
|
5
|
+
String.prepend(
|
6
|
+
Module.new {
|
7
|
+
def unpack1(format, offset: 0) # :nodoc:
|
8
|
+
offset == 0 ? super(format) : self[offset..].unpack1(format) # steep:ignore
|
9
|
+
end
|
10
|
+
}
|
11
|
+
)
|
12
|
+
end
|