herb 0.7.1-aarch64-linux-musl → 0.7.3-aarch64-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 (137) 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/error_helpers.c +27 -27
  7. data/ext/herb/extconf.rb +2 -1
  8. data/ext/herb/extension.c +6 -6
  9. data/ext/herb/extension_helpers.c +3 -3
  10. data/ext/herb/nodes.c +35 -35
  11. data/herb.gemspec +3 -0
  12. data/lib/herb/3.0/herb.so +0 -0
  13. data/lib/herb/3.1/herb.so +0 -0
  14. data/lib/herb/3.2/herb.so +0 -0
  15. data/lib/herb/3.3/herb.so +0 -0
  16. data/lib/herb/3.4/herb.so +0 -0
  17. data/lib/herb/engine/debug_visitor.rb +41 -21
  18. data/lib/herb/engine.rb +20 -6
  19. data/lib/herb/version.rb +1 -1
  20. data/sig/herb/engine/debug_visitor.rbs +3 -3
  21. data/sig/herb/engine.rbs +5 -0
  22. data/src/analyze.c +5 -9
  23. data/src/analyze_helpers.c +17 -6
  24. data/src/include/pretty_print.h +1 -1
  25. data/src/include/version.h +1 -1
  26. data/src/parser.c +6 -9
  27. data/src/pretty_print.c +1 -1
  28. data/templates/ext/herb/error_helpers.c.erb +85 -0
  29. data/templates/ext/herb/error_helpers.h.erb +12 -0
  30. data/templates/ext/herb/nodes.c.erb +90 -0
  31. data/templates/ext/herb/nodes.h.erb +9 -0
  32. data/templates/javascript/packages/core/src/errors.ts.erb +193 -0
  33. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +325 -0
  34. data/templates/javascript/packages/core/src/nodes.ts.erb +414 -0
  35. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -0
  36. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +113 -0
  37. data/templates/javascript/packages/node/extension/error_helpers.h.erb +17 -0
  38. data/templates/javascript/packages/node/extension/nodes.cpp.erb +111 -0
  39. data/templates/javascript/packages/node/extension/nodes.h.erb +17 -0
  40. data/templates/lib/herb/ast/nodes.rb.erb +117 -0
  41. data/templates/lib/herb/errors.rb.erb +106 -0
  42. data/templates/lib/herb/visitor.rb.erb +28 -0
  43. data/templates/sig/serialized_ast_errors.rbs.erb +10 -0
  44. data/templates/sig/serialized_ast_nodes.rbs.erb +10 -0
  45. data/templates/src/ast_nodes.c.erb +145 -0
  46. data/templates/src/ast_pretty_print.c.erb +97 -0
  47. data/templates/src/errors.c.erb +245 -0
  48. data/templates/src/include/ast_nodes.h.erb +46 -0
  49. data/templates/src/include/ast_pretty_print.h.erb +14 -0
  50. data/templates/src/include/errors.h.erb +58 -0
  51. data/templates/src/visitor.c.erb +47 -0
  52. data/templates/template.rb +406 -0
  53. data/templates/wasm/error_helpers.cpp.erb +93 -0
  54. data/templates/wasm/error_helpers.h.erb +15 -0
  55. data/templates/wasm/nodes.cpp.erb +79 -0
  56. data/templates/wasm/nodes.h.erb +15 -0
  57. data/vendor/prism/Rakefile +75 -0
  58. data/vendor/prism/config.yml +4713 -0
  59. data/vendor/prism/include/prism/ast.h +8190 -0
  60. data/vendor/prism/include/prism/defines.h +260 -0
  61. data/vendor/prism/include/prism/diagnostic.h +455 -0
  62. data/vendor/prism/include/prism/encoding.h +283 -0
  63. data/vendor/prism/include/prism/node.h +129 -0
  64. data/vendor/prism/include/prism/options.h +482 -0
  65. data/vendor/prism/include/prism/pack.h +163 -0
  66. data/vendor/prism/include/prism/parser.h +933 -0
  67. data/vendor/prism/include/prism/prettyprint.h +34 -0
  68. data/vendor/prism/include/prism/regexp.h +43 -0
  69. data/vendor/prism/include/prism/static_literals.h +121 -0
  70. data/vendor/prism/include/prism/util/pm_buffer.h +236 -0
  71. data/vendor/prism/include/prism/util/pm_char.h +204 -0
  72. data/vendor/prism/include/prism/util/pm_constant_pool.h +218 -0
  73. data/vendor/prism/include/prism/util/pm_integer.h +130 -0
  74. data/vendor/prism/include/prism/util/pm_list.h +103 -0
  75. data/vendor/prism/include/prism/util/pm_memchr.h +29 -0
  76. data/vendor/prism/include/prism/util/pm_newline_list.h +113 -0
  77. data/vendor/prism/include/prism/util/pm_string.h +200 -0
  78. data/vendor/prism/include/prism/util/pm_strncasecmp.h +32 -0
  79. data/vendor/prism/include/prism/util/pm_strpbrk.h +46 -0
  80. data/vendor/prism/include/prism/version.h +29 -0
  81. data/vendor/prism/include/prism.h +408 -0
  82. data/vendor/prism/src/diagnostic.c +848 -0
  83. data/vendor/prism/src/encoding.c +5235 -0
  84. data/vendor/prism/src/node.c +8676 -0
  85. data/vendor/prism/src/options.c +328 -0
  86. data/vendor/prism/src/pack.c +509 -0
  87. data/vendor/prism/src/prettyprint.c +8941 -0
  88. data/vendor/prism/src/prism.c +23302 -0
  89. data/vendor/prism/src/regexp.c +790 -0
  90. data/vendor/prism/src/serialize.c +2268 -0
  91. data/vendor/prism/src/static_literals.c +617 -0
  92. data/vendor/prism/src/token_type.c +703 -0
  93. data/vendor/prism/src/util/pm_buffer.c +357 -0
  94. data/vendor/prism/src/util/pm_char.c +318 -0
  95. data/vendor/prism/src/util/pm_constant_pool.c +342 -0
  96. data/vendor/prism/src/util/pm_integer.c +670 -0
  97. data/vendor/prism/src/util/pm_list.c +49 -0
  98. data/vendor/prism/src/util/pm_memchr.c +35 -0
  99. data/vendor/prism/src/util/pm_newline_list.c +125 -0
  100. data/vendor/prism/src/util/pm_string.c +383 -0
  101. data/vendor/prism/src/util/pm_strncasecmp.c +36 -0
  102. data/vendor/prism/src/util/pm_strpbrk.c +206 -0
  103. data/vendor/prism/templates/ext/prism/api_node.c.erb +282 -0
  104. data/vendor/prism/templates/include/prism/ast.h.erb +226 -0
  105. data/vendor/prism/templates/include/prism/diagnostic.h.erb +130 -0
  106. data/vendor/prism/templates/java/org/prism/AbstractNodeVisitor.java.erb +22 -0
  107. data/vendor/prism/templates/java/org/prism/Loader.java.erb +434 -0
  108. data/vendor/prism/templates/java/org/prism/Nodes.java.erb +403 -0
  109. data/vendor/prism/templates/javascript/src/deserialize.js.erb +448 -0
  110. data/vendor/prism/templates/javascript/src/nodes.js.erb +197 -0
  111. data/vendor/prism/templates/javascript/src/visitor.js.erb +78 -0
  112. data/vendor/prism/templates/lib/prism/compiler.rb.erb +43 -0
  113. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +103 -0
  114. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +189 -0
  115. data/vendor/prism/templates/lib/prism/dsl.rb.erb +133 -0
  116. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +131 -0
  117. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +19 -0
  118. data/vendor/prism/templates/lib/prism/node.rb.erb +515 -0
  119. data/vendor/prism/templates/lib/prism/reflection.rb.erb +136 -0
  120. data/vendor/prism/templates/lib/prism/serialize.rb.erb +602 -0
  121. data/vendor/prism/templates/lib/prism/visitor.rb.erb +55 -0
  122. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +68 -0
  123. data/vendor/prism/templates/rbi/prism/node.rbi.erb +164 -0
  124. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +18 -0
  125. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +45 -0
  126. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +31 -0
  127. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +7 -0
  128. data/vendor/prism/templates/sig/prism/node.rbs.erb +132 -0
  129. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +17 -0
  130. data/vendor/prism/templates/sig/prism.rbs.erb +89 -0
  131. data/vendor/prism/templates/src/diagnostic.c.erb +523 -0
  132. data/vendor/prism/templates/src/node.c.erb +333 -0
  133. data/vendor/prism/templates/src/prettyprint.c.erb +166 -0
  134. data/vendor/prism/templates/src/serialize.c.erb +406 -0
  135. data/vendor/prism/templates/src/token_type.c.erb +369 -0
  136. data/vendor/prism/templates/template.rb +689 -0
  137. metadata +112 -2
