herb 0.7.2-arm-linux-musl → 0.7.3-arm-linux-musl

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 (130) 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/version.rb +1 -1
  15. data/src/analyze.c +5 -9
  16. data/src/analyze_helpers.c +17 -6
  17. data/src/include/pretty_print.h +1 -1
  18. data/src/include/version.h +1 -1
  19. data/src/parser.c +1 -0
  20. data/src/pretty_print.c +1 -1
  21. data/templates/ext/herb/error_helpers.c.erb +85 -0
  22. data/templates/ext/herb/error_helpers.h.erb +12 -0
  23. data/templates/ext/herb/nodes.c.erb +90 -0
  24. data/templates/ext/herb/nodes.h.erb +9 -0
  25. data/templates/javascript/packages/core/src/errors.ts.erb +193 -0
  26. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +325 -0
  27. data/templates/javascript/packages/core/src/nodes.ts.erb +414 -0
  28. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -0
  29. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +113 -0
  30. data/templates/javascript/packages/node/extension/error_helpers.h.erb +17 -0
  31. data/templates/javascript/packages/node/extension/nodes.cpp.erb +111 -0
  32. data/templates/javascript/packages/node/extension/nodes.h.erb +17 -0
  33. data/templates/lib/herb/ast/nodes.rb.erb +117 -0
  34. data/templates/lib/herb/errors.rb.erb +106 -0
  35. data/templates/lib/herb/visitor.rb.erb +28 -0
  36. data/templates/sig/serialized_ast_errors.rbs.erb +10 -0
  37. data/templates/sig/serialized_ast_nodes.rbs.erb +10 -0
  38. data/templates/src/ast_nodes.c.erb +145 -0
  39. data/templates/src/ast_pretty_print.c.erb +97 -0
  40. data/templates/src/errors.c.erb +245 -0
  41. data/templates/src/include/ast_nodes.h.erb +46 -0
  42. data/templates/src/include/ast_pretty_print.h.erb +14 -0
  43. data/templates/src/include/errors.h.erb +58 -0
  44. data/templates/src/visitor.c.erb +47 -0
  45. data/templates/template.rb +406 -0
  46. data/templates/wasm/error_helpers.cpp.erb +93 -0
  47. data/templates/wasm/error_helpers.h.erb +15 -0
  48. data/templates/wasm/nodes.cpp.erb +79 -0
  49. data/templates/wasm/nodes.h.erb +15 -0
  50. data/vendor/prism/Rakefile +75 -0
  51. data/vendor/prism/config.yml +4713 -0
  52. data/vendor/prism/include/prism/ast.h +8190 -0
  53. data/vendor/prism/include/prism/defines.h +260 -0
  54. data/vendor/prism/include/prism/diagnostic.h +455 -0
  55. data/vendor/prism/include/prism/encoding.h +283 -0
  56. data/vendor/prism/include/prism/node.h +129 -0
  57. data/vendor/prism/include/prism/options.h +482 -0
  58. data/vendor/prism/include/prism/pack.h +163 -0
  59. data/vendor/prism/include/prism/parser.h +933 -0
  60. data/vendor/prism/include/prism/prettyprint.h +34 -0
  61. data/vendor/prism/include/prism/regexp.h +43 -0
  62. data/vendor/prism/include/prism/static_literals.h +121 -0
  63. data/vendor/prism/include/prism/util/pm_buffer.h +236 -0
  64. data/vendor/prism/include/prism/util/pm_char.h +204 -0
  65. data/vendor/prism/include/prism/util/pm_constant_pool.h +218 -0
  66. data/vendor/prism/include/prism/util/pm_integer.h +130 -0
  67. data/vendor/prism/include/prism/util/pm_list.h +103 -0
  68. data/vendor/prism/include/prism/util/pm_memchr.h +29 -0
  69. data/vendor/prism/include/prism/util/pm_newline_list.h +113 -0
  70. data/vendor/prism/include/prism/util/pm_string.h +200 -0
  71. data/vendor/prism/include/prism/util/pm_strncasecmp.h +32 -0
  72. data/vendor/prism/include/prism/util/pm_strpbrk.h +46 -0
  73. data/vendor/prism/include/prism/version.h +29 -0
  74. data/vendor/prism/include/prism.h +408 -0
  75. data/vendor/prism/src/diagnostic.c +848 -0
  76. data/vendor/prism/src/encoding.c +5235 -0
  77. data/vendor/prism/src/node.c +8676 -0
  78. data/vendor/prism/src/options.c +328 -0
  79. data/vendor/prism/src/pack.c +509 -0
  80. data/vendor/prism/src/prettyprint.c +8941 -0
  81. data/vendor/prism/src/prism.c +23302 -0
  82. data/vendor/prism/src/regexp.c +790 -0
  83. data/vendor/prism/src/serialize.c +2268 -0
  84. data/vendor/prism/src/static_literals.c +617 -0
  85. data/vendor/prism/src/token_type.c +703 -0
  86. data/vendor/prism/src/util/pm_buffer.c +357 -0
  87. data/vendor/prism/src/util/pm_char.c +318 -0
  88. data/vendor/prism/src/util/pm_constant_pool.c +342 -0
  89. data/vendor/prism/src/util/pm_integer.c +670 -0
  90. data/vendor/prism/src/util/pm_list.c +49 -0
  91. data/vendor/prism/src/util/pm_memchr.c +35 -0
  92. data/vendor/prism/src/util/pm_newline_list.c +125 -0
  93. data/vendor/prism/src/util/pm_string.c +383 -0
  94. data/vendor/prism/src/util/pm_strncasecmp.c +36 -0
  95. data/vendor/prism/src/util/pm_strpbrk.c +206 -0
  96. data/vendor/prism/templates/ext/prism/api_node.c.erb +282 -0
  97. data/vendor/prism/templates/include/prism/ast.h.erb +226 -0
  98. data/vendor/prism/templates/include/prism/diagnostic.h.erb +130 -0
  99. data/vendor/prism/templates/java/org/prism/AbstractNodeVisitor.java.erb +22 -0
  100. data/vendor/prism/templates/java/org/prism/Loader.java.erb +434 -0
  101. data/vendor/prism/templates/java/org/prism/Nodes.java.erb +403 -0
  102. data/vendor/prism/templates/javascript/src/deserialize.js.erb +448 -0
  103. data/vendor/prism/templates/javascript/src/nodes.js.erb +197 -0
  104. data/vendor/prism/templates/javascript/src/visitor.js.erb +78 -0
  105. data/vendor/prism/templates/lib/prism/compiler.rb.erb +43 -0
  106. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +103 -0
  107. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +189 -0
  108. data/vendor/prism/templates/lib/prism/dsl.rb.erb +133 -0
  109. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +131 -0
  110. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +19 -0
  111. data/vendor/prism/templates/lib/prism/node.rb.erb +515 -0
  112. data/vendor/prism/templates/lib/prism/reflection.rb.erb +136 -0
  113. data/vendor/prism/templates/lib/prism/serialize.rb.erb +602 -0
  114. data/vendor/prism/templates/lib/prism/visitor.rb.erb +55 -0
  115. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +68 -0
  116. data/vendor/prism/templates/rbi/prism/node.rbi.erb +164 -0
  117. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +18 -0
  118. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +45 -0
  119. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +31 -0
  120. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +7 -0
  121. data/vendor/prism/templates/sig/prism/node.rbs.erb +132 -0
  122. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +17 -0
  123. data/vendor/prism/templates/sig/prism.rbs.erb +89 -0
  124. data/vendor/prism/templates/src/diagnostic.c.erb +523 -0
  125. data/vendor/prism/templates/src/node.c.erb +333 -0
  126. data/vendor/prism/templates/src/prettyprint.c.erb +166 -0
  127. data/vendor/prism/templates/src/serialize.c.erb +406 -0
  128. data/vendor/prism/templates/src/token_type.c.erb +369 -0
  129. data/vendor/prism/templates/template.rb +689 -0
  130. metadata +112 -2
