herb 0.7.2-x86_64-linux-gnu → 0.7.4-x86_64-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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +2 -0
  3. data/README.md +1 -1
  4. data/Rakefile +46 -1
  5. data/config.yml +714 -0
  6. data/ext/herb/extconf.rb +2 -1
  7. data/ext/herb/nodes.c +1 -1
  8. data/herb.gemspec +3 -0
  9. data/lib/herb/3.0/herb.so +0 -0
  10. data/lib/herb/3.1/herb.so +0 -0
  11. data/lib/herb/3.2/herb.so +0 -0
  12. data/lib/herb/3.3/herb.so +0 -0
  13. data/lib/herb/3.4/herb.so +0 -0
  14. data/lib/herb/engine.rb +8 -1
  15. data/lib/herb/version.rb +1 -1
  16. data/src/analyze.c +5 -9
  17. data/src/analyze_helpers.c +17 -6
  18. data/src/herb.c +2 -2
  19. data/src/include/parser.h +2 -2
  20. data/src/include/pretty_print.h +1 -1
  21. data/src/include/version.h +1 -1
  22. data/src/parser.c +3 -2
  23. data/src/pretty_print.c +1 -1
  24. data/templates/ext/herb/error_helpers.c.erb +85 -0
  25. data/templates/ext/herb/error_helpers.h.erb +12 -0
  26. data/templates/ext/herb/nodes.c.erb +90 -0
  27. data/templates/ext/herb/nodes.h.erb +9 -0
  28. data/templates/javascript/packages/core/src/errors.ts.erb +193 -0
  29. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +325 -0
  30. data/templates/javascript/packages/core/src/nodes.ts.erb +414 -0
  31. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -0
  32. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +113 -0
  33. data/templates/javascript/packages/node/extension/error_helpers.h.erb +17 -0
  34. data/templates/javascript/packages/node/extension/nodes.cpp.erb +111 -0
  35. data/templates/javascript/packages/node/extension/nodes.h.erb +17 -0
  36. data/templates/lib/herb/ast/nodes.rb.erb +117 -0
  37. data/templates/lib/herb/errors.rb.erb +106 -0
  38. data/templates/lib/herb/visitor.rb.erb +28 -0
  39. data/templates/sig/serialized_ast_errors.rbs.erb +10 -0
  40. data/templates/sig/serialized_ast_nodes.rbs.erb +10 -0
  41. data/templates/src/ast_nodes.c.erb +145 -0
  42. data/templates/src/ast_pretty_print.c.erb +97 -0
  43. data/templates/src/errors.c.erb +245 -0
  44. data/templates/src/include/ast_nodes.h.erb +46 -0
  45. data/templates/src/include/ast_pretty_print.h.erb +14 -0
  46. data/templates/src/include/errors.h.erb +58 -0
  47. data/templates/src/visitor.c.erb +47 -0
  48. data/templates/template.rb +406 -0
  49. data/templates/wasm/error_helpers.cpp.erb +93 -0
  50. data/templates/wasm/error_helpers.h.erb +15 -0
  51. data/templates/wasm/nodes.cpp.erb +79 -0
  52. data/templates/wasm/nodes.h.erb +15 -0
  53. data/vendor/prism/Rakefile +75 -0
  54. data/vendor/prism/config.yml +4713 -0
  55. data/vendor/prism/include/prism/ast.h +8190 -0
  56. data/vendor/prism/include/prism/defines.h +260 -0
  57. data/vendor/prism/include/prism/diagnostic.h +455 -0
  58. data/vendor/prism/include/prism/encoding.h +283 -0
  59. data/vendor/prism/include/prism/node.h +129 -0
  60. data/vendor/prism/include/prism/options.h +482 -0
  61. data/vendor/prism/include/prism/pack.h +163 -0
  62. data/vendor/prism/include/prism/parser.h +933 -0
  63. data/vendor/prism/include/prism/prettyprint.h +34 -0
  64. data/vendor/prism/include/prism/regexp.h +43 -0
  65. data/vendor/prism/include/prism/static_literals.h +121 -0
  66. data/vendor/prism/include/prism/util/pm_buffer.h +236 -0
  67. data/vendor/prism/include/prism/util/pm_char.h +204 -0
  68. data/vendor/prism/include/prism/util/pm_constant_pool.h +218 -0
  69. data/vendor/prism/include/prism/util/pm_integer.h +130 -0
  70. data/vendor/prism/include/prism/util/pm_list.h +103 -0
  71. data/vendor/prism/include/prism/util/pm_memchr.h +29 -0
  72. data/vendor/prism/include/prism/util/pm_newline_list.h +113 -0
  73. data/vendor/prism/include/prism/util/pm_string.h +200 -0
  74. data/vendor/prism/include/prism/util/pm_strncasecmp.h +32 -0
  75. data/vendor/prism/include/prism/util/pm_strpbrk.h +46 -0
  76. data/vendor/prism/include/prism/version.h +29 -0
  77. data/vendor/prism/include/prism.h +408 -0
  78. data/vendor/prism/src/diagnostic.c +848 -0
  79. data/vendor/prism/src/encoding.c +5235 -0
  80. data/vendor/prism/src/node.c +8676 -0
  81. data/vendor/prism/src/options.c +328 -0
  82. data/vendor/prism/src/pack.c +509 -0
  83. data/vendor/prism/src/prettyprint.c +8941 -0
  84. data/vendor/prism/src/prism.c +23302 -0
  85. data/vendor/prism/src/regexp.c +790 -0
  86. data/vendor/prism/src/serialize.c +2268 -0
  87. data/vendor/prism/src/static_literals.c +617 -0
  88. data/vendor/prism/src/token_type.c +703 -0
  89. data/vendor/prism/src/util/pm_buffer.c +357 -0
  90. data/vendor/prism/src/util/pm_char.c +318 -0
  91. data/vendor/prism/src/util/pm_constant_pool.c +342 -0
  92. data/vendor/prism/src/util/pm_integer.c +670 -0
  93. data/vendor/prism/src/util/pm_list.c +49 -0
  94. data/vendor/prism/src/util/pm_memchr.c +35 -0
  95. data/vendor/prism/src/util/pm_newline_list.c +125 -0
  96. data/vendor/prism/src/util/pm_string.c +383 -0
  97. data/vendor/prism/src/util/pm_strncasecmp.c +36 -0
  98. data/vendor/prism/src/util/pm_strpbrk.c +206 -0
  99. data/vendor/prism/templates/ext/prism/api_node.c.erb +282 -0
  100. data/vendor/prism/templates/include/prism/ast.h.erb +226 -0
  101. data/vendor/prism/templates/include/prism/diagnostic.h.erb +130 -0
  102. data/vendor/prism/templates/java/org/prism/AbstractNodeVisitor.java.erb +22 -0
  103. data/vendor/prism/templates/java/org/prism/Loader.java.erb +434 -0
  104. data/vendor/prism/templates/java/org/prism/Nodes.java.erb +403 -0
  105. data/vendor/prism/templates/javascript/src/deserialize.js.erb +448 -0
  106. data/vendor/prism/templates/javascript/src/nodes.js.erb +197 -0
  107. data/vendor/prism/templates/javascript/src/visitor.js.erb +78 -0
  108. data/vendor/prism/templates/lib/prism/compiler.rb.erb +43 -0
  109. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +103 -0
  110. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +189 -0
  111. data/vendor/prism/templates/lib/prism/dsl.rb.erb +133 -0
  112. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +131 -0
  113. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +19 -0
  114. data/vendor/prism/templates/lib/prism/node.rb.erb +515 -0
  115. data/vendor/prism/templates/lib/prism/reflection.rb.erb +136 -0
  116. data/vendor/prism/templates/lib/prism/serialize.rb.erb +602 -0
  117. data/vendor/prism/templates/lib/prism/visitor.rb.erb +55 -0
  118. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +68 -0
  119. data/vendor/prism/templates/rbi/prism/node.rbi.erb +164 -0
  120. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +18 -0
  121. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +45 -0
  122. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +31 -0
  123. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +7 -0
  124. data/vendor/prism/templates/sig/prism/node.rbs.erb +132 -0
  125. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +17 -0
  126. data/vendor/prism/templates/sig/prism.rbs.erb +89 -0
  127. data/vendor/prism/templates/src/diagnostic.c.erb +523 -0
  128. data/vendor/prism/templates/src/node.c.erb +333 -0
  129. data/vendor/prism/templates/src/prettyprint.c.erb +166 -0
  130. data/vendor/prism/templates/src/serialize.c.erb +406 -0
  131. data/vendor/prism/templates/src/token_type.c.erb +369 -0
  132. data/vendor/prism/templates/template.rb +689 -0
  133. 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