@@ -0,0 +1,448 @@
1
+ import * as nodes from "./nodes.js";
2
+
3
+ const MAJOR_VERSION = 1;
4
+ const MINOR_VERSION = 5;
5
+ const PATCH_VERSION = 1;
6
+
7
+ // The DataView getFloat64 function takes an optional second argument that
8
+ // specifies whether the number is little-endian or big-endian. It does not
9
+ // appear to have a native endian mode, so we need to determine the endianness
10
+ // of the system at runtime.
11
+ const LITTLE_ENDIAN = (() => {
12
+ let uint32 = new Uint32Array([0x11223344]);
13
+ let uint8 = new Uint8Array(uint32.buffer);
14
+
15
+ if (uint8[0] === 0x44) {
16
+ return true;
17
+ } else if (uInt8[0] === 0x11) {
18
+ return false;
19
+ } else {
20
+ throw new Error("Mixed endianness");
21
+ }
22
+ })();
23
+
24
+ class SerializationBuffer {
25
+ FORCED_UTF8_ENCODING_FLAG = 1 << 2;
26
+ FORCED_BINARY_ENCODING_FLAG = 1 << 3;
27
+
28
+ DECODER_MAP = new Map([
29
+ ["ascii-8bit", "ascii"]
30
+ ]);
31
+
32
+ constructor(source, array) {
33
+ this.source = source;
34
+ this.array = array;
35
+ this.index = 0;
36
+ this.fileEncoding = "utf-8";
37
+ this.decoders = new Map();
38
+ }
39
+
40
+ readByte() {
41
+ const result = this.array[this.index];
42
+ this.index += 1;
43
+ return result;
44
+ }
45
+
46
+ readBytes(length) {
47
+ const result = this.array.slice(this.index, this.index + length);
48
+ this.index += length;
49
+ return result;
50
+ }
51
+
52
+ readString(length, flags) {
53
+ return this.decodeString(this.readBytes(length), flags).value;
54
+ }
55
+
56
+ // Read a 32-bit unsigned integer in little-endian format.
57
+ readUint32() {
58
+ const result = this.scanUint32(this.index);
59
+ this.index += 4;
60
+ return result;
61
+ }
62
+
63
+ scanUint32(offset) {
64
+ const bytes = this.array.slice(offset, offset + 4);
65
+ return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);
66
+ }
67
+
68
+ readVarInt() {
69
+ let result = 0;
70
+ let shift = 0;
71
+
72
+ while (true) {
73
+ const byte = this.readByte();
74
+ result += (byte & 0x7f) << shift;
75
+ shift += 7;
76
+
77
+ if ((byte & 0x80) === 0) {
78
+ break;
79
+ }
80
+ }
81
+
82
+ return result;
83
+ }
84
+
85
+ readLocation() {
86
+ return { startOffset: this.readVarInt(), length: this.readVarInt() };
87
+ }
88
+
89
+ readOptionalLocation() {
90
+ if (this.readByte() != 0) {
91
+ return this.readLocation();
92
+ } else {
93
+ return null;
94
+ }
95
+ }
96
+
97
+ readStringField(flags) {
98
+ if (flags === undefined) flags = 0;
99
+ const type = this.readByte();
100
+
101
+ switch (type) {
102
+ case 1: {
103
+ const startOffset = this.readVarInt();
104
+ const length = this.readVarInt();
105
+ return this.decodeString(this.source.slice(startOffset, startOffset + length), flags);
106
+ }
107
+ case 2:
108
+ return this.decodeString(this.readBytes(this.readVarInt()), flags);
109
+ default:
110
+ throw new Error(`Unknown serialized string type: ${type}`);
111
+ }
112
+ }
113
+
114
+ scanConstant(constantPoolOffset, constantIndex) {
115
+ const offset = constantPoolOffset + constantIndex * 8;
116
+ let startOffset = this.scanUint32(offset);
117
+ const length = this.scanUint32(offset + 4);
118
+
119
+ if (startOffset & (1 << 31)) {
120
+ startOffset &= (1 << 31) - 1;
121
+ return new TextDecoder().decode(this.array.slice(startOffset, startOffset + length));
122
+ } else {
123
+ return new TextDecoder().decode(this.source.slice(startOffset, startOffset + length));
124
+ }
125
+ }
126
+
127
+ readDouble() {
128
+ const view = new DataView(new ArrayBuffer(8));
129
+ for (let index = 0; index < 8; index++) {
130
+ view.setUint8(index, this.readByte());
131
+ }
132
+
133
+ return view.getFloat64(0, LITTLE_ENDIAN);
134
+ }
135
+
136
+ decodeString(bytes, flags) {
137
+ const forcedBin = (flags & this.FORCED_BINARY_ENCODING_FLAG) !== 0;
138
+ const forcedUtf8 = (flags & this.FORCED_UTF8_ENCODING_FLAG) !== 0;
139
+
140
+ if (forcedBin) {
141
+ // just use raw bytes
142
+ return {
143
+ encoding: "ascii",
144
+ validEncoding: true,
145
+ value: this.asciiDecoder.decode(bytes)
146
+ };
147
+ } else {
148
+ const encoding = forcedUtf8 ? "utf-8" : this.fileEncoding.toLowerCase();
149
+ const decoder = this.getDecoder(encoding);
150
+
151
+ try {
152
+ // decode with encoding
153
+ return {
154
+ encoding,
155
+ validEncoding: true,
156
+ value: decoder.decode(bytes)
157
+ };
158
+ } catch(e) {
159
+ // just use raw bytes, capture what the encoding should be, set flag saying encoding is invalid
160
+ if (e.code === "ERR_ENCODING_INVALID_ENCODED_DATA") {
161
+ return {
162
+ encoding,
163
+ validEncoding: false,
164
+ value: this.asciiDecoder.decode(bytes)
165
+ };
166
+ }
167
+
168
+ throw e;
169
+ }
170
+ }
171
+ }
172
+
173
+ getDecoder(encoding) {
174
+ encoding = this.DECODER_MAP.get(encoding) || encoding;
175
+
176
+ if (!this.decoders.has(encoding)) {
177
+ this.decoders.set(encoding, new TextDecoder(encoding, {fatal: true}));
178
+ }
179
+
180
+ return this.decoders.get(encoding);
181
+ }
182
+
183
+ get asciiDecoder() {
184
+ if (!this._asciiDecoder) {
185
+ this._asciiDecoder = new TextDecoder("ascii");
186
+ }
187
+
188
+ return this._asciiDecoder;
189
+ }
190
+ }
191
+
192
+ /**
193
+ * A location in the source code.
194
+ *
195
+ * @typedef {{ startOffset: number, length: number }} Location
196
+ */
197
+
198
+ /**
199
+ * A comment in the source code.
200
+ *
201
+ * @typedef {{ type: number, location: Location }} Comment
202
+ */
203
+
204
+ /**
205
+ * A magic comment in the source code.
206
+ *
207
+ * @typedef {{ startLocation: Location, endLocation: Location }} MagicComment
208
+ */
209
+
210
+ /**
211
+ * An error in the source code.
212
+ *
213
+ * @typedef {{ type: string, message: string, location: Location, level: string }} ParseError
214
+ */
215
+
216
+ /**
217
+ * A warning in the source code.
218
+ *
219
+ * @typedef {{ type: string, message: string, location: Location, level: string }} ParseWarning
220
+ */
221
+
222
+ /**
223
+ * The result of parsing the source code.
224
+ *
225
+ * @typedef {{ value: ProgramNode, comments: Comment[], magicComments: MagicComment[], errors: ParseError[], warnings: ParseWarning[] }} ParseResult
226
+ */
227
+
228
+ /**
229
+ * The result of calling parse.
230
+ */
231
+ export class ParseResult {
232
+ /**
233
+ * @type {nodes.ProgramNode}
234
+ */
235
+ value;
236
+
237
+ /**
238
+ * @type {Comment[]}
239
+ */
240
+ comments;
241
+
242
+ /**
243
+ * @type {MagicComment[]}
244
+ */
245
+ magicComments;
246
+
247
+ /**
248
+ * @type {Location | null}
249
+ */
250
+
251
+ /**
252
+ * @type {ParseError[]}
253
+ */
254
+ errors;
255
+
256
+ /**
257
+ * @type {ParseWarning[]}
258
+ */
259
+ warnings;
260
+
261
+ /**
262
+ * @param {nodes.ProgramNode} value
263
+ * @param {Comment[]} comments
264
+ * @param {MagicComment[]} magicComments
265
+ * @param {ParseError[]} errors
266
+ * @param {ParseWarning[]} warnings
267
+ */
268
+ constructor(value, comments, magicComments, dataLoc, errors, warnings) {
269
+ this.value = value;
270
+ this.comments = comments;
271
+ this.magicComments = magicComments;
272
+ this.dataLoc = dataLoc;
273
+ this.errors = errors;
274
+ this.warnings = warnings;
275
+ }
276
+ }
277
+
278
+ const errorLevels = ["syntax", "argument", "load"];
279
+ const errorTypes = [
280
+ <%- errors.each do |error| -%>
281
+ "<%= error.name.downcase %>",
282
+ <%- end -%>
283
+ ];
284
+
285
+ const warningLevels = ["default", "verbose"];
286
+ const warningTypes = [
287
+ <%- warnings.each do |warning| -%>
288
+ "<%= warning.name.downcase %>",
289
+ <%- end -%>
290
+ ];
291
+
292
+ /**
293
+ * Accept two Uint8Arrays, one for the source and one for the serialized format.
294
+ * Return the AST corresponding to the serialized form.
295
+ *
296
+ * @param {Uint8Array} source
297
+ * @param {Uint8Array} array
298
+ * @returns {ParseResult}
299
+ * @throws {Error}
300
+ */
301
+ export function deserialize(source, array) {
302
+ const buffer = new SerializationBuffer(source, array);
303
+
304
+ if (buffer.readString(5) !== "PRISM") {
305
+ throw new Error("Invalid serialization");
306
+ }
307
+
308
+ if ((buffer.readByte() != MAJOR_VERSION) || (buffer.readByte() != MINOR_VERSION) || (buffer.readByte() != PATCH_VERSION)) {
309
+ throw new Error("Invalid serialization");
310
+ }
311
+
312
+ if (buffer.readByte() != 0) {
313
+ throw new Error("Invalid serialization (location fields must be included but are not)");
314
+ }
315
+
316
+ // Read the file's encoding.
317
+ buffer.fileEncoding = buffer.readString(buffer.readVarInt());
318
+
319
+ // Skip past the start line, as we don't support that option yet in
320
+ // JavaScript.
321
+ buffer.readVarInt();
322
+
323
+ // Skip past the line offsets, as there is no Source object yet in JavaScript.
324
+ // const lineOffsets = Array.from({ length: buffer.readVarInt() }, () => buffer.readVarInt());
325
+ const lineOffsetsCount = buffer.readVarInt();
326
+ for (let i = 0; i < lineOffsetsCount; i ++) {
327
+ buffer.readVarInt();
328
+ }
329
+
330
+ const comments = Array.from({ length: buffer.readVarInt() }, () => ({
331
+ type: buffer.readVarInt(),
332
+ location: buffer.readLocation()
333
+ }));
334
+
335
+ const magicComments = Array.from({ length: buffer.readVarInt() }, () => ({
336
+ startLocation: buffer.readLocation(),
337
+ endLocation: buffer.readLocation()
338
+ }));
339
+
340
+ const dataLoc = buffer.readOptionalLocation();
341
+
342
+ const errors = Array.from({ length: buffer.readVarInt() }, () => ({
343
+ type: errorTypes[buffer.readVarInt()],
344
+ message: buffer.readString(buffer.readVarInt()),
345
+ location: buffer.readLocation(),
346
+ level: errorLevels[buffer.readByte()]
347
+ }));
348
+
349
+ const warnings = Array.from({ length: buffer.readVarInt() }, () => ({
350
+ type: warningTypes[buffer.readVarInt()],
351
+ message: buffer.readString(buffer.readVarInt()),
352
+ location: buffer.readLocation(),
353
+ level: warningLevels[buffer.readByte()]
354
+ }));
355
+
356
+ const constantPoolOffset = buffer.readUint32();
357
+ const constants = Array.from({ length: buffer.readVarInt() }, () => null);
358
+
359
+ return new ParseResult(readRequiredNode(), comments, magicComments, dataLoc, errors, warnings);
360
+
361
+ function readRequiredNode() {
362
+ const type = buffer.readByte();
363
+ const nodeID = buffer.readVarInt();
364
+ const location = buffer.readLocation();
365
+ let flags;
366
+
367
+ switch (type) {
368
+ <%- nodes.each.with_index(1) do |node, index| -%>
369
+ case <%= index %>:
370
+ <%- if node.needs_serialized_length? -%>
371
+ buffer.readUint32();
372
+ <%- end -%>
373
+ return new nodes.<%= node.name %>(<%= ["nodeID", "location", "flags = buffer.readVarInt()", *node.fields.map { |field|
374
+ case field
375
+ when Prism::Template::NodeField then "readRequiredNode()"
376
+ when Prism::Template::OptionalNodeField then "readOptionalNode()"
377
+ when Prism::Template::StringField then "buffer.readStringField(flags)"
378
+ when Prism::Template::NodeListField then "Array.from({ length: buffer.readVarInt() }, readRequiredNode)"
379
+ when Prism::Template::ConstantField then "readRequiredConstant()"
380
+ when Prism::Template::OptionalConstantField then "readOptionalConstant()"
381
+ when Prism::Template::ConstantListField then "Array.from({ length: buffer.readVarInt() }, readRequiredConstant)"
382
+ when Prism::Template::LocationField then "buffer.readLocation()"
383
+ when Prism::Template::OptionalLocationField then "buffer.readOptionalLocation()"
384
+ when Prism::Template::UInt8Field then "buffer.readByte()"
385
+ when Prism::Template::UInt32Field then "buffer.readVarInt()"
386
+ when Prism::Template::IntegerField then "readInteger()"
387
+ when Prism::Template::DoubleField then "buffer.readDouble()"
388
+ end
389
+ }].join(", ") -%>);
390
+ <%- end -%>
391
+ default:
392
+ throw new Error(`Unknown node type: ${type}`);
393
+ }
394
+ }
395
+
396
+ function readOptionalNode() {
397
+ if (buffer.readByte() != 0) {
398
+ buffer.index -= 1;
399
+ return readRequiredNode();
400
+ } else {
401
+ return null;
402
+ }
403
+ }
404
+
405
+ function scanConstant(constantIndex) {
406
+ if (constants[constantIndex] === null) {
407
+ constants[constantIndex] = buffer.scanConstant(constantPoolOffset, constantIndex);
408
+ }
409
+
410
+ return constants[constantIndex];
411
+ }
412
+
413
+ function readRequiredConstant() {
414
+ return scanConstant(buffer.readVarInt() - 1);
415
+ }
416
+
417
+ function readOptionalConstant() {
418
+ const index = buffer.readVarInt();
419
+ if (index === 0) {
420
+ return null;
421
+ } else {
422
+ return scanConstant(index - 1);
423
+ }
424
+ }
425
+
426
+ function readInteger() {
427
+ const negative = buffer.readByte() != 0;
428
+ const length = buffer.readVarInt();
429
+
430
+ const firstWord = buffer.readVarInt();
431
+ if (length == 1) {
432
+ if (negative && firstWord >= 0x80000000) {
433
+ return -BigInt(firstWord);
434
+ } else if (negative) {
435
+ return -firstWord;
436
+ } else {
437
+ return firstWord;
438
+ }
439
+ }
440
+
441
+ let result = BigInt(firstWord);
442
+ for (let index = 1; index < length; index++) {
443
+ result |= (BigInt(buffer.readVarInt()) << BigInt(index * 32));
444
+ }
445
+
446
+ return negative ? -result : result;
447
+ }
448
+ }
@@ -0,0 +1,197 @@
1
+ <%-
2
+
3
+ def camelize(string)
4
+ string.gsub(/_([a-z])/) { $1.upcase }
5
+ end
6
+
7
+ def prop(field)
8
+ field.name == "arguments" ? "arguments_" : camelize(field.name)
9
+ end
10
+
11
+ def jstype(field)
12
+ case field
13
+ when Prism::Template::NodeField then field.ruby_type
14
+ when Prism::Template::OptionalNodeField then "#{field.ruby_type} | null"
15
+ when Prism::Template::NodeListField then "Node[]"
16
+ when Prism::Template::StringField then "RubyString"
17
+ when Prism::Template::ConstantField then "string"
18
+ when Prism::Template::OptionalConstantField then "string | null"
19
+ when Prism::Template::ConstantListField then "string[]"
20
+ when Prism::Template::LocationField then "Location"
21
+ when Prism::Template::OptionalLocationField then "Location | null"
22
+ when Prism::Template::UInt8Field, Prism::Template::UInt32Field, Prism::Template::IntegerField, Prism::Template::DoubleField then "number"
23
+ else raise
24
+ end
25
+ end
26
+ -%>
27
+ import * as visitors from "./visitor.js"
28
+
29
+ <%- flags.each do |flag| -%>
30
+
31
+ /**
32
+ * <%= flag.comment %>
33
+ */
34
+ const <%= flag.name %> = {
35
+ <%- flag.values.each_with_index do |value, index| -%>
36
+ <%= value.name %>: 1 << <%= index + Prism::Template::COMMON_FLAGS_COUNT %>,
37
+ <%- end -%>
38
+ };
39
+ <%- end -%>
40
+
41
+ /**
42
+ * A location in the source code.
43
+ *
44
+ * @typedef {{ startOffset: number, length: number }} Location
45
+ */
46
+
47
+ /**
48
+ * An encoded Ruby string.
49
+ *
50
+ * @typedef {{ value: string, encoding: string, validEncoding: boolean }} RubyString
51
+ */
52
+
53
+ /**
54
+ * A generic node in the tree.
55
+ *
56
+ * @typedef {(<%= nodes.map(&:name).join("|") %>)} Node
57
+ */
58
+ <%- nodes.each do |node| -%>
59
+
60
+ /**
61
+ <%- node.each_comment_line do |line| -%>
62
+ *<%= line %>
63
+ <%- end -%>
64
+ */
65
+ export class <%= node.name -%> {
66
+ /**
67
+ * @type number
68
+ */
69
+ nodeID;
70
+
71
+ /**
72
+ * @type {Location}
73
+ */
74
+ location;
75
+
76
+ /**
77
+ * @type number
78
+ */
79
+ #flags;
80
+
81
+ <%- node.fields.each do |field| -%>
82
+ /**
83
+ * @type <%= jstype(field) %>
84
+ */
85
+ <%= prop(field) %>;
86
+
87
+ <%- end -%>
88
+ /**
89
+ * Construct a new <%= node.name %>.
90
+ *
91
+ * @param {number} nodeID
92
+ * @param {Location} location
93
+ * @param {number} flags
94
+ <%- node.fields.each do |field| -%>
95
+ * @param {<%= jstype(field) %>} <%= prop(field) %>
96
+ <%- end -%>
97
+ */
98
+ constructor(<%= ["nodeID", "location", "flags", *node.fields.map { |field| prop(field) }].join(", ") %>) {
99
+ this.nodeID = nodeID;
100
+ this.location = location;
101
+ this.#flags = flags;
102
+ <%- node.fields.each do |field| -%>
103
+ this.<%= prop(field) %> = <%= prop(field) %>;
104
+ <%- end -%>
105
+ }
106
+ <%- if (node_flags = node.flags) -%>
107
+ <%- node_flags.values.each do |value| -%>
108
+
109
+ /**
110
+ * True if this node has the <%= value.name %> flag.
111
+ *
112
+ * @returns {boolean}
113
+ */
114
+ is<%= value.camelcase %>() {
115
+ return (this.#flags & <%= node_flags.name %>.<%= value.name %>) !== 0;
116
+ }
117
+ <%- end -%>
118
+ <%- end -%>
119
+
120
+ /**
121
+ * Accept a visitor for this node.
122
+ *
123
+ * @param {visitors.Visitor} visitor
124
+ */
125
+ accept(visitor) {
126
+ visitor.visit<%= camelize(node.name) %>(this)
127
+ }
128
+
129
+ /**
130
+ * Returns all child nodes of the current node.
131
+ *
132
+ * @returns {(Node | null)[]} An array of child nodes.
133
+ */
134
+ childNodes() {
135
+ return [<%= node.fields.map { |field|
136
+ case field
137
+ when Prism::Template::NodeField, Prism::Template::OptionalNodeField then "this.#{prop(field)}"
138
+ when Prism::Template::NodeListField then "...this.#{prop(field)}"
139
+ end
140
+ }.compact.join(", ") %>]
141
+ }
142
+
143
+ /**
144
+ * Compact and return an array of child nodes.
145
+ *
146
+ * @returns {Node[]} An array of compacted child nodes.
147
+ */
148
+ compactChildNodes() {
149
+ <%- if node.fields.any? { |field| field.is_a?(Prism::Template::OptionalNodeField) } -%>
150
+ const compact = [];
151
+
152
+ <%- node.fields.each do |field| -%>
153
+ <%- case field -%>
154
+ <%- when Prism::Template::NodeField -%>
155
+ compact.push(this.<%= prop(field) %>);
156
+
157
+ <%- when Prism::Template::OptionalNodeField -%>
158
+ if (this.<%= prop(field) %>) {
159
+ compact.push(this.<%= prop(field) %>);
160
+ }
161
+ <%- when Prism::Template::NodeListField -%>
162
+ compact.concat(this.<%= prop(field) %>);
163
+ <%- end -%>
164
+ <%- end -%>
165
+
166
+ return compact;
167
+ <%- else -%>
168
+ return [<%= node.fields.map { |field|
169
+ case field
170
+ when Prism::Template::NodeField then "this.#{prop(field)}"
171
+ when Prism::Template::NodeListField then "...this.#{prop(field)}"
172
+ end
173
+ }.compact.join(", ") %>];
174
+ <%- end -%>
175
+ }
176
+
177
+ /**
178
+ * Transforms the Node to a JavaScript object.
179
+ *
180
+ * @returns {Object}
181
+ */
182
+ toJSON() {
183
+ return {
184
+ type: "<%= node.name %>",
185
+ location: this.location,
186
+ flags: this.#flags,
187
+ <%- node.fields.each do |field| -%>
188
+ <%- if field.name == "arguments" -%>
189
+ arguments: this.<%= prop(field) %>,
190
+ <%- else -%>
191
+ <%= prop(field) %>: this.<%= prop(field) %>,
192
+ <%- end -%>
193
+ <%- end -%>
194
+ };
195
+ }
196
+ }
197
+ <%- end -%>
@@ -0,0 +1,78 @@
1
+ import * as nodes from "./nodes.js";
2
+
3
+ /**
4
+ * A class that knows how to walk down the tree. None of the individual visit
5
+ * methods are implemented on this visitor, so it forces the consumer to
6
+ * implement each one that they need. For a default implementation that
7
+ * continues walking the tree, see the `Visitor` class.
8
+ *
9
+ */
10
+ export class BasicVisitor {
11
+ /**
12
+ * Calls `accept` on the given node if it is not `null`, which in turn should
13
+ * call back into this visitor by calling the appropriate `visit*` method.
14
+ *
15
+ * @param {nodes.Node} node
16
+ */
17
+ visit(node) {
18
+ node?.accept(this);
19
+ }
20
+
21
+ /**
22
+ * Visits each node in `nodes` by calling `accept` on each one.
23
+ *
24
+ * @param {nodes.Node[]} nodes
25
+ */
26
+ visitAll(nodes) {
27
+ nodes.forEach((node) => {
28
+ node?.accept(this);
29
+ });
30
+ }
31
+
32
+ /**
33
+ * Visits the child nodes of `node` by calling `accept` on each one.
34
+ *
35
+ * @param {nodes.Node} node
36
+ */
37
+ visitChildNodes(node) {
38
+ node.compactChildNodes().forEach((childNode) => {
39
+ childNode.accept(this);
40
+ });
41
+ }
42
+ }
43
+
44
+ /**
45
+ * A visitor is a class that provides a default implementation for every accept
46
+ * method defined on the nodes. This means it can walk a tree without the
47
+ * caller needing to define any special handling. This allows you to handle a
48
+ * subset of the tree, while still walking the whole tree.
49
+ *
50
+ * For example, to find all of the method calls that call the `foo` method, you
51
+ * could write:
52
+ *
53
+ * @example
54
+ * class FooCalls extends Visitor {
55
+ * visitCallNode(node) {
56
+ * if (node.name === "foo") {
57
+ * // Do something with the node
58
+ * }
59
+ *
60
+ * // Call super so that the visitor continues walking the tree
61
+ * super.visitCallNode(node);
62
+ * }
63
+ * }
64
+ *
65
+ */
66
+ export class Visitor extends BasicVisitor {
67
+ <%- nodes.each_with_index do |node, index| -%>
68
+ <%= "\n" if index != 0 -%>
69
+ /**
70
+ * Visit a <%= node.name %> node.
71
+ *
72
+ * @param {nodes.<%= node.name %>} node
73
+ */
74
+ <%= "visit#{node.name.gsub(/_([a-z])/) { $1.upcase }}" %>(node) {
75
+ this.visitChildNodes(node);
76
+ }
77
+ <%- end -%>
78
+ }