@@ -0,0 +1,602 @@
1
+ require "stringio"
2
+ require_relative "polyfill/unpack1"
3
+
4
+ module Prism
5
+ # A module responsible for deserializing parse results.
6
+ module Serialize
7
+ # The major version of prism that we are expecting to find in the serialized
8
+ # strings.
9
+ MAJOR_VERSION = 1
10
+
11
+ # The minor version of prism that we are expecting to find in the serialized
12
+ # strings.
13
+ MINOR_VERSION = 5
14
+
15
+ # The patch version of prism that we are expecting to find in the serialized
16
+ # strings.
17
+ PATCH_VERSION = 1
18
+
19
+ # Deserialize the dumped output from a request to parse or parse_file.
20
+ #
21
+ # The formatting of the source of this method is purposeful to illustrate
22
+ # the structure of the serialized data.
23
+ def self.load_parse(input, serialized, freeze)
24
+ input = input.dup
25
+ source = Source.for(input)
26
+ loader = Loader.new(source, serialized)
27
+
28
+ loader.load_header
29
+ encoding = loader.load_encoding
30
+ start_line = loader.load_varsint
31
+ offsets = loader.load_line_offsets(freeze)
32
+
33
+ source.replace_start_line(start_line)
34
+ source.replace_offsets(offsets)
35
+
36
+ comments = loader.load_comments(freeze)
37
+ magic_comments = loader.load_magic_comments(freeze)
38
+ data_loc = loader.load_optional_location_object(freeze)
39
+ errors = loader.load_errors(encoding, freeze)
40
+ warnings = loader.load_warnings(encoding, freeze)
41
+ cpool_base = loader.load_uint32
42
+ cpool_size = loader.load_varuint
43
+
44
+ constant_pool = ConstantPool.new(input, serialized, cpool_base, cpool_size)
45
+
46
+ node = loader.load_node(constant_pool, encoding, freeze)
47
+ loader.load_constant_pool(constant_pool)
48
+ raise unless loader.eof?
49
+
50
+ result = ParseResult.new(node, comments, magic_comments, data_loc, errors, warnings, source)
51
+ result.freeze if freeze
52
+
53
+ input.force_encoding(encoding)
54
+
55
+ # This is an extremely niche use-case where the file was marked as binary
56
+ # but it contained UTF-8-encoded characters. In that case we will actually
57
+ # put it back to UTF-8 to give the location APIs the best chance of being
58
+ # correct.
59
+ if !input.ascii_only? && input.encoding == Encoding::BINARY
60
+ input.force_encoding(Encoding::UTF_8)
61
+ input.force_encoding(Encoding::BINARY) unless input.valid_encoding?
62
+ end
63
+
64
+ if freeze
65
+ input.freeze
66
+ source.deep_freeze
67
+ end
68
+
69
+ result
70
+ end
71
+
72
+ # Deserialize the dumped output from a request to lex or lex_file.
73
+ #
74
+ # The formatting of the source of this method is purposeful to illustrate
75
+ # the structure of the serialized data.
76
+ def self.load_lex(input, serialized, freeze)
77
+ source = Source.for(input)
78
+ loader = Loader.new(source, serialized)
79
+
80
+ tokens = loader.load_tokens
81
+ encoding = loader.load_encoding
82
+ start_line = loader.load_varsint
83
+ offsets = loader.load_line_offsets(freeze)
84
+
85
+ source.replace_start_line(start_line)
86
+ source.replace_offsets(offsets)
87
+
88
+ comments = loader.load_comments(freeze)
89
+ magic_comments = loader.load_magic_comments(freeze)
90
+ data_loc = loader.load_optional_location_object(freeze)
91
+ errors = loader.load_errors(encoding, freeze)
92
+ warnings = loader.load_warnings(encoding, freeze)
93
+ raise unless loader.eof?
94
+
95
+ result = LexResult.new(tokens, comments, magic_comments, data_loc, errors, warnings, source)
96
+
97
+ tokens.each do |token|
98
+ token[0].value.force_encoding(encoding)
99
+
100
+ if freeze
101
+ token[0].deep_freeze
102
+ token.freeze
103
+ end
104
+ end
105
+
106
+ if freeze
107
+ source.deep_freeze
108
+ tokens.freeze
109
+ result.freeze
110
+ end
111
+
112
+ result
113
+ end
114
+
115
+ # Deserialize the dumped output from a request to parse_comments or
116
+ # parse_file_comments.
117
+ #
118
+ # The formatting of the source of this method is purposeful to illustrate
119
+ # the structure of the serialized data.
120
+ def self.load_parse_comments(input, serialized, freeze)
121
+ source = Source.for(input)
122
+ loader = Loader.new(source, serialized)
123
+
124
+ loader.load_header
125
+ loader.load_encoding
126
+ start_line = loader.load_varsint
127
+
128
+ source.replace_start_line(start_line)
129
+
130
+ result = loader.load_comments(freeze)
131
+ raise unless loader.eof?
132
+
133
+ source.deep_freeze if freeze
134
+ result
135
+ end
136
+
137
+ # Deserialize the dumped output from a request to parse_lex or
138
+ # parse_lex_file.
139
+ #
140
+ # The formatting of the source of this method is purposeful to illustrate
141
+ # the structure of the serialized data.
142
+ def self.load_parse_lex(input, serialized, freeze)
143
+ source = Source.for(input)
144
+ loader = Loader.new(source, serialized)
145
+
146
+ tokens = loader.load_tokens
147
+ loader.load_header
148
+ encoding = loader.load_encoding
149
+ start_line = loader.load_varsint
150
+ offsets = loader.load_line_offsets(freeze)
151
+
152
+ source.replace_start_line(start_line)
153
+ source.replace_offsets(offsets)
154
+
155
+ comments = loader.load_comments(freeze)
156
+ magic_comments = loader.load_magic_comments(freeze)
157
+ data_loc = loader.load_optional_location_object(freeze)
158
+ errors = loader.load_errors(encoding, freeze)
159
+ warnings = loader.load_warnings(encoding, freeze)
160
+ cpool_base = loader.load_uint32
161
+ cpool_size = loader.load_varuint
162
+
163
+ constant_pool = ConstantPool.new(input, serialized, cpool_base, cpool_size)
164
+
165
+ node = loader.load_node(constant_pool, encoding, freeze)
166
+ loader.load_constant_pool(constant_pool)
167
+ raise unless loader.eof?
168
+
169
+ value = [node, tokens]
170
+ result = ParseLexResult.new(value, comments, magic_comments, data_loc, errors, warnings, source)
171
+
172
+ tokens.each do |token|
173
+ token[0].value.force_encoding(encoding)
174
+
175
+ if freeze
176
+ token[0].deep_freeze
177
+ token.freeze
178
+ end
179
+ end
180
+
181
+ if freeze
182
+ source.deep_freeze
183
+ tokens.freeze
184
+ value.freeze
185
+ result.freeze
186
+ end
187
+
188
+ result
189
+ end
190
+
191
+ class ConstantPool # :nodoc:
192
+ attr_reader :size
193
+
194
+ def initialize(input, serialized, base, size)
195
+ @input = input
196
+ @serialized = serialized
197
+ @base = base
198
+ @size = size
199
+ @pool = Array.new(size, nil)
200
+ end
201
+
202
+ def get(index, encoding)
203
+ @pool[index] ||=
204
+ begin
205
+ offset = @base + index * 8
206
+ start = @serialized.unpack1("L", offset: offset)
207
+ length = @serialized.unpack1("L", offset: offset + 4)
208
+
209
+ if start.nobits?(1 << 31)
210
+ @input.byteslice(start, length).force_encoding(encoding).to_sym
211
+ else
212
+ @serialized.byteslice(start & ((1 << 31) - 1), length).force_encoding(encoding).to_sym
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ if RUBY_ENGINE == "truffleruby"
219
+ # StringIO is synchronized and that adds a high overhead on TruffleRuby.
220
+ class FastStringIO # :nodoc:
221
+ attr_accessor :pos
222
+
223
+ def initialize(string)
224
+ @string = string
225
+ @pos = 0
226
+ end
227
+
228
+ def getbyte
229
+ byte = @string.getbyte(@pos)
230
+ @pos += 1
231
+ byte
232
+ end
233
+
234
+ def read(n)
235
+ slice = @string.byteslice(@pos, n)
236
+ @pos += n
237
+ slice
238
+ end
239
+
240
+ def eof?
241
+ @pos >= @string.bytesize
242
+ end
243
+ end
244
+ else
245
+ FastStringIO = ::StringIO # :nodoc:
246
+ end
247
+
248
+ class Loader # :nodoc:
249
+ attr_reader :input, :io, :source
250
+
251
+ def initialize(source, serialized)
252
+ @input = source.source.dup
253
+ raise unless serialized.encoding == Encoding::BINARY
254
+ @io = FastStringIO.new(serialized)
255
+ @source = source
256
+ define_load_node_lambdas if RUBY_ENGINE != "ruby"
257
+ end
258
+
259
+ def eof?
260
+ io.getbyte
261
+ io.eof?
262
+ end
263
+
264
+ def load_constant_pool(constant_pool)
265
+ trailer = 0
266
+
267
+ constant_pool.size.times do |index|
268
+ start, length = io.read(8).unpack("L2")
269
+ trailer += length if start.anybits?(1 << 31)
270
+ end
271
+
272
+ io.read(trailer)
273
+ end
274
+
275
+ def load_header
276
+ raise "Invalid serialization" if io.read(5) != "PRISM"
277
+ raise "Invalid serialization" if io.read(3).unpack("C3") != [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
278
+ raise "Invalid serialization (location fields must be included but are not)" if io.getbyte != 0
279
+ end
280
+
281
+ def load_encoding
282
+ encoding = Encoding.find(io.read(load_varuint))
283
+ @input = input.force_encoding(encoding).freeze
284
+ encoding
285
+ end
286
+
287
+ def load_line_offsets(freeze)
288
+ offsets = Array.new(load_varuint) { load_varuint }
289
+ offsets.freeze if freeze
290
+ offsets
291
+ end
292
+
293
+ def load_comments(freeze)
294
+ comments =
295
+ Array.new(load_varuint) do
296
+ comment =
297
+ case load_varuint
298
+ when 0 then InlineComment.new(load_location_object(freeze))
299
+ when 1 then EmbDocComment.new(load_location_object(freeze))
300
+ end
301
+
302
+ comment.freeze if freeze
303
+ comment
304
+ end
305
+
306
+ comments.freeze if freeze
307
+ comments
308
+ end
309
+
310
+ def load_magic_comments(freeze)
311
+ magic_comments =
312
+ Array.new(load_varuint) do
313
+ magic_comment =
314
+ MagicComment.new(
315
+ load_location_object(freeze),
316
+ load_location_object(freeze)
317
+ )
318
+
319
+ magic_comment.freeze if freeze
320
+ magic_comment
321
+ end
322
+
323
+ magic_comments.freeze if freeze
324
+ magic_comments
325
+ end
326
+
327
+ DIAGNOSTIC_TYPES = [
328
+ <%- errors.each do |error| -%>
329
+ <%= error.name.downcase.to_sym.inspect %>,
330
+ <%- end -%>
331
+ <%- warnings.each do |warning| -%>
332
+ <%= warning.name.downcase.to_sym.inspect %>,
333
+ <%- end -%>
334
+ ].freeze
335
+
336
+ private_constant :DIAGNOSTIC_TYPES
337
+
338
+ def load_error_level
339
+ level = io.getbyte
340
+
341
+ case level
342
+ when 0
343
+ :syntax
344
+ when 1
345
+ :argument
346
+ when 2
347
+ :load
348
+ else
349
+ raise "Unknown level: #{level}"
350
+ end
351
+ end
352
+
353
+ def load_errors(encoding, freeze)
354
+ errors =
355
+ Array.new(load_varuint) do
356
+ error =
357
+ ParseError.new(
358
+ DIAGNOSTIC_TYPES.fetch(load_varuint),
359
+ load_embedded_string(encoding),
360
+ load_location_object(freeze),
361
+ load_error_level
362
+ )
363
+
364
+ error.freeze if freeze
365
+ error
366
+ end
367
+
368
+ errors.freeze if freeze
369
+ errors
370
+ end
371
+
372
+ def load_warning_level
373
+ level = io.getbyte
374
+
375
+ case level
376
+ when 0
377
+ :default
378
+ when 1
379
+ :verbose
380
+ else
381
+ raise "Unknown level: #{level}"
382
+ end
383
+ end
384
+
385
+ def load_warnings(encoding, freeze)
386
+ warnings =
387
+ Array.new(load_varuint) do
388
+ warning =
389
+ ParseWarning.new(
390
+ DIAGNOSTIC_TYPES.fetch(load_varuint),
391
+ load_embedded_string(encoding),
392
+ load_location_object(freeze),
393
+ load_warning_level
394
+ )
395
+
396
+ warning.freeze if freeze
397
+ warning
398
+ end
399
+
400
+ warnings.freeze if freeze
401
+ warnings
402
+ end
403
+
404
+ def load_tokens
405
+ tokens = []
406
+
407
+ while (type = TOKEN_TYPES.fetch(load_varuint))
408
+ start = load_varuint
409
+ length = load_varuint
410
+ lex_state = load_varuint
411
+
412
+ location = Location.new(@source, start, length)
413
+ token = Token.new(@source, type, location.slice, location)
414
+
415
+ tokens << [token, lex_state]
416
+ end
417
+
418
+ tokens
419
+ end
420
+
421
+ # variable-length integer using https://en.wikipedia.org/wiki/LEB128
422
+ # This is also what protobuf uses: https://protobuf.dev/programming-guides/encoding/#varints
423
+ def load_varuint
424
+ n = io.getbyte
425
+ if n < 128
426
+ n
427
+ else
428
+ n -= 128
429
+ shift = 0
430
+ while (b = io.getbyte) >= 128
431
+ n += (b - 128) << (shift += 7)
432
+ end
433
+ n + (b << (shift + 7))
434
+ end
435
+ end
436
+
437
+ def load_varsint
438
+ n = load_varuint
439
+ (n >> 1) ^ (-(n & 1))
440
+ end
441
+
442
+ def load_integer
443
+ negative = io.getbyte != 0
444
+ length = load_varuint
445
+
446
+ value = 0
447
+ length.times { |index| value |= (load_varuint << (index * 32)) }
448
+
449
+ value = -value if negative
450
+ value
451
+ end
452
+
453
+ def load_double
454
+ io.read(8).unpack1("D")
455
+ end
456
+
457
+ def load_uint32
458
+ io.read(4).unpack1("L")
459
+ end
460
+
461
+ def load_optional_node(constant_pool, encoding, freeze)
462
+ if io.getbyte != 0
463
+ io.pos -= 1
464
+ load_node(constant_pool, encoding, freeze)
465
+ end
466
+ end
467
+
468
+ def load_embedded_string(encoding)
469
+ io.read(load_varuint).force_encoding(encoding).freeze
470
+ end
471
+
472
+ def load_string(encoding)
473
+ case (type = io.getbyte)
474
+ when 1
475
+ input.byteslice(load_varuint, load_varuint).force_encoding(encoding).freeze
476
+ when 2
477
+ load_embedded_string(encoding)
478
+ else
479
+ raise "Unknown serialized string type: #{type}"
480
+ end
481
+ end
482
+
483
+ def load_location_object(freeze)
484
+ location = Location.new(source, load_varuint, load_varuint)
485
+ location.freeze if freeze
486
+ location
487
+ end
488
+
489
+ def load_location(freeze)
490
+ return load_location_object(freeze) if freeze
491
+ (load_varuint << 32) | load_varuint
492
+ end
493
+
494
+ def load_optional_location(freeze)
495
+ load_location(freeze) if io.getbyte != 0
496
+ end
497
+
498
+ def load_optional_location_object(freeze)
499
+ load_location_object(freeze) if io.getbyte != 0
500
+ end
501
+
502
+ def load_constant(constant_pool, encoding)
503
+ index = load_varuint
504
+ constant_pool.get(index - 1, encoding)
505
+ end
506
+
507
+ def load_optional_constant(constant_pool, encoding)
508
+ index = load_varuint
509
+ constant_pool.get(index - 1, encoding) if index != 0
510
+ end
511
+
512
+ if RUBY_ENGINE == "ruby"
513
+ def load_node(constant_pool, encoding, freeze)
514
+ type = io.getbyte
515
+ node_id = load_varuint
516
+ location = load_location(freeze)
517
+ value = case type
518
+ <%- nodes.each_with_index do |node, index| -%>
519
+ when <%= index + 1 %> then
520
+ <%- if node.needs_serialized_length? -%>
521
+ load_uint32
522
+ <%- end -%>
523
+ <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
524
+ case field
525
+ when Prism::Template::NodeField then "load_node(constant_pool, encoding, freeze)"
526
+ when Prism::Template::OptionalNodeField then "load_optional_node(constant_pool, encoding, freeze)"
527
+ when Prism::Template::StringField then "load_string(encoding)"
528
+ when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node(constant_pool, encoding, freeze) }.tap { |nodes| nodes.freeze if freeze }"
529
+ when Prism::Template::ConstantField then "load_constant(constant_pool, encoding)"
530
+ when Prism::Template::OptionalConstantField then "load_optional_constant(constant_pool, encoding)"
531
+ when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_constant(constant_pool, encoding) }.tap { |constants| constants.freeze if freeze }"
532
+ when Prism::Template::LocationField then "load_location(freeze)"
533
+ when Prism::Template::OptionalLocationField then "load_optional_location(freeze)"
534
+ when Prism::Template::UInt8Field then "io.getbyte"
535
+ when Prism::Template::UInt32Field then "load_varuint"
536
+ when Prism::Template::IntegerField then "load_integer"
537
+ when Prism::Template::DoubleField then "load_double"
538
+ else raise
539
+ end
540
+ }].join(", ") -%>)
541
+ <%- end -%>
542
+ end
543
+
544
+ value.freeze if freeze
545
+ value
546
+ end
547
+ else
548
+ def load_node(constant_pool, encoding, freeze)
549
+ @load_node_lambdas[io.getbyte].call(constant_pool, encoding, freeze)
550
+ end
551
+
552
+ def define_load_node_lambdas
553
+ @load_node_lambdas = [
554
+ nil,
555
+ <%- nodes.each do |node| -%>
556
+ -> (constant_pool, encoding, freeze) {
557
+ node_id = load_varuint
558
+ location = load_location(freeze)
559
+ <%- if node.needs_serialized_length? -%>
560
+ load_uint32
561
+ <%- end -%>
562
+ value = <%= node.name %>.new(<%= ["source", "node_id", "location", "load_varuint", *node.fields.map { |field|
563
+ case field
564
+ when Prism::Template::NodeField then "load_node(constant_pool, encoding, freeze)"
565
+ when Prism::Template::OptionalNodeField then "load_optional_node(constant_pool, encoding, freeze)"
566
+ when Prism::Template::StringField then "load_string(encoding)"
567
+ when Prism::Template::NodeListField then "Array.new(load_varuint) { load_node(constant_pool, encoding, freeze) }"
568
+ when Prism::Template::ConstantField then "load_constant(constant_pool, encoding)"
569
+ when Prism::Template::OptionalConstantField then "load_optional_constant(constant_pool, encoding)"
570
+ when Prism::Template::ConstantListField then "Array.new(load_varuint) { load_constant(constant_pool, encoding) }"
571
+ when Prism::Template::LocationField then "load_location(freeze)"
572
+ when Prism::Template::OptionalLocationField then "load_optional_location(freeze)"
573
+ when Prism::Template::UInt8Field then "io.getbyte"
574
+ when Prism::Template::UInt32Field then "load_varuint"
575
+ when Prism::Template::IntegerField then "load_integer"
576
+ when Prism::Template::DoubleField then "load_double"
577
+ else raise
578
+ end
579
+ }].join(", ") -%>)
580
+ value.freeze if freeze
581
+ value
582
+ },
583
+ <%- end -%>
584
+ ]
585
+ end
586
+ end
587
+ end
588
+
589
+ # The token types that can be indexed by their enum values.
590
+ TOKEN_TYPES = [
591
+ nil,
592
+ <%- tokens.each do |token| -%>
593
+ <%= token.name.to_sym.inspect %>,
594
+ <%- end -%>
595
+ ].freeze
596
+
597
+ private_constant :MAJOR_VERSION, :MINOR_VERSION, :PATCH_VERSION
598
+ private_constant :ConstantPool, :FastStringIO, :Loader, :TOKEN_TYPES
599
+ end
600
+
601
+ private_constant :Serialize
602
+ end
@@ -0,0 +1,55 @@
1
+ module Prism
2
+ # A class that knows how to walk down the tree. None of the individual visit
3
+ # methods are implemented on this visitor, so it forces the consumer to
4
+ # implement each one that they need. For a default implementation that
5
+ # continues walking the tree, see the Visitor class.
6
+ class BasicVisitor
7
+ # Calls `accept` on the given node if it is not `nil`, which in turn should
8
+ # call back into this visitor by calling the appropriate `visit_*` method.
9
+ def visit(node)
10
+ # @type self: _Visitor
11
+ node&.accept(self)
12
+ end
13
+
14
+ # Visits each node in `nodes` by calling `accept` on each one.
15
+ def visit_all(nodes)
16
+ # @type self: _Visitor
17
+ nodes.each { |node| node&.accept(self) }
18
+ end
19
+
20
+ # Visits the child nodes of `node` by calling `accept` on each one.
21
+ def visit_child_nodes(node)
22
+ # @type self: _Visitor
23
+ node.compact_child_nodes.each { |node| node.accept(self) }
24
+ end
25
+ end
26
+
27
+ # A visitor is a class that provides a default implementation for every accept
28
+ # method defined on the nodes. This means it can walk a tree without the
29
+ # caller needing to define any special handling. This allows you to handle a
30
+ # subset of the tree, while still walking the whole tree.
31
+ #
32
+ # For example, to find all of the method calls that call the `foo` method, you
33
+ # could write:
34
+ #
35
+ # class FooCalls < Prism::Visitor
36
+ # def visit_call_node(node)
37
+ # if node.name == :foo
38
+ # # Do something with the node
39
+ # end
40
+ #
41
+ # # Call super so that the visitor continues walking the tree
42
+ # super
43
+ # end
44
+ # end
45
+ #
46
+ class Visitor < BasicVisitor
47
+ <%- nodes.each_with_index do |node, index| -%>
48
+ <%= "\n" if index != 0 -%>
49
+ # Visit a <%= node.name %> node
50
+ def visit_<%= node.human %>(node)
51
+ node.compact_child_nodes.each { |node| node.accept(self) }
52
+ end
53
+ <%- end -%>
54
+ end
55
+ end