herb 0.7.2-aarch64-linux-gnu → 0.7.4-aarch64-linux-gnu
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/Makefile +2 -0
- data/README.md +1 -1
- data/Rakefile +46 -1
- data/config.yml +714 -0
- data/ext/herb/extconf.rb +2 -1
- data/ext/herb/nodes.c +1 -1
- data/herb.gemspec +3 -0
- data/lib/herb/3.0/herb.so +0 -0
- data/lib/herb/3.1/herb.so +0 -0
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/engine.rb +8 -1
- data/lib/herb/version.rb +1 -1
- data/src/analyze.c +5 -9
- data/src/analyze_helpers.c +17 -6
- data/src/herb.c +2 -2
- data/src/include/parser.h +2 -2
- data/src/include/pretty_print.h +1 -1
- data/src/include/version.h +1 -1
- data/src/parser.c +3 -2
- data/src/pretty_print.c +1 -1
- data/templates/ext/herb/error_helpers.c.erb +85 -0
- data/templates/ext/herb/error_helpers.h.erb +12 -0
- data/templates/ext/herb/nodes.c.erb +90 -0
- data/templates/ext/herb/nodes.h.erb +9 -0
- data/templates/javascript/packages/core/src/errors.ts.erb +193 -0
- data/templates/javascript/packages/core/src/node-type-guards.ts.erb +325 -0
- data/templates/javascript/packages/core/src/nodes.ts.erb +414 -0
- data/templates/javascript/packages/core/src/visitor.ts.erb +29 -0
- data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +113 -0
- data/templates/javascript/packages/node/extension/error_helpers.h.erb +17 -0
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +111 -0
- data/templates/javascript/packages/node/extension/nodes.h.erb +17 -0
- data/templates/lib/herb/ast/nodes.rb.erb +117 -0
- data/templates/lib/herb/errors.rb.erb +106 -0
- data/templates/lib/herb/visitor.rb.erb +28 -0
- data/templates/sig/serialized_ast_errors.rbs.erb +10 -0
- data/templates/sig/serialized_ast_nodes.rbs.erb +10 -0
- data/templates/src/ast_nodes.c.erb +145 -0
- data/templates/src/ast_pretty_print.c.erb +97 -0
- data/templates/src/errors.c.erb +245 -0
- data/templates/src/include/ast_nodes.h.erb +46 -0
- data/templates/src/include/ast_pretty_print.h.erb +14 -0
- data/templates/src/include/errors.h.erb +58 -0
- data/templates/src/visitor.c.erb +47 -0
- data/templates/template.rb +406 -0
- data/templates/wasm/error_helpers.cpp.erb +93 -0
- data/templates/wasm/error_helpers.h.erb +15 -0
- data/templates/wasm/nodes.cpp.erb +79 -0
- data/templates/wasm/nodes.h.erb +15 -0
- data/vendor/prism/Rakefile +75 -0
- data/vendor/prism/config.yml +4713 -0
- data/vendor/prism/include/prism/ast.h +8190 -0
- data/vendor/prism/include/prism/defines.h +260 -0
- data/vendor/prism/include/prism/diagnostic.h +455 -0
- data/vendor/prism/include/prism/encoding.h +283 -0
- data/vendor/prism/include/prism/node.h +129 -0
- data/vendor/prism/include/prism/options.h +482 -0
- data/vendor/prism/include/prism/pack.h +163 -0
- data/vendor/prism/include/prism/parser.h +933 -0
- data/vendor/prism/include/prism/prettyprint.h +34 -0
- data/vendor/prism/include/prism/regexp.h +43 -0
- data/vendor/prism/include/prism/static_literals.h +121 -0
- data/vendor/prism/include/prism/util/pm_buffer.h +236 -0
- data/vendor/prism/include/prism/util/pm_char.h +204 -0
- data/vendor/prism/include/prism/util/pm_constant_pool.h +218 -0
- data/vendor/prism/include/prism/util/pm_integer.h +130 -0
- data/vendor/prism/include/prism/util/pm_list.h +103 -0
- data/vendor/prism/include/prism/util/pm_memchr.h +29 -0
- data/vendor/prism/include/prism/util/pm_newline_list.h +113 -0
- data/vendor/prism/include/prism/util/pm_string.h +200 -0
- data/vendor/prism/include/prism/util/pm_strncasecmp.h +32 -0
- data/vendor/prism/include/prism/util/pm_strpbrk.h +46 -0
- data/vendor/prism/include/prism/version.h +29 -0
- data/vendor/prism/include/prism.h +408 -0
- data/vendor/prism/src/diagnostic.c +848 -0
- data/vendor/prism/src/encoding.c +5235 -0
- data/vendor/prism/src/node.c +8676 -0
- data/vendor/prism/src/options.c +328 -0
- data/vendor/prism/src/pack.c +509 -0
- data/vendor/prism/src/prettyprint.c +8941 -0
- data/vendor/prism/src/prism.c +23302 -0
- data/vendor/prism/src/regexp.c +790 -0
- data/vendor/prism/src/serialize.c +2268 -0
- data/vendor/prism/src/static_literals.c +617 -0
- data/vendor/prism/src/token_type.c +703 -0
- data/vendor/prism/src/util/pm_buffer.c +357 -0
- data/vendor/prism/src/util/pm_char.c +318 -0
- data/vendor/prism/src/util/pm_constant_pool.c +342 -0
- data/vendor/prism/src/util/pm_integer.c +670 -0
- data/vendor/prism/src/util/pm_list.c +49 -0
- data/vendor/prism/src/util/pm_memchr.c +35 -0
- data/vendor/prism/src/util/pm_newline_list.c +125 -0
- data/vendor/prism/src/util/pm_string.c +383 -0
- data/vendor/prism/src/util/pm_strncasecmp.c +36 -0
- data/vendor/prism/src/util/pm_strpbrk.c +206 -0
- data/vendor/prism/templates/ext/prism/api_node.c.erb +282 -0
- data/vendor/prism/templates/include/prism/ast.h.erb +226 -0
- data/vendor/prism/templates/include/prism/diagnostic.h.erb +130 -0
- data/vendor/prism/templates/java/org/prism/AbstractNodeVisitor.java.erb +22 -0
- data/vendor/prism/templates/java/org/prism/Loader.java.erb +434 -0
- data/vendor/prism/templates/java/org/prism/Nodes.java.erb +403 -0
- data/vendor/prism/templates/javascript/src/deserialize.js.erb +448 -0
- data/vendor/prism/templates/javascript/src/nodes.js.erb +197 -0
- data/vendor/prism/templates/javascript/src/visitor.js.erb +78 -0
- data/vendor/prism/templates/lib/prism/compiler.rb.erb +43 -0
- data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +103 -0
- data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +189 -0
- data/vendor/prism/templates/lib/prism/dsl.rb.erb +133 -0
- data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +131 -0
- data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +19 -0
- data/vendor/prism/templates/lib/prism/node.rb.erb +515 -0
- data/vendor/prism/templates/lib/prism/reflection.rb.erb +136 -0
- data/vendor/prism/templates/lib/prism/serialize.rb.erb +602 -0
- data/vendor/prism/templates/lib/prism/visitor.rb.erb +55 -0
- data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +68 -0
- data/vendor/prism/templates/rbi/prism/node.rbi.erb +164 -0
- data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +18 -0
- data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +45 -0
- data/vendor/prism/templates/sig/prism/dsl.rbs.erb +31 -0
- data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +7 -0
- data/vendor/prism/templates/sig/prism/node.rbs.erb +132 -0
- data/vendor/prism/templates/sig/prism/visitor.rbs.erb +17 -0
- data/vendor/prism/templates/sig/prism.rbs.erb +89 -0
- data/vendor/prism/templates/src/diagnostic.c.erb +523 -0
- data/vendor/prism/templates/src/node.c.erb +333 -0
- data/vendor/prism/templates/src/prettyprint.c.erb +166 -0
- data/vendor/prism/templates/src/serialize.c.erb +406 -0
- data/vendor/prism/templates/src/token_type.c.erb +369 -0
- data/vendor/prism/templates/template.rb +689 -0
- metadata +112 -2
@@ -0,0 +1,515 @@
|
|
1
|
+
module Prism
|
2
|
+
# This represents a node in the tree. It is the parent class of all of the
|
3
|
+
# various node types.
|
4
|
+
class Node
|
5
|
+
# A pointer to the source that this node was created from.
|
6
|
+
attr_reader :source
|
7
|
+
private :source
|
8
|
+
|
9
|
+
# A unique identifier for this node. This is used in a very specific
|
10
|
+
# use case where you want to keep around a reference to a node without
|
11
|
+
# having to keep around the syntax tree in memory. This unique identifier
|
12
|
+
# will be consistent across multiple parses of the same source code.
|
13
|
+
attr_reader :node_id
|
14
|
+
|
15
|
+
# Save this node using a saved source so that it can be retrieved later.
|
16
|
+
def save(repository)
|
17
|
+
repository.enter(node_id, :itself)
|
18
|
+
end
|
19
|
+
|
20
|
+
# A Location instance that represents the location of this node in the
|
21
|
+
# source.
|
22
|
+
def location
|
23
|
+
location = @location
|
24
|
+
return location if location.is_a?(Location)
|
25
|
+
@location = Location.new(source, location >> 32, location & 0xFFFFFFFF)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Save the location using a saved source so that it can be retrieved later.
|
29
|
+
def save_location(repository)
|
30
|
+
repository.enter(node_id, :location)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Delegates to the start_line of the associated location object.
|
34
|
+
def start_line
|
35
|
+
location.start_line
|
36
|
+
end
|
37
|
+
|
38
|
+
# Delegates to the end_line of the associated location object.
|
39
|
+
def end_line
|
40
|
+
location.end_line
|
41
|
+
end
|
42
|
+
|
43
|
+
# The start offset of the node in the source. This method is effectively a
|
44
|
+
# delegate method to the location object.
|
45
|
+
def start_offset
|
46
|
+
location = @location
|
47
|
+
location.is_a?(Location) ? location.start_offset : location >> 32
|
48
|
+
end
|
49
|
+
|
50
|
+
# The end offset of the node in the source. This method is effectively a
|
51
|
+
# delegate method to the location object.
|
52
|
+
def end_offset
|
53
|
+
location = @location
|
54
|
+
location.is_a?(Location) ? location.end_offset : ((location >> 32) + (location & 0xFFFFFFFF))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Delegates to the start_character_offset of the associated location object.
|
58
|
+
def start_character_offset
|
59
|
+
location.start_character_offset
|
60
|
+
end
|
61
|
+
|
62
|
+
# Delegates to the end_character_offset of the associated location object.
|
63
|
+
def end_character_offset
|
64
|
+
location.end_character_offset
|
65
|
+
end
|
66
|
+
|
67
|
+
# Delegates to the cached_start_code_units_offset of the associated location
|
68
|
+
# object.
|
69
|
+
def cached_start_code_units_offset(cache)
|
70
|
+
location.cached_start_code_units_offset(cache)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Delegates to the cached_end_code_units_offset of the associated location
|
74
|
+
# object.
|
75
|
+
def cached_end_code_units_offset(cache)
|
76
|
+
location.cached_end_code_units_offset(cache)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Delegates to the start_column of the associated location object.
|
80
|
+
def start_column
|
81
|
+
location.start_column
|
82
|
+
end
|
83
|
+
|
84
|
+
# Delegates to the end_column of the associated location object.
|
85
|
+
def end_column
|
86
|
+
location.end_column
|
87
|
+
end
|
88
|
+
|
89
|
+
# Delegates to the start_character_column of the associated location object.
|
90
|
+
def start_character_column
|
91
|
+
location.start_character_column
|
92
|
+
end
|
93
|
+
|
94
|
+
# Delegates to the end_character_column of the associated location object.
|
95
|
+
def end_character_column
|
96
|
+
location.end_character_column
|
97
|
+
end
|
98
|
+
|
99
|
+
# Delegates to the cached_start_code_units_column of the associated location
|
100
|
+
# object.
|
101
|
+
def cached_start_code_units_column(cache)
|
102
|
+
location.cached_start_code_units_column(cache)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Delegates to the cached_end_code_units_column of the associated location
|
106
|
+
# object.
|
107
|
+
def cached_end_code_units_column(cache)
|
108
|
+
location.cached_end_code_units_column(cache)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Delegates to the leading_comments of the associated location object.
|
112
|
+
def leading_comments
|
113
|
+
location.leading_comments
|
114
|
+
end
|
115
|
+
|
116
|
+
# Delegates to the trailing_comments of the associated location object.
|
117
|
+
def trailing_comments
|
118
|
+
location.trailing_comments
|
119
|
+
end
|
120
|
+
|
121
|
+
# Delegates to the comments of the associated location object.
|
122
|
+
def comments
|
123
|
+
location.comments
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns all of the lines of the source code associated with this node.
|
127
|
+
def source_lines
|
128
|
+
location.source_lines
|
129
|
+
end
|
130
|
+
|
131
|
+
# An alias for source_lines, used to mimic the API from
|
132
|
+
# RubyVM::AbstractSyntaxTree to make it easier to migrate.
|
133
|
+
alias script_lines source_lines
|
134
|
+
|
135
|
+
# Slice the location of the node from the source.
|
136
|
+
def slice
|
137
|
+
location.slice
|
138
|
+
end
|
139
|
+
|
140
|
+
# Slice the location of the node from the source, starting at the beginning
|
141
|
+
# of the line that the location starts on, ending at the end of the line
|
142
|
+
# that the location ends on.
|
143
|
+
def slice_lines
|
144
|
+
location.slice_lines
|
145
|
+
end
|
146
|
+
|
147
|
+
# An bitset of flags for this node. There are certain flags that are common
|
148
|
+
# for all nodes, and then some nodes have specific flags.
|
149
|
+
attr_reader :flags
|
150
|
+
protected :flags
|
151
|
+
|
152
|
+
# Returns true if the node has the newline flag set.
|
153
|
+
def newline?
|
154
|
+
flags.anybits?(NodeFlags::NEWLINE)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns true if the node has the static literal flag set.
|
158
|
+
def static_literal?
|
159
|
+
flags.anybits?(NodeFlags::STATIC_LITERAL)
|
160
|
+
end
|
161
|
+
|
162
|
+
# Similar to inspect, but respects the current level of indentation given by
|
163
|
+
# the pretty print object.
|
164
|
+
def pretty_print(q)
|
165
|
+
q.seplist(inspect.chomp.each_line, -> { q.breakable }) do |line|
|
166
|
+
q.text(line.chomp)
|
167
|
+
end
|
168
|
+
q.current_group.break
|
169
|
+
end
|
170
|
+
|
171
|
+
# Convert this node into a graphviz dot graph string.
|
172
|
+
def to_dot
|
173
|
+
# @type self: node
|
174
|
+
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns a list of nodes that are descendants of this node that contain the
|
178
|
+
# given line and column. This is useful for locating a node that is selected
|
179
|
+
# based on the line and column of the source code.
|
180
|
+
#
|
181
|
+
# Important to note is that the column given to this method should be in
|
182
|
+
# bytes, as opposed to characters or code units.
|
183
|
+
def tunnel(line, column)
|
184
|
+
queue = [self] #: Array[Prism::node]
|
185
|
+
result = [] #: Array[Prism::node]
|
186
|
+
|
187
|
+
while (node = queue.shift)
|
188
|
+
result << node
|
189
|
+
|
190
|
+
node.compact_child_nodes.each do |child_node|
|
191
|
+
child_location = child_node.location
|
192
|
+
|
193
|
+
start_line = child_location.start_line
|
194
|
+
end_line = child_location.end_line
|
195
|
+
|
196
|
+
if start_line == end_line
|
197
|
+
if line == start_line && column >= child_location.start_column && column < child_location.end_column
|
198
|
+
queue << child_node
|
199
|
+
break
|
200
|
+
end
|
201
|
+
elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column)
|
202
|
+
queue << child_node
|
203
|
+
break
|
204
|
+
elsif line > start_line && line < end_line
|
205
|
+
queue << child_node
|
206
|
+
break
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
result
|
212
|
+
end
|
213
|
+
|
214
|
+
# Returns the first node that matches the given block when visited in a
|
215
|
+
# depth-first search. This is useful for finding a node that matches a
|
216
|
+
# particular condition.
|
217
|
+
#
|
218
|
+
# node.breadth_first_search { |node| node.node_id == node_id }
|
219
|
+
#
|
220
|
+
def breadth_first_search(&block)
|
221
|
+
queue = [self] #: Array[Prism::node]
|
222
|
+
|
223
|
+
while (node = queue.shift)
|
224
|
+
return node if yield node
|
225
|
+
queue.concat(node.compact_child_nodes)
|
226
|
+
end
|
227
|
+
|
228
|
+
nil
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns a list of the fields that exist for this node class. Fields
|
232
|
+
# describe the structure of the node. This kind of reflection is useful for
|
233
|
+
# things like recursively visiting each node _and_ field in the tree.
|
234
|
+
def self.fields
|
235
|
+
# This method should only be called on subclasses of Node, not Node
|
236
|
+
# itself.
|
237
|
+
raise NoMethodError, "undefined method `fields' for #{inspect}" if self == Node
|
238
|
+
|
239
|
+
Reflection.fields_for(self)
|
240
|
+
end
|
241
|
+
|
242
|
+
# --------------------------------------------------------------------------
|
243
|
+
# :section: Node interface
|
244
|
+
# These methods are effectively abstract methods that must be implemented by
|
245
|
+
# the various subclasses of Node. They are here to make it easier to work
|
246
|
+
# with typecheckers.
|
247
|
+
# --------------------------------------------------------------------------
|
248
|
+
|
249
|
+
# Accepts a visitor and calls back into the specialized visit function.
|
250
|
+
def accept(visitor)
|
251
|
+
raise NoMethodError, "undefined method `accept' for #{inspect}"
|
252
|
+
end
|
253
|
+
|
254
|
+
# Returns an array of child nodes, including `nil`s in the place of optional
|
255
|
+
# nodes that were not present.
|
256
|
+
def child_nodes
|
257
|
+
raise NoMethodError, "undefined method `child_nodes' for #{inspect}"
|
258
|
+
end
|
259
|
+
|
260
|
+
alias deconstruct child_nodes
|
261
|
+
|
262
|
+
# Returns an array of child nodes, excluding any `nil`s in the place of
|
263
|
+
# optional nodes that were not present.
|
264
|
+
def compact_child_nodes
|
265
|
+
raise NoMethodError, "undefined method `compact_child_nodes' for #{inspect}"
|
266
|
+
end
|
267
|
+
|
268
|
+
# Returns an array of child nodes and locations that could potentially have
|
269
|
+
# comments attached to them.
|
270
|
+
def comment_targets
|
271
|
+
raise NoMethodError, "undefined method `comment_targets' for #{inspect}"
|
272
|
+
end
|
273
|
+
|
274
|
+
# Returns a string representation of the node.
|
275
|
+
def inspect
|
276
|
+
raise NoMethodError, "undefined method `inspect' for #{inspect}"
|
277
|
+
end
|
278
|
+
|
279
|
+
# Sometimes you want to check an instance of a node against a list of
|
280
|
+
# classes to see what kind of behavior to perform. Usually this is done by
|
281
|
+
# calling `[cls1, cls2].include?(node.class)` or putting the node into a
|
282
|
+
# case statement and doing `case node; when cls1; when cls2; end`. Both of
|
283
|
+
# these approaches are relatively slow because of the constant lookups,
|
284
|
+
# method calls, and/or array allocations.
|
285
|
+
#
|
286
|
+
# Instead, you can call #type, which will return to you a symbol that you
|
287
|
+
# can use for comparison. This is faster than the other approaches because
|
288
|
+
# it uses a single integer comparison, but also because if you're on CRuby
|
289
|
+
# you can take advantage of the fact that case statements with all symbol
|
290
|
+
# keys will use a jump table.
|
291
|
+
def type
|
292
|
+
raise NoMethodError, "undefined method `type' for #{inspect}"
|
293
|
+
end
|
294
|
+
|
295
|
+
# Similar to #type, this method returns a symbol that you can use for
|
296
|
+
# splitting on the type of the node without having to do a long === chain.
|
297
|
+
# Note that like #type, it will still be slower than using == for a single
|
298
|
+
# class, but should be faster in a case statement or an array comparison.
|
299
|
+
def self.type
|
300
|
+
raise NoMethodError, "undefined method `type' for #{inspect}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
<%- nodes.each do |node| -%>
|
304
|
+
|
305
|
+
<%- node.each_comment_line do |line| -%>
|
306
|
+
#<%= line %>
|
307
|
+
<%- end -%>
|
308
|
+
class <%= node.name -%> < Node
|
309
|
+
# Initialize a new <%= node.name %> node.
|
310
|
+
def initialize(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
|
311
|
+
@source = source
|
312
|
+
@node_id = node_id
|
313
|
+
@location = location
|
314
|
+
@flags = flags
|
315
|
+
<%- node.fields.each do |field| -%>
|
316
|
+
<%- if Prism::Template::CHECK_FIELD_KIND && field.respond_to?(:check_field_kind) -%>
|
317
|
+
raise "<%= node.name %>#<%= field.name %> was of unexpected type:\n#{<%= field.name %>.inspect}" unless <%= field.check_field_kind %>
|
318
|
+
<%- end -%>
|
319
|
+
@<%= field.name %> = <%= field.name %>
|
320
|
+
<%- end -%>
|
321
|
+
end
|
322
|
+
|
323
|
+
# def accept: (Visitor visitor) -> void
|
324
|
+
def accept(visitor)
|
325
|
+
visitor.visit_<%= node.human %>(self)
|
326
|
+
end
|
327
|
+
|
328
|
+
# def child_nodes: () -> Array[Node?]
|
329
|
+
def child_nodes
|
330
|
+
[<%= node.fields.map { |field|
|
331
|
+
case field
|
332
|
+
when Prism::Template::NodeField, Prism::Template::OptionalNodeField then field.name
|
333
|
+
when Prism::Template::NodeListField then "*#{field.name}"
|
334
|
+
end
|
335
|
+
}.compact.join(", ") %>]
|
336
|
+
end
|
337
|
+
|
338
|
+
# def compact_child_nodes: () -> Array[Node]
|
339
|
+
def compact_child_nodes
|
340
|
+
<%- if node.fields.any? { |field| field.is_a?(Prism::Template::OptionalNodeField) } -%>
|
341
|
+
compact = [] #: Array[Prism::node]
|
342
|
+
<%- node.fields.each do |field| -%>
|
343
|
+
<%- case field -%>
|
344
|
+
<%- when Prism::Template::NodeField -%>
|
345
|
+
compact << <%= field.name %>
|
346
|
+
<%- when Prism::Template::OptionalNodeField -%>
|
347
|
+
compact << <%= field.name %> if <%= field.name %>
|
348
|
+
<%- when Prism::Template::NodeListField -%>
|
349
|
+
compact.concat(<%= field.name %>)
|
350
|
+
<%- end -%>
|
351
|
+
<%- end -%>
|
352
|
+
compact
|
353
|
+
<%- else -%>
|
354
|
+
[<%= node.fields.map { |field|
|
355
|
+
case field
|
356
|
+
when Prism::Template::NodeField then field.name
|
357
|
+
when Prism::Template::NodeListField then "*#{field.name}"
|
358
|
+
end
|
359
|
+
}.compact.join(", ") %>]
|
360
|
+
<%- end -%>
|
361
|
+
end
|
362
|
+
|
363
|
+
# def comment_targets: () -> Array[Node | Location]
|
364
|
+
def comment_targets
|
365
|
+
[<%= node.fields.map { |field|
|
366
|
+
case field
|
367
|
+
when Prism::Template::NodeField, Prism::Template::LocationField then field.name
|
368
|
+
when Prism::Template::OptionalNodeField, Prism::Template::NodeListField, Prism::Template::OptionalLocationField then "*#{field.name}"
|
369
|
+
end
|
370
|
+
}.compact.join(", ") %>] #: Array[Prism::node | Location]
|
371
|
+
end
|
372
|
+
|
373
|
+
# def copy: (<%= (["?node_id: Integer", "?location: Location", "?flags: Integer"] + node.fields.map { |field| "?#{field.name}: #{field.rbs_class}" }).join(", ") %>) -> <%= node.name %>
|
374
|
+
def copy(<%= (["node_id", "location", "flags"] + node.fields.map(&:name)).map { |field| "#{field}: self.#{field}" }.join(", ") %>)
|
375
|
+
<%= node.name %>.new(<%= ["source", "node_id", "location", "flags", *node.fields.map(&:name)].join(", ") %>)
|
376
|
+
end
|
377
|
+
|
378
|
+
# def deconstruct: () -> Array[Node?]
|
379
|
+
alias deconstruct child_nodes
|
380
|
+
|
381
|
+
# def deconstruct_keys: (Array[Symbol] keys) -> { <%= (["node_id: Integer", "location: Location"] + node.fields.map { |field| "#{field.name}: #{field.rbs_class}" }).join(", ") %> }
|
382
|
+
def deconstruct_keys(keys)
|
383
|
+
{ <%= (["node_id: node_id", "location: location"] + node.fields.map { |field| "#{field.name}: #{field.name}" }).join(", ") %> }
|
384
|
+
end
|
385
|
+
<%- if (node_flags = node.flags) -%>
|
386
|
+
<%- node_flags.values.each do |value| -%>
|
387
|
+
|
388
|
+
# def <%= value.name.downcase %>?: () -> bool
|
389
|
+
def <%= value.name.downcase %>?
|
390
|
+
flags.anybits?(<%= node_flags.name %>::<%= value.name %>)
|
391
|
+
end
|
392
|
+
<%- end -%>
|
393
|
+
<%- end -%>
|
394
|
+
<%- node.fields.each do |field| -%>
|
395
|
+
|
396
|
+
<%- if field.comment.nil? -%>
|
397
|
+
# attr_reader <%= field.name %>: <%= field.rbs_class %>
|
398
|
+
<%- else -%>
|
399
|
+
<%- field.each_comment_line do |line| -%>
|
400
|
+
#<%= line %>
|
401
|
+
<%- end -%>
|
402
|
+
<%- end -%>
|
403
|
+
<%- case field -%>
|
404
|
+
<%- when Prism::Template::LocationField -%>
|
405
|
+
def <%= field.name %>
|
406
|
+
location = @<%= field.name %>
|
407
|
+
return location if location.is_a?(Location)
|
408
|
+
@<%= field.name %> = Location.new(source, location >> 32, location & 0xFFFFFFFF)
|
409
|
+
end
|
410
|
+
|
411
|
+
# Save the <%= field.name %> location using the given saved source so that
|
412
|
+
# it can be retrieved later.
|
413
|
+
def save_<%= field.name %>(repository)
|
414
|
+
repository.enter(node_id, :<%= field.name %>)
|
415
|
+
end
|
416
|
+
<%- when Prism::Template::OptionalLocationField -%>
|
417
|
+
def <%= field.name %>
|
418
|
+
location = @<%= field.name %>
|
419
|
+
case location
|
420
|
+
when nil
|
421
|
+
nil
|
422
|
+
when Location
|
423
|
+
location
|
424
|
+
else
|
425
|
+
@<%= field.name %> = Location.new(source, location >> 32, location & 0xFFFFFFFF)
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
# Save the <%= field.name %> location using the given saved source so that
|
430
|
+
# it can be retrieved later.
|
431
|
+
def save_<%= field.name %>(repository)
|
432
|
+
repository.enter(node_id, :<%= field.name %>) unless @<%= field.name %>.nil?
|
433
|
+
end
|
434
|
+
<%- else -%>
|
435
|
+
attr_reader :<%= field.name %>
|
436
|
+
<%- end -%>
|
437
|
+
<%- end -%>
|
438
|
+
<%- node.fields.each do |field| -%>
|
439
|
+
<%- case field -%>
|
440
|
+
<%- when Prism::Template::LocationField -%>
|
441
|
+
<%- raise unless field.name.end_with?("_loc") -%>
|
442
|
+
<%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>
|
443
|
+
|
444
|
+
# def <%= field.name.delete_suffix("_loc") %>: () -> String
|
445
|
+
def <%= field.name.delete_suffix("_loc") %>
|
446
|
+
<%= field.name %>.slice
|
447
|
+
end
|
448
|
+
<%- when Prism::Template::OptionalLocationField -%>
|
449
|
+
<%- raise unless field.name.end_with?("_loc") -%>
|
450
|
+
<%- next if node.fields.any? { |other| other.name == field.name.delete_suffix("_loc") } -%>
|
451
|
+
|
452
|
+
# def <%= field.name.delete_suffix("_loc") %>: () -> String?
|
453
|
+
def <%= field.name.delete_suffix("_loc") %>
|
454
|
+
<%= field.name %>&.slice
|
455
|
+
end
|
456
|
+
<%- end -%>
|
457
|
+
<%- end -%>
|
458
|
+
|
459
|
+
# def inspect -> String
|
460
|
+
def inspect
|
461
|
+
InspectVisitor.compose(self)
|
462
|
+
end
|
463
|
+
|
464
|
+
# Return a symbol representation of this node type. See `Node#type`.
|
465
|
+
def type
|
466
|
+
:<%= node.human %>
|
467
|
+
end
|
468
|
+
|
469
|
+
# Return a symbol representation of this node type. See `Node::type`.
|
470
|
+
def self.type
|
471
|
+
:<%= node.human %>
|
472
|
+
end
|
473
|
+
|
474
|
+
# Implements case-equality for the node. This is effectively == but without
|
475
|
+
# comparing the value of locations. Locations are checked only for presence.
|
476
|
+
def ===(other)
|
477
|
+
other.is_a?(<%= node.name %>)<%= " &&" if (fields = [*node.flags, *node.fields]).any? %>
|
478
|
+
<%- fields.each_with_index do |field, index| -%>
|
479
|
+
<%- if field.is_a?(Prism::Template::LocationField) || field.is_a?(Prism::Template::OptionalLocationField) -%>
|
480
|
+
(<%= field.name %>.nil? == other.<%= field.name %>.nil?)<%= " &&" if index != fields.length - 1 %>
|
481
|
+
<%- elsif field.is_a?(Prism::Template::NodeListField) || field.is_a?(Prism::Template::ConstantListField) -%>
|
482
|
+
(<%= field.name %>.length == other.<%= field.name %>.length) &&
|
483
|
+
<%= field.name %>.zip(other.<%= field.name %>).all? { |left, right| left === right }<%= " &&" if index != fields.length - 1 %>
|
484
|
+
<%- elsif field.is_a?(Prism::Template::Flags) -%>
|
485
|
+
(flags === other.flags)<%= " &&" if index != fields.length - 1 %>
|
486
|
+
<%- else -%>
|
487
|
+
(<%= field.name %> === other.<%= field.name %>)<%= " &&" if index != fields.length - 1 %>
|
488
|
+
<%- end -%>
|
489
|
+
<%- end -%>
|
490
|
+
end
|
491
|
+
end
|
492
|
+
<%- end -%>
|
493
|
+
<%- flags.each do |flag| -%>
|
494
|
+
|
495
|
+
# <%= flag.comment %>
|
496
|
+
module <%= flag.name %>
|
497
|
+
<%- flag.values.each_with_index do |value, index| -%>
|
498
|
+
# <%= value.comment %>
|
499
|
+
<%= value.name %> = 1 << <%= index + Prism::Template::COMMON_FLAGS_COUNT %>
|
500
|
+
<%= "\n" if value != flag.values.last -%>
|
501
|
+
<%- end -%>
|
502
|
+
end
|
503
|
+
<%- end -%>
|
504
|
+
|
505
|
+
# The flags that are common to all nodes.
|
506
|
+
module NodeFlags
|
507
|
+
# A flag to indicate that the node is a candidate to emit a :line event
|
508
|
+
# through tracepoint when compiled.
|
509
|
+
NEWLINE = 1
|
510
|
+
|
511
|
+
# A flag to indicate that the value that the node represents is a value that
|
512
|
+
# can be determined at parse-time.
|
513
|
+
STATIC_LITERAL = 2
|
514
|
+
end
|
515
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Prism
|
2
|
+
# The Reflection module provides the ability to reflect on the structure of
|
3
|
+
# the syntax tree itself, as opposed to looking at a single syntax tree. This
|
4
|
+
# is useful in metaprogramming contexts.
|
5
|
+
module Reflection
|
6
|
+
# A field represents a single piece of data on a node. It is the base class
|
7
|
+
# for all other field types.
|
8
|
+
class Field
|
9
|
+
# The name of the field.
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# Initializes the field with the given name.
|
13
|
+
def initialize(name)
|
14
|
+
@name = name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# A node field represents a single child node in the syntax tree. It
|
19
|
+
# resolves to a Prism::Node in Ruby.
|
20
|
+
class NodeField < Field
|
21
|
+
end
|
22
|
+
|
23
|
+
# An optional node field represents a single child node in the syntax tree
|
24
|
+
# that may or may not be present. It resolves to either a Prism::Node or nil
|
25
|
+
# in Ruby.
|
26
|
+
class OptionalNodeField < Field
|
27
|
+
end
|
28
|
+
|
29
|
+
# A node list field represents a list of child nodes in the syntax tree. It
|
30
|
+
# resolves to an array of Prism::Node instances in Ruby.
|
31
|
+
class NodeListField < Field
|
32
|
+
end
|
33
|
+
|
34
|
+
# A constant field represents a constant value on a node. Effectively, it
|
35
|
+
# represents an identifier found within the source. It resolves to a symbol
|
36
|
+
# in Ruby.
|
37
|
+
class ConstantField < Field
|
38
|
+
end
|
39
|
+
|
40
|
+
# An optional constant field represents a constant value on a node that may
|
41
|
+
# or may not be present. It resolves to either a symbol or nil in Ruby.
|
42
|
+
class OptionalConstantField < Field
|
43
|
+
end
|
44
|
+
|
45
|
+
# A constant list field represents a list of constant values on a node. It
|
46
|
+
# resolves to an array of symbols in Ruby.
|
47
|
+
class ConstantListField < Field
|
48
|
+
end
|
49
|
+
|
50
|
+
# A string field represents a string value on a node. It almost always
|
51
|
+
# represents the unescaped value of a string-like literal. It resolves to a
|
52
|
+
# string in Ruby.
|
53
|
+
class StringField < Field
|
54
|
+
end
|
55
|
+
|
56
|
+
# A location field represents the location of some part of the node in the
|
57
|
+
# source code. For example, the location of a keyword or an operator. It
|
58
|
+
# resolves to a Prism::Location in Ruby.
|
59
|
+
class LocationField < Field
|
60
|
+
end
|
61
|
+
|
62
|
+
# An optional location field represents the location of some part of the
|
63
|
+
# node in the source code that may or may not be present. It resolves to
|
64
|
+
# either a Prism::Location or nil in Ruby.
|
65
|
+
class OptionalLocationField < Field
|
66
|
+
end
|
67
|
+
|
68
|
+
# An integer field represents an integer value. It is used to represent the
|
69
|
+
# value of an integer literal, the depth of local variables, and the number
|
70
|
+
# of a numbered reference. It resolves to an Integer in Ruby.
|
71
|
+
class IntegerField < Field
|
72
|
+
end
|
73
|
+
|
74
|
+
# A float field represents a double-precision floating point value. It is
|
75
|
+
# used exclusively to represent the value of a floating point literal. It
|
76
|
+
# resolves to a Float in Ruby.
|
77
|
+
class FloatField < Field
|
78
|
+
end
|
79
|
+
|
80
|
+
# A flags field represents a bitset of flags on a node. It resolves to an
|
81
|
+
# integer in Ruby. Note that the flags cannot be accessed directly on the
|
82
|
+
# node because the integer is kept private. Instead, the various flags in
|
83
|
+
# the bitset should be accessed through their query methods.
|
84
|
+
class FlagsField < Field
|
85
|
+
# The names of the flags in the bitset.
|
86
|
+
attr_reader :flags
|
87
|
+
|
88
|
+
# Initializes the flags field with the given name and flags.
|
89
|
+
def initialize(name, flags)
|
90
|
+
super(name)
|
91
|
+
@flags = flags
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the fields for the given node.
|
96
|
+
def self.fields_for(node)
|
97
|
+
case node.type
|
98
|
+
<%- nodes.each do |node| -%>
|
99
|
+
when :<%= node.human %>
|
100
|
+
[<%= [*node.flags, *node.fields].map { |field|
|
101
|
+
case field
|
102
|
+
when Prism::Template::NodeField
|
103
|
+
"NodeField.new(:#{field.name})"
|
104
|
+
when Prism::Template::OptionalNodeField
|
105
|
+
"OptionalNodeField.new(:#{field.name})"
|
106
|
+
when Prism::Template::NodeListField
|
107
|
+
"NodeListField.new(:#{field.name})"
|
108
|
+
when Prism::Template::ConstantField
|
109
|
+
"ConstantField.new(:#{field.name})"
|
110
|
+
when Prism::Template::OptionalConstantField
|
111
|
+
"OptionalConstantField.new(:#{field.name})"
|
112
|
+
when Prism::Template::ConstantListField
|
113
|
+
"ConstantListField.new(:#{field.name})"
|
114
|
+
when Prism::Template::StringField
|
115
|
+
"StringField.new(:#{field.name})"
|
116
|
+
when Prism::Template::LocationField
|
117
|
+
"LocationField.new(:#{field.name})"
|
118
|
+
when Prism::Template::OptionalLocationField
|
119
|
+
"OptionalLocationField.new(:#{field.name})"
|
120
|
+
when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField
|
121
|
+
"IntegerField.new(:#{field.name})"
|
122
|
+
when Prism::Template::DoubleField
|
123
|
+
"FloatField.new(:#{field.name})"
|
124
|
+
when Prism::Template::Flags
|
125
|
+
"FlagsField.new(:flags, [#{field.values.map { |value| ":#{value.name.downcase}?" }.join(", ")}])"
|
126
|
+
else
|
127
|
+
raise field.class.name
|
128
|
+
end
|
129
|
+
}.join(", ") %>]
|
130
|
+
<%- end -%>
|
131
|
+
else
|
132
|
+
raise "Unknown node type: #{node.type.inspect}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|