@thomasfosterau/effect-parse 0.4.0 → 0.5.0

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 (148) hide show
  1. package/README.md +40 -14
  2. package/dist/Ascii.d.ts +11 -4
  3. package/dist/Ascii.d.ts.map +1 -1
  4. package/dist/Ascii.js +7 -1
  5. package/dist/Ascii.js.map +1 -1
  6. package/dist/Binary.d.ts.map +1 -1
  7. package/dist/Binary.js +64 -35
  8. package/dist/Binary.js.map +1 -1
  9. package/dist/Bits.d.ts.map +1 -1
  10. package/dist/Bits.js +7 -4
  11. package/dist/Bits.js.map +1 -1
  12. package/dist/Compiler.d.ts +74 -2
  13. package/dist/Compiler.d.ts.map +1 -1
  14. package/dist/Compiler.js +78 -1
  15. package/dist/Compiler.js.map +1 -1
  16. package/dist/Expression.d.ts.map +1 -1
  17. package/dist/Expression.js +86 -74
  18. package/dist/Expression.js.map +1 -1
  19. package/dist/Input.d.ts +37 -4
  20. package/dist/Input.d.ts.map +1 -1
  21. package/dist/Input.js +42 -0
  22. package/dist/Input.js.map +1 -1
  23. package/dist/Nom.d.ts +5 -15
  24. package/dist/Nom.d.ts.map +1 -1
  25. package/dist/Nom.js.map +1 -1
  26. package/dist/ParseError.d.ts +2 -2
  27. package/dist/ParseError.d.ts.map +1 -1
  28. package/dist/ParseError.js +1 -1
  29. package/dist/ParseError.js.map +1 -1
  30. package/dist/Parser.d.ts +370 -28
  31. package/dist/Parser.d.ts.map +1 -1
  32. package/dist/Parser.js +390 -19
  33. package/dist/Parser.js.map +1 -1
  34. package/dist/ParserSchema.js +2 -2
  35. package/dist/ParserSchema.js.map +1 -1
  36. package/dist/ParserStream.d.ts +3 -2
  37. package/dist/ParserStream.d.ts.map +1 -1
  38. package/dist/ParserStream.js +15 -10
  39. package/dist/ParserStream.js.map +1 -1
  40. package/dist/Syntax.d.ts +23 -5
  41. package/dist/Syntax.d.ts.map +1 -1
  42. package/dist/Syntax.js.map +1 -1
  43. package/dist/Text.d.ts.map +1 -1
  44. package/dist/Text.js +9 -9
  45. package/dist/Text.js.map +1 -1
  46. package/dist/Token.d.ts +55 -10
  47. package/dist/Token.d.ts.map +1 -1
  48. package/dist/Token.js +59 -21
  49. package/dist/Token.js.map +1 -1
  50. package/dist/internal/compiler/closure.d.ts.map +1 -1
  51. package/dist/internal/compiler/closure.js +257 -97
  52. package/dist/internal/compiler/closure.js.map +1 -1
  53. package/dist/internal/compiler/entries.d.ts +3 -1
  54. package/dist/internal/compiler/entries.d.ts.map +1 -1
  55. package/dist/internal/compiler/entries.js +3 -2
  56. package/dist/internal/compiler/entries.js.map +1 -1
  57. package/dist/internal/compiler/first.d.ts.map +1 -1
  58. package/dist/internal/compiler/first.js +7 -1
  59. package/dist/internal/compiler/first.js.map +1 -1
  60. package/dist/internal/compiler/graph.d.ts +17 -0
  61. package/dist/internal/compiler/graph.d.ts.map +1 -0
  62. package/dist/internal/compiler/graph.js +56 -0
  63. package/dist/internal/compiler/graph.js.map +1 -0
  64. package/dist/internal/compiler/jit.d.ts +5 -0
  65. package/dist/internal/compiler/jit.d.ts.map +1 -1
  66. package/dist/internal/compiler/jit.js +185 -96
  67. package/dist/internal/compiler/jit.js.map +1 -1
  68. package/dist/internal/compiler/registry.d.ts +10 -2
  69. package/dist/internal/compiler/registry.d.ts.map +1 -1
  70. package/dist/internal/compiler/registry.js.map +1 -1
  71. package/dist/internal/compiler/search.d.ts +32 -0
  72. package/dist/internal/compiler/search.d.ts.map +1 -0
  73. package/dist/internal/compiler/search.js +68 -0
  74. package/dist/internal/compiler/search.js.map +1 -0
  75. package/dist/internal/compiler/sets.d.ts.map +1 -1
  76. package/dist/internal/compiler/sets.js +1 -1
  77. package/dist/internal/compiler/sets.js.map +1 -1
  78. package/dist/internal/compiler/wasm.d.ts +8 -0
  79. package/dist/internal/compiler/wasm.d.ts.map +1 -0
  80. package/dist/internal/compiler/wasm.js +2769 -0
  81. package/dist/internal/compiler/wasm.js.map +1 -0
  82. package/dist/internal/compiler/wasmAsm.d.ts +199 -0
  83. package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
  84. package/dist/internal/compiler/wasmAsm.js +427 -0
  85. package/dist/internal/compiler/wasmAsm.js.map +1 -0
  86. package/dist/internal/entries.d.ts +3 -1
  87. package/dist/internal/entries.d.ts.map +1 -1
  88. package/dist/internal/entries.js +1 -2
  89. package/dist/internal/entries.js.map +1 -1
  90. package/dist/internal/node.d.ts +58 -2
  91. package/dist/internal/node.d.ts.map +1 -1
  92. package/dist/internal/node.js +13 -3
  93. package/dist/internal/node.js.map +1 -1
  94. package/dist/internal/numbers.d.ts.map +1 -1
  95. package/dist/internal/numbers.js.map +1 -1
  96. package/dist/internal/run.d.ts +12 -0
  97. package/dist/internal/run.d.ts.map +1 -1
  98. package/dist/internal/run.js +51 -11
  99. package/dist/internal/run.js.map +1 -1
  100. package/dist/internal/stack.d.ts +6 -0
  101. package/dist/internal/stack.d.ts.map +1 -1
  102. package/dist/internal/stack.js +8 -2
  103. package/dist/internal/stack.js.map +1 -1
  104. package/dist/internal/syntax.d.ts +4 -4
  105. package/dist/internal/syntax.d.ts.map +1 -1
  106. package/dist/internal/syntax.js +18 -10
  107. package/dist/internal/syntax.js.map +1 -1
  108. package/dist/internal/text.d.ts +32 -0
  109. package/dist/internal/text.d.ts.map +1 -1
  110. package/dist/internal/text.js +68 -14
  111. package/dist/internal/text.js.map +1 -1
  112. package/dist/internal/tokens.d.ts +13 -0
  113. package/dist/internal/tokens.d.ts.map +1 -1
  114. package/dist/internal/tokens.js +59 -39
  115. package/dist/internal/tokens.js.map +1 -1
  116. package/package.json +5 -4
  117. package/src/Ascii.ts +42 -9
  118. package/src/Binary.ts +151 -71
  119. package/src/Bits.ts +12 -6
  120. package/src/Compiler.ts +101 -10
  121. package/src/Expression.ts +94 -81
  122. package/src/Input.ts +65 -6
  123. package/src/Nom.ts +15 -5
  124. package/src/ParseError.ts +9 -4
  125. package/src/Parser.ts +682 -129
  126. package/src/ParserSchema.ts +1 -1
  127. package/src/ParserStream.ts +40 -19
  128. package/src/Syntax.ts +60 -36
  129. package/src/Text.ts +16 -15
  130. package/src/Token.ts +138 -29
  131. package/src/internal/compiler/closure.ts +362 -135
  132. package/src/internal/compiler/entries.ts +4 -2
  133. package/src/internal/compiler/first.ts +10 -0
  134. package/src/internal/compiler/graph.ts +68 -0
  135. package/src/internal/compiler/jit.ts +284 -154
  136. package/src/internal/compiler/registry.ts +10 -2
  137. package/src/internal/compiler/search.ts +68 -0
  138. package/src/internal/compiler/sets.ts +7 -3
  139. package/src/internal/compiler/wasm.ts +3203 -0
  140. package/src/internal/compiler/wasmAsm.ts +484 -0
  141. package/src/internal/entries.ts +10 -4
  142. package/src/internal/node.ts +54 -4
  143. package/src/internal/numbers.ts +3 -1
  144. package/src/internal/run.ts +71 -12
  145. package/src/internal/stack.ts +8 -1
  146. package/src/internal/syntax.ts +39 -18
  147. package/src/internal/text.ts +97 -9
  148. package/src/internal/tokens.ts +96 -14
@@ -0,0 +1,2769 @@
1
+ import * as Predicate from "effect/Predicate";
2
+ import * as Result from "effect/Result";
3
+ import { Fail, State } from "../../Input.js";
4
+ import { floatTexts, toFloat } from "../numbers.js";
5
+ import { backend as backend$1, jitSupported } from "./jit.js";
6
+ import * as Option from "effect/Option";
7
+ import { charOf, fastLimit, latin1, string, utf16be, utf16le, utf8 } from "../text.js";
8
+ import * as Arr from "effect/Array";
9
+ import { addEntry, flushEntries, fromEntries, isPlainKey } from "../entries.js";
10
+ import { nodeOf } from "../node.js";
11
+ import { buildsEntries, isDiagnostic, pairOf } from "./entries.js";
12
+ import { TableSize, kindOfEncoding, textSet, tokenSet } from "./sets.js";
13
+ import { countRefs, isLeaf, isLetter, isSmall, lowerAscii, selectorOf } from "./graph.js";
14
+ import { Body, F64, I32, Op, Simd, encodeModule } from "./wasmAsm.js";
15
+ // src/internal/compiler/wasm.ts
16
+ /**
17
+ * The WebAssembly compiler: scans the input in WebAssembly, then builds the
18
+ * value in JavaScript (see `docs/DESIGN.md`, "The WebAssembly compiler").
19
+ *
20
+ * A parse runs in two passes over one description of the grammar:
21
+ *
22
+ * 1. **Scan.** Generated WebAssembly matches the input, which is copied into
23
+ * linear memory, with the same control flow as the JIT (labelled blocks
24
+ * for failure, a function per rule, `state.mode` as a global). Where a
25
+ * value is used, it appends what the value needs to a _trace_ in linear
26
+ * memory: slice bounds, which branch or case matched, repetition counts,
27
+ * floats. When it backtracks it rewinds the trace with the cursor, so the
28
+ * trace only describes the successful parse.
29
+ * 2. **Build.** A JavaScript function generated for the grammar reads the
30
+ * trace in order and builds the value, with the same callbacks and the
31
+ * same object shapes as the JIT, without scanning anything.
32
+ *
33
+ * Parsers with no native form are _islands_: the scan calls back into
34
+ * JavaScript, which runs their JIT-compiled step on the shared state, and the
35
+ * trace records the index of their value. Streaming (resumable) builds,
36
+ * array input, and environments without `WebAssembly` or `new Function` use
37
+ * the JIT.
38
+ */
39
+ /** Globals. `F` holds the float of the latest scan, the others are `i32`. */
40
+ const G = {
41
+ mode: 0,
42
+ end: 1,
43
+ len: 2,
44
+ tp: 3,
45
+ tlim: 4,
46
+ nv: 5,
47
+ w: 6,
48
+ f: 7
49
+ };
50
+ /** Imported functions. */
51
+ const Imp = {
52
+ island: 0,
53
+ grow: 1,
54
+ test: 2,
55
+ float: 3,
56
+ check: 4
57
+ };
58
+ const importCount = 5;
59
+ /**
60
+ * Function types: rules and decoders `(i32) -> i32`, imports and helpers of
61
+ * two arguments `(i32, i32) -> i32`, `grow` `() -> i32`, `float` `(i32, i32) -> f64`,
62
+ * `start` `(i32 × 5) -> i32`.
63
+ */
64
+ const Ty = {
65
+ rule: 0,
66
+ pair: 1,
67
+ grow: 2,
68
+ toF64: 3,
69
+ start: 4
70
+ };
71
+ /** Linear memory: membership tables from 0, powers of ten, then the input, then the trace. */
72
+ const TablesEnd = 61440;
73
+ const Pow10 = 61440;
74
+ /** The string cache (see `intern`): `StringSlots` slots of a version, a length and `MaxInterned` units. */
75
+ const Strings = 65536;
76
+ const StringSlots = 1024;
77
+ const MaxInterned = 16;
78
+ const SlotBytes = 40;
79
+ const Input$1 = 131072;
80
+ const PageSize = 65536;
81
+ /** Headroom kept free above the trace limit: more than the writes between two checks. */
82
+ const Slack = 65536;
83
+ /** Trace words a function may write past the last check that dominates them (see `put`). */
84
+ const MaxWrites = 4096;
85
+ /** Bytes left after the cursor beyond which a driver's parse of the same buffer runs the JIT (see `run`). */
86
+ const LargeRest = 4096;
87
+ /** The most literals a compiled `takeUntilAny` checks at each candidate; more are searched in JavaScript. */
88
+ const MaxUntil = 64;
89
+ /** The most leading bytes of each literal a SIMD search tests at once. */
90
+ const MaxPositions = 3;
91
+ /** Teddy's buckets: one bit each in a nibble table's bytes. */
92
+ const Buckets = 8;
93
+ /** For each low nibble, the high nibbles `from` to `from + 7` of the bytes `set` accepts, as bits from 0. */
94
+ /** Whether `set` accepts any byte. */
95
+ const accepts = (set) => Array.from({ length: 256 }, (_, c) => set.cs.table[c] === 1 !== set.negate).some((ok) => ok);
96
+ const nibbleTable = (set, from) => {
97
+ const table = new Array(16).fill(0);
98
+ for (let c = from << 4; c < from + 8 << 4; c++) if (set.cs.table[c] === 1 !== set.negate) table[c & 15] = (table[c & 15] ?? 0) | 1 << (c >> 4) - from;
99
+ return table;
100
+ };
101
+ /** The most rejected bytes a vectorised `takeWhile` compares with one by one. */
102
+ const MaxStops = 3;
103
+ /** For a high nibble `h` from 8 up, bit `h - 8`; none below. */
104
+ const UpperNibbleBits = [
105
+ 0,
106
+ 0,
107
+ 0,
108
+ 0,
109
+ 0,
110
+ 0,
111
+ 0,
112
+ 0,
113
+ 1,
114
+ 2,
115
+ 4,
116
+ 8,
117
+ 16,
118
+ 32,
119
+ 64,
120
+ 128
121
+ ];
122
+ /** For a high nibble `h`, bit `h` below 8 (ASCII), none above. */
123
+ const HighNibbleBits = [
124
+ 1,
125
+ 2,
126
+ 4,
127
+ 8,
128
+ 16,
129
+ 32,
130
+ 64,
131
+ 128,
132
+ 0,
133
+ 0,
134
+ 0,
135
+ 0,
136
+ 0,
137
+ 0,
138
+ 0,
139
+ 0
140
+ ];
141
+ const Zeros = [
142
+ 0,
143
+ 0,
144
+ 0,
145
+ 0,
146
+ 0,
147
+ 0,
148
+ 0,
149
+ 0,
150
+ 0,
151
+ 0,
152
+ 0,
153
+ 0,
154
+ 0,
155
+ 0,
156
+ 0,
157
+ 0
158
+ ];
159
+ const LowNibbles = [
160
+ 15,
161
+ 15,
162
+ 15,
163
+ 15,
164
+ 15,
165
+ 15,
166
+ 15,
167
+ 15,
168
+ 15,
169
+ 15,
170
+ 15,
171
+ 15,
172
+ 15,
173
+ 15,
174
+ 15,
175
+ 15
176
+ ];
177
+ /**
178
+ * Teddy's tables for the first `m` bytes of `literals`: for each position,
179
+ * the low- and high-nibble tables, literal `i` in bucket `i % 8`.
180
+ */
181
+ const teddyTables = (literals, m) => Array.from({ length: m }, (_, j) => {
182
+ const lo = new Array(16).fill(0);
183
+ const hi = new Array(16).fill(0);
184
+ literals.forEach((lit, i) => {
185
+ const byte = lit[j] ?? 0;
186
+ const bit = 1 << i % Buckets;
187
+ lo[byte & 15] = (lo[byte & 15] ?? 0) | bit;
188
+ hi[byte >> 4] = (hi[byte >> 4] ?? 0) | bit;
189
+ });
190
+ return [lo, hi];
191
+ });
192
+ /**
193
+ * The bytes of literal units (`width` bytes each, little-endian), and the
194
+ * 0x20 to OR into each byte of a caseless letter, which `bytes` holds in
195
+ * lower case.
196
+ */
197
+ const unitBytes = (codes, caseless, width) => {
198
+ const bytes = [];
199
+ const fold = [];
200
+ for (const code of codes) {
201
+ const letter = caseless && isLetter(code);
202
+ const unit = letter ? lowerAscii(code) : code;
203
+ for (let k = 0; k < width; k++) {
204
+ bytes.push(unit >> 8 * k & 255);
205
+ fold.push(letter && k === 0 ? 32 : 0);
206
+ }
207
+ }
208
+ return {
209
+ bytes,
210
+ fold
211
+ };
212
+ };
213
+ /** The widest load, of 16 (with SIMD), 8, 4, 2 or 1 bytes, that `left` bytes fill. */
214
+ const chunkSize = (left) => {
215
+ if (left >= 16 && simd()) return 16;
216
+ return [
217
+ 8,
218
+ 4,
219
+ 2
220
+ ].find((n) => left >= n) ?? 1;
221
+ };
222
+ /**
223
+ * With an address on the stack, pushes whether the 1, 2, 4, 8 or 16 bytes
224
+ * at it (plus `offset`), ORed with `fold`, differ from `bytes`.
225
+ */
226
+ const compareChunk = (b, bytes, fold, offset) => {
227
+ const n = bytes.length;
228
+ const folds = fold.some((f) => f !== 0);
229
+ if (n === 16) {
230
+ b.simd(Simd.v128Load, 0, offset);
231
+ if (folds) b.v128(fold).simd(Simd.v128Or);
232
+ b.v128(bytes).simd(Simd.i8x16Eq).simd(Simd.i8x16AllTrue).op(Op.i32Eqz);
233
+ } else if (n === 8) {
234
+ b.mem(Op.i64Load, 0, offset);
235
+ if (folds) b.i64(littleEndian(fold, 0, 8)).op(Op.i64Or);
236
+ b.i64(littleEndian(bytes, 0, 8)).op(Op.i64Ne);
237
+ } else {
238
+ b.mem(n === 4 ? Op.i32Load : n === 2 ? Op.i32Load16U : Op.i32Load8U, 0, offset);
239
+ if (folds) b.i32(Number(littleEndian(fold, 0, n))).op(Op.i32Or);
240
+ b.i32(Number(BigInt.asIntN(32, littleEndian(bytes, 0, n)))).op(Op.i32Ne);
241
+ }
242
+ };
243
+ /** `n` bytes from `bytes[i]` as a little-endian integer (as a load reads them). */
244
+ const littleEndian = (bytes, i, n) => {
245
+ let v = 0n;
246
+ for (let k = n - 1; k >= 0; k--) v = v << 8n | BigInt(bytes[i + k] ?? 0);
247
+ return BigInt.asIntN(64, v);
248
+ };
249
+ /** Values of `G.mode`. */
250
+ const Backtrack = 0;
251
+ const Cut = 1;
252
+ /** Whether the scan decodes an encoding itself. */
253
+ const isBuiltin = (enc) => enc === string || enc === utf8 || enc === utf16le || enc === utf16be || enc === latin1;
254
+ /** Pushes the code point of the surrogate pair in locals `hi` and `lo`. */
255
+ const pair = (b, hi, lo) => {
256
+ b.get(hi).i32(55296).op(Op.i32Sub).i32(10).op(Op.i32Shl);
257
+ b.get(lo).i32(56320).op(Op.i32Sub).op(Op.i32Add).i32(65536).op(Op.i32Add);
258
+ };
259
+ /** Whether every key of a record of cases is one unit below `size` (a byte, as a numeric key, for `bytes`). */
260
+ const closedKeys = (keys, size, bytes) => keys.every((k) => Predicate.isString(k) && (bytes ? /^\d+$/.test(k) && Number(k) < size : k.length === 1 && k.charCodeAt(0) < size));
261
+ /** Per builder function: its variables. */
262
+ var Vars = class {
263
+ names = [];
264
+ };
265
+ const modeOf = (mode) => mode === "Cut" ? Cut : mode === "Backtrack" ? Backtrack : 2;
266
+ /** The inclusive runs of accepted code points of a set, when its ranges are known. */
267
+ const acceptedRuns = (cs, negate, max) => {
268
+ if (cs.ranges === void 0) return Option.none();
269
+ const runs = [];
270
+ for (const [a, b] of cs.ranges) if (a <= max) runs.push([a, Math.min(b, max)]);
271
+ if (!negate) return Option.some(runs);
272
+ const out = [];
273
+ let next = 0;
274
+ for (const [a, b] of runs) {
275
+ if (a > next) out.push([next, a - 1]);
276
+ next = b + 1;
277
+ }
278
+ if (next <= max) out.push([next, max]);
279
+ return Option.some(out);
280
+ };
281
+ let simdChecked = false;
282
+ let simdSupported = false;
283
+ /**
284
+ * Whether WebAssembly SIMD is available, for the widener of strings (checked
285
+ * once): a module of one `v128` load validates.
286
+ */
287
+ const simd = () => {
288
+ if (!simdChecked) {
289
+ simdChecked = true;
290
+ simdSupported = validates((probe) => probe.get(0).simd(Simd.v128Load, 0, 0).simd(Simd.i8x16Bitmask));
291
+ }
292
+ return simdSupported;
293
+ };
294
+ let relaxedChecked = false;
295
+ let relaxedSupported = false;
296
+ /**
297
+ * Whether relaxed SIMD is available (checked once): its `relaxed_swizzle`
298
+ * is `swizzle` without the fix-up for indices from 16 up, which the nibble
299
+ * lookups never pass.
300
+ */
301
+ const relaxed = () => {
302
+ if (!relaxedChecked) {
303
+ relaxedChecked = true;
304
+ relaxedSupported = simd() && validates((probe) => probe.get(0).simd(Simd.v128Load, 0, 0).get(0).simd(Simd.v128Load, 0, 0).simd(Simd.i8x16RelaxedSwizzle).simd(Simd.i8x16Bitmask));
305
+ }
306
+ return relaxedSupported;
307
+ };
308
+ /** Pushes a swizzle of a table by nibbles (indices below 16): relaxed where it validates. */
309
+ const nibbleSwizzle = (b) => {
310
+ b.simd(relaxed() ? Simd.i8x16RelaxedSwizzle : Simd.i8x16Swizzle);
311
+ };
312
+ /** Whether a module of one function `(i32) -> i32` with the body `write` writes validates. */
313
+ const validates = (write) => {
314
+ const probe = new Body(1);
315
+ write(probe);
316
+ const bytes = encodeModule({
317
+ types: [{
318
+ params: [I32],
319
+ results: [I32]
320
+ }],
321
+ imports: [],
322
+ memoryPages: 1,
323
+ functions: [[0, probe]],
324
+ globals: [],
325
+ exports: [],
326
+ data: []
327
+ });
328
+ return WebAssembly.validate(bytes);
329
+ };
330
+ /** Whether a builder is available: it is generated with `new Function`. */
331
+ const supported = () => Predicate.isObject(globalThis.WebAssembly) && jitSupported();
332
+ var WasmCompiler = class WasmCompiler {
333
+ kind;
334
+ functions = [];
335
+ builders = [];
336
+ constants = [];
337
+ islands = [];
338
+ fallbacks = [];
339
+ tables = [];
340
+ tests = [];
341
+ rules = [/* @__PURE__ */ new WeakMap(), /* @__PURE__ */ new WeakMap()];
342
+ pending = [];
343
+ refs = /* @__PURE__ */ new WeakMap();
344
+ decoders = /* @__PURE__ */ new WeakMap();
345
+ floatScanners = /* @__PURE__ */ new WeakMap();
346
+ /** The float scanner of `Token` / `Ascii` text, which has no encoding. */
347
+ tokenFloatScanner = -1;
348
+ next = 0;
349
+ constructor(kind) {
350
+ this.kind = kind;
351
+ }
352
+ /** Counts the distinct parents of each parser. */
353
+ countRefs(root) {
354
+ this.refs = countRefs(root);
355
+ }
356
+ /** A constant of the builder, `C[i]`; the same value (by `Object.is`) is stored once. */
357
+ const(value) {
358
+ let i = this.constants.findIndex((c) => Object.is(c, value));
359
+ if (i < 0) i = this.constants.push(value) - 1;
360
+ return `C[${i}]`;
361
+ }
362
+ /** A JavaScript literal for simple values, otherwise a constant. */
363
+ lit(value) {
364
+ if (value === void 0) return "void 0";
365
+ if (value === null || Predicate.isBoolean(value)) return String(value);
366
+ if (Predicate.isNumber(value) && Number.isFinite(value) && !Object.is(value, -0)) return String(value);
367
+ return this.const(value);
368
+ }
369
+ v(bf) {
370
+ const name = `v${this.next++}`;
371
+ bf.names.push(name);
372
+ return name;
373
+ }
374
+ /** Reserves a function index; its body is filled in later. */
375
+ reserve(type, params = 1) {
376
+ const body = new Body(params);
377
+ this.functions.push([type, body]);
378
+ return [importCount + this.functions.length - 1, body];
379
+ }
380
+ /** The function of a rule, generating it later if new. With `used`, it has a builder `b<index>`. */
381
+ rule(p, used) {
382
+ const rules = this.rules[used ? 1 : 0];
383
+ const known = rules.get(p);
384
+ if (known !== void 0) return known;
385
+ const [index] = this.reserve(Ty.rule);
386
+ rules.set(p, index);
387
+ this.pending.push([
388
+ p,
389
+ used,
390
+ index
391
+ ]);
392
+ return index;
393
+ }
394
+ /** Generates the pending rules (and the rules they use). */
395
+ flush() {
396
+ for (let r = this.pending.shift(); r !== void 0; r = this.pending.shift()) {
397
+ const [p, used, index] = r;
398
+ const body = this.functions[index - importCount][1];
399
+ const bf = new Vars();
400
+ const out = used ? this.v(bf) : "";
401
+ body.tp = body.local();
402
+ body.gget(G.tp).set(body.tp);
403
+ body.endLocal = body.local();
404
+ body.gget(G.end).set(body.endLocal);
405
+ this.check(body);
406
+ body.writes = 0;
407
+ let built = "";
408
+ body.block((fail) => {
409
+ built = this.inline(p, out, body, fail, bf, 0);
410
+ body.get(body.tp).gset(G.tp);
411
+ body.get(0).op(Op.return);
412
+ });
413
+ body.i32(-1);
414
+ if (used) this.builders.push(`function b${index}(i){${Arr.isArrayNonEmpty(bf.names) ? `let ${bf.names.join(",")};` : ""}${built}N=i;return ${out}}`);
415
+ }
416
+ }
417
+ /** Fails with a mode. */
418
+ failWith(b, fail, mode) {
419
+ b.i32(mode).gset(G.mode).br(fail);
420
+ }
421
+ /** Fails with `Backtrack` when the `i32` at the top of the stack is true. */
422
+ failIf(b, fail) {
423
+ b.if(() => this.failWith(b, fail, Backtrack));
424
+ }
425
+ /** Propagates a failure unless its mode is `Backtrack`. */
426
+ unlessBacktrack(b, fail) {
427
+ b.gget(G.mode).brIf(fail);
428
+ }
429
+ /** Pushes the input unit at local `pos` plus `delta` units. */
430
+ load(b, pos, delta = 0) {
431
+ if (this.kind === 0) b.get(pos).i32(1).op(Op.i32Shl).mem(Op.i32Load16U, 1, Input$1 + 2 * delta);
432
+ else b.get(pos).mem(Op.i32Load8U, 0, Input$1 + delta);
433
+ }
434
+ /** Pushes the end of the input: from a local in rule functions, from the global in helpers. */
435
+ end(b) {
436
+ return b.endLocal >= 0 ? b.get(b.endLocal) : b.gget(G.end);
437
+ }
438
+ /** Pushes `p >= E`. */
439
+ atEnd(b, pos) {
440
+ this.end(b.get(pos)).op(Op.i32GeU);
441
+ }
442
+ /** `p += n`. */
443
+ advance(b, n) {
444
+ b.get(0).i32(n).op(Op.i32Add).set(0);
445
+ }
446
+ /** Saves the cursor and the trace pointer. */
447
+ save(b) {
448
+ const p = b.local();
449
+ const t = b.local();
450
+ b.get(0).set(p).get(b.tp).set(t);
451
+ return [p, t];
452
+ }
453
+ /** Restores a saved cursor and trace pointer. */
454
+ restore(b, [p, t]) {
455
+ b.get(p).set(0).get(t).set(b.tp);
456
+ }
457
+ /** Grows the trace if it is past its limit. */
458
+ check(b) {
459
+ b.get(b.tp).gget(G.tlim).op(Op.i32GtU);
460
+ b.if(() => b.call(Imp.grow).gset(G.tlim));
461
+ }
462
+ /**
463
+ * Appends words to the trace. Every function and loop iteration starts
464
+ * with a check, and the limit keeps `Slack` bytes free, so a check is
465
+ * only written here once a function wrote `MaxWrites` words since one.
466
+ */
467
+ put(b, words) {
468
+ b.writes += words.length;
469
+ if (b.writes > MaxWrites) this.check(b);
470
+ words.forEach((push, k) => {
471
+ b.get(b.tp);
472
+ push();
473
+ b.mem(Op.i32Store, 2, 4 * k);
474
+ });
475
+ b.get(b.tp).i32(4 * words.length).op(Op.i32Add).set(b.tp);
476
+ }
477
+ /** Reserves a trace word, returning a local holding its address. */
478
+ slot(b) {
479
+ const s = b.local();
480
+ b.get(b.tp).set(s);
481
+ this.put(b, [() => b.i32(0)]);
482
+ return s;
483
+ }
484
+ /** Appends the `f64` in `G.f` to the trace, aligned to 8 bytes. */
485
+ putF64(b) {
486
+ b.writes += 4;
487
+ if (b.writes > MaxWrites) this.check(b);
488
+ b.get(b.tp).i32(7).op(Op.i32Add).i32(-8).op(Op.i32And).set(b.tp);
489
+ b.get(b.tp).gget(G.f).mem(Op.f64Store, 3, 0);
490
+ b.get(b.tp).i32(8).op(Op.i32Add).set(b.tp);
491
+ }
492
+ /** A loop with a trace check at the start of each iteration. */
493
+ loop(b, body) {
494
+ const before = b.writes;
495
+ b.loop((again) => {
496
+ this.check(b);
497
+ b.writes = 0;
498
+ body(again);
499
+ });
500
+ b.writes += before;
501
+ }
502
+ /** Builder code reading the next trace word. */
503
+ static word = "T[i++]";
504
+ /**
505
+ * Runs `p`'s JIT-compiled step on the shared state. With `out`, its value
506
+ * is kept by JavaScript and the trace records its index.
507
+ */
508
+ island(p, out, b, fail, reason) {
509
+ const id = this.islands.length;
510
+ this.islands.push({
511
+ parser: p,
512
+ used: out !== ""
513
+ });
514
+ this.fallbacks.push({
515
+ name: p.name,
516
+ tag: nodeOf(p)._tag,
517
+ reason
518
+ });
519
+ const r = b.local();
520
+ b.i32(id).get(0).call(Imp.island).tee(r).i32(0).op(Op.i32LtS);
521
+ b.if(() => {
522
+ b.i32(-1).get(r).op(Op.i32Sub).gset(G.mode).br(fail);
523
+ });
524
+ b.get(r).set(0);
525
+ if (out === "") return "";
526
+ this.put(b, [() => b.gget(G.nv)]);
527
+ b.gget(G.nv).i32(1).op(Op.i32Add).gset(G.nv);
528
+ return `${out}=V[${WasmCompiler.word}];`;
529
+ }
530
+ /** Builder functions of the value islands, `w<id>`, and what they apply to the value. */
531
+ valueFns = [];
532
+ checks = [];
533
+ /**
534
+ * A callback that needs `self`'s value while scanning (`filter`,
535
+ * `tryMap`, `filterMap`, `tap`): `self` is scanned here, then JavaScript
536
+ * builds its value from its trace (with a builder function of its own) and
537
+ * applies `apply`, which returns the result or `Fail` (a failure with
538
+ * `Backtrack`). The trace of `self` is then replaced by the index of the
539
+ * result.
540
+ */
541
+ valueIsland(self, out, b, fail, d, apply) {
542
+ const id = this.valueFns.length;
543
+ this.valueFns.push("");
544
+ this.checks.push(apply);
545
+ const ts = b.local();
546
+ b.get(b.tp).set(ts);
547
+ const vars = new Vars();
548
+ const x = this.v(vars);
549
+ const code = this.gen(self, x, b, fail, vars, d);
550
+ this.valueFns[id] = `function w${id}(i){let ${vars.names.join(",")};${code}return ${x}}`;
551
+ b.i32(id).get(ts).call(Imp.check).op(Op.i32Eqz);
552
+ this.failIf(b, fail);
553
+ b.get(ts).set(b.tp);
554
+ if (out !== "") this.put(b, [() => b.gget(G.nv)]);
555
+ b.gget(G.nv).i32(1).op(Op.i32Add).gset(G.nv);
556
+ return out === "" ? "" : `${out}=V[T[i++]];`;
557
+ }
558
+ call(index, out, b, fail) {
559
+ b.get(b.tp).gset(G.tp);
560
+ b.get(0).call(index).tee(0).i32(0).op(Op.i32LtS).brIf(fail);
561
+ b.gget(G.tp).set(b.tp);
562
+ return out === "" ? "" : `${out}=b${index}(i);i=N;`;
563
+ }
564
+ /**
565
+ * Scan code for `p`, falling through with `p` advanced, or branching to
566
+ * `fail` with `G.mode` set. With `out`, returns the builder code that
567
+ * reads its trace and sets `out` to its value.
568
+ */
569
+ gen(p, out, b, fail, bf, depth) {
570
+ const node = nodeOf(p);
571
+ if (Predicate.isTagged(node, "Suspend")) return this.call(this.rule(node.resolve(), out !== ""), out, b, fail);
572
+ if (!isLeaf(node) && ((this.refs.get(p) ?? 0) > 1 && !isSmall(p) || depth > 32)) return this.call(this.rule(p, out !== ""), out, b, fail);
573
+ return this.inline(p, out, b, fail, bf, depth);
574
+ }
575
+ /** Whether the scan reads tokens of this encoding itself. */
576
+ native(enc) {
577
+ if (enc === void 0) return true;
578
+ return isBuiltin(enc) && kindOfEncoding(enc) === this.kind;
579
+ }
580
+ inline(p, out, b, fail, bf, depth) {
581
+ const node = nodeOf(p);
582
+ const s = {
583
+ p,
584
+ out,
585
+ b,
586
+ fail,
587
+ bf,
588
+ d: depth + 1
589
+ };
590
+ const families = [
591
+ (n, x) => this.constant(n, x),
592
+ (n, x) => this.slices(n, x),
593
+ (n, x) => this.values(n, x),
594
+ (n, x) => this.control(n, x),
595
+ (n, x) => this.structure(n, x)
596
+ ];
597
+ for (const family of families) {
598
+ const code = family(node, s);
599
+ if (Option.isSome(code)) return code.value;
600
+ }
601
+ return this.island(p, out, b, fail, "no WebAssembly form");
602
+ }
603
+ /** `out = value;`, or nothing when the value is unused. */
604
+ set(s, value) {
605
+ return s.out === "" ? "" : `${s.out}=${value};`;
606
+ }
607
+ /** Constants, the end of the input, positions and rules. */
608
+ constant(node, s) {
609
+ const { b, fail } = s;
610
+ if (Predicate.isTagged(node, "Succeed")) return Option.some(this.set(s, this.lit(node.value)));
611
+ if (Predicate.isTagged(node, "Sync")) return Option.some(this.set(s, `${this.const(node.evaluate)}()`));
612
+ if (Predicate.isTagged(node, "Fail")) {
613
+ this.failWith(b, fail, modeOf(node.mode));
614
+ return Option.some(this.set(s, "void 0"));
615
+ }
616
+ if (Predicate.isTagged(node, "Eof")) {
617
+ this.atEnd(b, 0);
618
+ b.op(Op.i32Eqz);
619
+ this.failIf(b, fail);
620
+ return Option.some(this.set(s, "void 0"));
621
+ }
622
+ if (Predicate.isTagged(node, "Location") || Predicate.isTagged(node, "RestLen")) {
623
+ if (s.out !== "") this.put(b, [() => b.get(0)]);
624
+ return Option.some(this.set(s, Predicate.isTagged(node, "Location") ? "T[i++]" : "E-T[i++]"));
625
+ }
626
+ if (Predicate.isTagged(node, "Suspend")) return Option.some(this.call(this.rule(node.resolve(), s.out !== ""), s.out, b, fail));
627
+ if (Predicate.isTagged(node, "Fixed") && this.kind === 1) {
628
+ this.end(b.get(0).i32(node.size).op(Op.i32Add)).op(Op.i32GtU);
629
+ this.failIf(b, fail);
630
+ if (s.out !== "") this.put(b, [() => b.get(0)]);
631
+ this.advance(b, node.size);
632
+ return Option.some(this.set(s, `${this.const(node.read)}(I,T[i++],S)`));
633
+ }
634
+ return Option.none();
635
+ }
636
+ /** Tokens, `escaped`, and parsers whose value is the input they consumed. */
637
+ slices(node, s) {
638
+ if (Predicate.isTagged(node, "Any") || Predicate.isTagged(node, "OneOf") || Predicate.isTagged(node, "Literal") || Predicate.isTagged(node, "TakeWhile")) return Option.some(this.token(s, node));
639
+ if (Predicate.isTagged(node, "Escaped")) return Option.some(this.escaped(s, node));
640
+ if (Predicate.isTagged(node, "TakeUntil") || Predicate.isTagged(node, "TakeUntilAny")) return Option.some(this.takeUntil(s, node));
641
+ if (Predicate.isTagged(node, "Taken")) {
642
+ if (node.encoding !== void 0) return Option.some(this.island(s.p, s.out, s.b, s.fail, "text slices are validated in JavaScript"));
643
+ return Option.some(this.sliceOf(s, node.self, this.kind === 0 ? "I.slice(T[i],T[i+1])" : "I.subarray(T[i],T[i+1])"));
644
+ }
645
+ if (Predicate.isTagged(node, "Span")) return Option.some(this.sliceOf(s, node.self, "{start:T[i],end:T[i+1]}"));
646
+ if (Predicate.isTagged(node, "WithTaken") || Predicate.isTagged(node, "WithSpan")) return Option.some(this.withSlice(s, node));
647
+ return Option.none();
648
+ }
649
+ /** `self`, whose value is `value`, an expression of its start and end `T[i]`, `T[i+1]`. */
650
+ sliceOf(s, self, value) {
651
+ const { b } = s;
652
+ const st = b.local();
653
+ b.get(0).set(st);
654
+ this.gen(self, "", b, s.fail, s.bf, s.d);
655
+ if (s.out === "") return "";
656
+ this.put(b, [() => b.get(st), () => b.get(0)]);
657
+ return `${s.out}=${value};i+=2;`;
658
+ }
659
+ /** `withTaken` and `withSpan`: the value of `self` and its slice or span. */
660
+ withSlice(s, node) {
661
+ const { b, out } = s;
662
+ if (out === "") return this.gen(node.self, "", b, s.fail, s.bf, s.d);
663
+ const st = b.local();
664
+ b.get(0).set(st);
665
+ this.put(b, [() => b.get(st)]);
666
+ const x = this.v(s.bf);
667
+ const start = this.v(s.bf);
668
+ const code = this.gen(node.self, x, b, s.fail, s.bf, s.d);
669
+ this.put(b, [() => b.get(0)]);
670
+ return `${start}=T[i++];${code}${out}=[${x},${Predicate.isTagged(node, "WithSpan") ? `{start:${start},end:T[i++]}` : `S.slice(${start},T[i++])`}];`;
671
+ }
672
+ /** Mapping, and callbacks on values. */
673
+ values(node, s) {
674
+ const { b, fail, d } = s;
675
+ if (Predicate.isTagged(node, "Map")) return Option.some(this.map(node, s.out, b, fail, s.bf, d));
676
+ if (Predicate.isTagged(node, "As")) {
677
+ this.gen(node.self, "", b, fail, s.bf, d);
678
+ return Option.some(this.set(s, this.lit(node.value)));
679
+ }
680
+ if (Predicate.isTagged(node, "Filter")) return Option.some(this.filter(s, node));
681
+ if (Predicate.isTagged(node, "TryMap")) {
682
+ const f = node.f;
683
+ return Option.some(this.valueIsland(node.self, s.out, b, fail, d, (v) => Result.getOrElse(f(v), () => Fail)));
684
+ }
685
+ if (Predicate.isTagged(node, "FilterMap")) {
686
+ const f = node.f;
687
+ return Option.some(this.valueIsland(node.self, s.out, b, fail, d, (v) => Option.getOrElse(f(v), () => Fail)));
688
+ }
689
+ if (Predicate.isTagged(node, "Tap")) {
690
+ const f = node.f;
691
+ return Option.some(this.valueIsland(node.self, s.out, b, fail, d, (v) => {
692
+ f(v);
693
+ return v;
694
+ }));
695
+ }
696
+ return Option.none();
697
+ }
698
+ /** `filter`: on a float, a test of the double; otherwise a value island. */
699
+ filter(s, node) {
700
+ const predicate = node.predicate;
701
+ if (predicate === Number.isFinite) {
702
+ const code = this.finiteFloat(node.self, s.out, s.b, s.fail, s.bf, s.d);
703
+ if (Option.isSome(code)) return code.value;
704
+ }
705
+ return this.valueIsland(node.self, s.out, s.b, s.fail, s.d, (v) => predicate(v) ? v : Fail);
706
+ }
707
+ /** Modes, diagnostics and lookahead. */
708
+ control(node, s) {
709
+ const { b, fail, out, d } = s;
710
+ if (Predicate.isTagged(node, "Mode")) return Option.some(this.withMode(b, node, fail, (bad) => this.gen(node.self, out, b, bad, s.bf, d)));
711
+ if (isDiagnostic(node)) return Option.some(this.gen(node.self, out, b, fail, s.bf, d));
712
+ if (Predicate.isTagged(node, "ResumeAfter")) {
713
+ if (out === "") return Option.some(this.gen(node.self, "", b, fail, s.bf, d));
714
+ const x = this.v(s.bf);
715
+ return Option.some(this.gen(node.self, x, b, fail, s.bf, d) + `${out}=R.some(${x});`);
716
+ }
717
+ if (Predicate.isTagged(node, "Opt") || Predicate.isTagged(node, "OrElseSucceed")) return Option.some(this.opt(s, node));
718
+ if (Predicate.isTagged(node, "Peek")) {
719
+ const st = b.local();
720
+ b.get(0).set(st);
721
+ const code = this.gen(node.self, out, b, fail, s.bf, d);
722
+ b.get(st).set(0);
723
+ return Option.some(code);
724
+ }
725
+ if (Predicate.isTagged(node, "Not")) return Option.some(this.not(s, node));
726
+ return Option.none();
727
+ }
728
+ /**
729
+ * Runs `body`, which branches to the label it is given on failure; then
730
+ * `failed` runs, and may fall through to the code after both.
731
+ */
732
+ attempt(b, body, failed) {
733
+ b.block((ok) => {
734
+ b.block((bad) => {
735
+ body(bad);
736
+ b.br(ok);
737
+ });
738
+ failed();
739
+ });
740
+ }
741
+ /** `cut` and `complete`: a failure of `body` with the mode `from` fails with `to`. */
742
+ withMode(b, node, fail, body) {
743
+ let code = "";
744
+ this.attempt(b, (bad) => {
745
+ code = body(bad);
746
+ }, () => {
747
+ b.gget(G.mode).i32(modeOf(node.from)).op(Op.i32Eq);
748
+ b.if(() => b.i32(modeOf(node.to)).gset(G.mode));
749
+ b.br(fail);
750
+ });
751
+ return code;
752
+ }
753
+ /** `opt` and `orElseSucceed`: the trace holds 1 when `self` matched. */
754
+ opt(s, node) {
755
+ const { b, out } = s;
756
+ const flag = out === "" ? -1 : this.slot(b);
757
+ const saved = this.save(b);
758
+ const x = out === "" ? "" : this.v(s.bf);
759
+ let code = "";
760
+ this.attempt(b, (bad) => {
761
+ code = this.gen(node.self, x, b, bad, s.bf, s.d);
762
+ if (flag >= 0) this.putAt(b, flag, 1);
763
+ }, () => {
764
+ this.unlessBacktrack(b, s.fail);
765
+ this.restore(b, saved);
766
+ });
767
+ if (out === "") return "";
768
+ const some = Predicate.isTagged(node, "Opt") ? `R.some(${x})` : `${x}`;
769
+ const none = Predicate.isTagged(node, "Opt") ? "R.none()" : `${this.const(node.value)}()`;
770
+ return `if(T[i++]===1){${code}${out}=${some}}else ${out}=${none};`;
771
+ }
772
+ /** `not`: succeeds, consuming nothing, where `self` fails with `Backtrack`. */
773
+ not(s, node) {
774
+ const { b, fail } = s;
775
+ const saved = this.save(b);
776
+ this.attempt(b, (bad) => {
777
+ this.gen(node.self, "", b, bad, s.bf, s.d);
778
+ this.restore(b, saved);
779
+ this.failWith(b, fail, Backtrack);
780
+ }, () => {
781
+ this.unlessBacktrack(b, fail);
782
+ this.restore(b, saved);
783
+ });
784
+ return this.set(s, "void 0");
785
+ }
786
+ /** Sequences, choice and repetition. */
787
+ structure(node, s) {
788
+ const { p, out, b, fail, bf, d } = s;
789
+ if (Predicate.isTagged(node, "Seq")) return Option.some(this.seq(node, out, b, fail, bf, d));
790
+ if (Predicate.isTagged(node, "Struct")) return Option.some(this.struct(s, node));
791
+ if (Predicate.isTagged(node, "ZipWith")) return Option.some(this.zipWith(s, node));
792
+ if (Predicate.isTagged(node, "Alt")) return Option.some(this.alt(node, out, b, fail, bf, d));
793
+ if (Predicate.isTagged(node, "Dispatch")) return Option.some(this.dispatch(p, node, out, b, fail, bf, d));
794
+ if (Predicate.isTagged(node, "Repeat")) return Option.some(this.repeat(node, out, b, fail, bf, this.collect(node.self, out, d)));
795
+ if (Predicate.isTagged(node, "Fold")) return Option.some(node.while === void 0 ? this.fold(node, out, b, fail, bf, d) : this.island(p, out, b, fail, "the condition needs the accumulator"));
796
+ if (Predicate.isTagged(node, "Separated")) return Option.some(this.separated(node, out, b, fail, bf, d, this.collect(node.self, out, d)));
797
+ return Option.none();
798
+ }
799
+ struct(s, node) {
800
+ const { b, out } = s;
801
+ if (out === "") {
802
+ for (const q of node.parsers) this.gen(q, "", b, s.fail, s.bf, s.d);
803
+ return "";
804
+ }
805
+ const vars = node.parsers.map(() => this.v(s.bf));
806
+ const code = node.parsers.map((q, i) => this.gen(q, vars[i], b, s.fail, s.bf, s.d)).join("");
807
+ if (node.keys.includes("__proto__")) return code + `${out}={};` + node.keys.map((k, i) => `${out}[${this.const(k)}]=${vars[i]};`).join("");
808
+ return code + `${out}={${node.keys.map((k, i) => `[${this.const(k)}]:${vars[i]}`).join(",")}};`;
809
+ }
810
+ zipWith(s, node) {
811
+ const { b, out } = s;
812
+ if (out === "") {
813
+ this.gen(node.self, "", b, s.fail, s.bf, s.d);
814
+ this.gen(node.that, "", b, s.fail, s.bf, s.d);
815
+ return "";
816
+ }
817
+ const x = this.v(s.bf);
818
+ const y = this.v(s.bf);
819
+ return this.gen(node.self, x, b, s.fail, s.bf, s.d) + this.gen(node.that, y, b, s.fail, s.bf, s.d) + `${out}=${this.const(node.f)}(${x},${y});`;
820
+ }
821
+ /** Writes `value` to the trace word at the address in local `slot`. */
822
+ putAt(b, slot, value) {
823
+ b.get(slot).i32(value).mem(Op.i32Store, 2, 0);
824
+ }
825
+ map(node, out, b, fail, bf, d) {
826
+ if (out === "") return this.gen(node.self, "", b, fail, bf, d);
827
+ if (node.f === toFloat) {
828
+ const code = this.float(node, out, b, fail, bf, d);
829
+ if (Option.isSome(code)) return code.value;
830
+ }
831
+ if (node.f === fromEntries && buildsEntries(node.self)) return this.entries(node.self, out, b, fail, bf, d);
832
+ const x = this.v(bf);
833
+ return this.gen(node.self, x, b, fail, bf, d) + `${out}=${this.const(node.f)}(${x});`;
834
+ }
835
+ /** Whether `Ascii.float` / `Text.float` (`map(text, toFloat)`) can be scanned and converted in one pass. */
836
+ floatScans(node) {
837
+ return node.f === toFloat && floatTexts.has(node.self) && Option.isSome(this.floatEncoding(node.self));
838
+ }
839
+ /**
840
+ * The encoding of the text parser of `Ascii.float` / `Text.float` (`none`
841
+ * for `Ascii`), when the scan reads it: decimal notation is ASCII, which
842
+ * every built-in encoding read here encodes as one unit per character.
843
+ */
844
+ floatEncoding(p) {
845
+ let taken = nodeOf(p);
846
+ while (Predicate.isTagged(taken, "Expected")) taken = nodeOf(taken.self);
847
+ if (!Predicate.isTagged(taken, "Taken")) return Option.none();
848
+ const enc = taken.encoding;
849
+ return this.native(enc) ? Option.some(enc) : Option.none();
850
+ }
851
+ /**
852
+ * `Ascii.float` and `Text.float`: decimal numbers are matched and
853
+ * converted in one pass (see `scanFloat`); the other forms (`nan`, `inf`)
854
+ * are matched by the float's text parser and converted by `toFloat`. The
855
+ * trace holds the double.
856
+ */
857
+ float(node, out, b, fail, bf, d) {
858
+ if (!this.floatScans(node)) return Option.none();
859
+ return Option.some(this.scanFloatThen(node, out, b, fail, false, bf, d));
860
+ }
861
+ /** `filter(float, Number.isFinite)`: the float scan, then a test of the double. */
862
+ finiteFloat(self, out, b, fail, bf, d) {
863
+ const node = nodeOf(self);
864
+ if (!Predicate.isTagged(node, "Map") || !this.floatScans(node)) return Option.none();
865
+ return Option.some(this.scanFloatThen(node, out, b, fail, true, bf, d));
866
+ }
867
+ /**
868
+ * The float at `p`: the scan of a decimal number, or else the float's text
869
+ * parser, whose text `toFloat` converts in JavaScript. A failure of the
870
+ * scan fails with `Backtrack`, as the text parser would. With `finite`, a
871
+ * value that isn't finite fails.
872
+ */
873
+ scanFloatThen(map, out, b, fail, finite, bf, d) {
874
+ const enc = Option.getOrUndefined(this.floatEncoding(map.self));
875
+ let taken = nodeOf(map.self);
876
+ while (Predicate.isTagged(taken, "Expected")) taken = nodeOf(taken.self);
877
+ const r = b.local();
878
+ const st = b.local();
879
+ b.get(0).set(st);
880
+ b.get(0).call(this.scanFloat(enc)).tee(r).i32(-1).op(Op.i32Eq);
881
+ b.if(() => {
882
+ if (Predicate.isTagged(taken, "Taken")) this.gen(taken.self, "", b, fail, bf, d);
883
+ b.get(st).get(0).call(Imp.float).gset(G.f);
884
+ }, () => {
885
+ b.get(r).i32(-2).op(Op.i32Eq);
886
+ this.failIf(b, fail);
887
+ b.get(r).set(0);
888
+ });
889
+ if (finite) {
890
+ b.gget(G.f).gget(G.f).op(Op.f64Sub).f64(0).op(Op.f64Ne);
891
+ this.failIf(b, fail);
892
+ }
893
+ if (out === "") return "";
894
+ this.putF64(b);
895
+ return `i=(i+1)&-2;${out}=F[i>>1];i+=2;`;
896
+ }
897
+ seq(node, out, b, fail, bf, d) {
898
+ const output = node.output;
899
+ if (out === "") {
900
+ for (const q of node.parsers) this.gen(q, "", b, fail, bf, d);
901
+ return "";
902
+ }
903
+ if (Predicate.isNumber(output)) return node.parsers.map((q, i) => this.gen(q, i === output ? out : "", b, fail, bf, d)).join("");
904
+ const keep = (i) => output === "tuple" || output.includes(i);
905
+ const vars = node.parsers.map((_, i) => keep(i) ? this.v(bf) : "");
906
+ return node.parsers.map((q, i) => this.gen(q, vars[i], b, fail, bf, d)).join("") + `${out}=[${(output === "tuple" ? vars.filter((v) => v !== "") : output.map((i) => vars[i])).join(",")}];`;
907
+ }
908
+ alt(node, out, b, fail, bf, d) {
909
+ const parsers = node.parsers;
910
+ if (Arr.isReadonlyArrayEmpty(parsers)) {
911
+ this.failWith(b, fail, Backtrack);
912
+ return "";
913
+ }
914
+ if (parsers.length === 1) return this.gen(parsers[0], out, b, fail, bf, d);
915
+ const saved = this.save(b);
916
+ const cases = [];
917
+ b.block((done) => {
918
+ parsers.forEach((q, i) => {
919
+ b.block((bad) => {
920
+ if (out !== "") this.put(b, [() => b.i32(i)]);
921
+ cases.push(this.gen(q, out, b, bad, bf, d));
922
+ b.br(done);
923
+ });
924
+ this.unlessBacktrack(b, fail);
925
+ this.restore(b, saved);
926
+ });
927
+ this.failWith(b, fail, Backtrack);
928
+ });
929
+ if (out === "") return "";
930
+ return `switch(T[i++]){${cases.map((c, i) => `case ${i}:{${c}break}`).join("")}}`;
931
+ }
932
+ dispatch(p, node, out, b, fail, bf, d) {
933
+ const { node: sel, peek } = selectorOf(node.selector);
934
+ const cases = node.cases;
935
+ if (cases === void 0 || !Predicate.isTagged(sel, "Any") || !this.native(sel.encoding)) return this.island(p, out, b, fail, "the selector runs in JavaScript");
936
+ const enc = sel.encoding;
937
+ const r = Option.map(Option.fromUndefinedOr(enc), (e) => this.reader(e));
938
+ const size = this.dispatchSize(r);
939
+ if (size === 0) return this.island(p, out, b, fail, "the selector runs in JavaScript");
940
+ const bytes = enc === void 0 && this.kind === 1;
941
+ const choose = (unit) => node.choose(bytes ? unit : charOf(unit));
942
+ const targets = [];
943
+ for (let unit = 0; unit < size; unit++) {
944
+ const q = choose(unit);
945
+ if (q !== void 0 && !targets.includes(q)) targets.push(q);
946
+ }
947
+ const closed = node.otherwise === void 0 && closedKeys(Reflect.ownKeys(cases), size, bytes);
948
+ const u = b.local();
949
+ const st = b.local();
950
+ b.get(0).set(st);
951
+ this.selectorUnit(b, r, size);
952
+ b.set(u);
953
+ b.get(u).i32(-1).op(Op.i32Eq);
954
+ this.failIf(b, fail);
955
+ const code = [];
956
+ let general = "";
957
+ b.block((done) => this.nested(b, targets.length + 2, (labels) => {
958
+ const table = Arr.makeBy(size, (unit) => {
959
+ const q = choose(unit);
960
+ return q === void 0 ? labels[targets.length] : labels[targets.indexOf(q)];
961
+ });
962
+ b.get(u).brTable(table, labels[targets.length + 1]);
963
+ }, (j) => {
964
+ if (j < targets.length) {
965
+ if (!peek) this.advance(b, Option.match(r, {
966
+ onNone: () => 1,
967
+ onSome: (x) => x.width
968
+ }));
969
+ if (out !== "") this.put(b, [() => b.i32(j)]);
970
+ code[j] = this.gen(targets[j], out, b, fail, bf, d);
971
+ b.br(done);
972
+ } else if (j === targets.length || closed) this.failWith(b, fail, Backtrack);
973
+ else {
974
+ b.get(st).set(0);
975
+ if (out !== "") this.put(b, [() => b.i32(targets.length)]);
976
+ general = this.island(p, out, b, fail, "the selector reads a code point beyond the fast units");
977
+ b.br(done);
978
+ }
979
+ }));
980
+ if (out === "") return "";
981
+ return `switch(T[i++]){${code.map((c, j) => `case ${j}:{${c}break}`).join("")}default:{${general}}}`;
982
+ }
983
+ /** How many units a `dispatch` switches on: the units that are whole code points, at most `TableSize`. */
984
+ dispatchSize(r) {
985
+ const limit = Option.match(r, {
986
+ onNone: () => this.kind === 0 ? 55296 : TableSize,
987
+ onSome: (x) => Math.min(x.fast, 55296)
988
+ });
989
+ return Math.min(limit, TableSize);
990
+ }
991
+ /** Pushes the unit a `dispatch` switches on: -1 at the end, `size` for a unit cut short. */
992
+ selectorUnit(b, r, size) {
993
+ if (Option.isNone(r)) {
994
+ this.atEnd(b, 0);
995
+ b.ifI32(() => b.i32(-1), () => this.load(b, 0));
996
+ return;
997
+ }
998
+ const reader = r.value;
999
+ reader.guard(b, 0);
1000
+ b.ifI32(() => reader.unit(b, 0), () => {
1001
+ this.atEnd(b, 0);
1002
+ b.ifI32(() => b.i32(-1), () => b.i32(size));
1003
+ });
1004
+ }
1005
+ /**
1006
+ * `n` nested blocks around `inner`, which gets their labels, outermost
1007
+ * first; after the end of block `j` (where a branch to its label goes),
1008
+ * `after(j)` runs.
1009
+ */
1010
+ nested(b, n, inner, after) {
1011
+ const open = (j, labels) => {
1012
+ if (j === n) return inner(labels);
1013
+ b.block((l) => open(j + 1, [...labels, l]));
1014
+ after(j);
1015
+ };
1016
+ open(0, []);
1017
+ }
1018
+ /** An element that is pushed to an array (or not kept). */
1019
+ collect(self, out, d) {
1020
+ return (b, fail, bf) => {
1021
+ if (out === "") {
1022
+ this.gen(self, "", b, fail, bf, d);
1023
+ return "";
1024
+ }
1025
+ const x = this.v(bf);
1026
+ return `${this.gen(self, x, b, fail, bf, d)}${out}.push(${x});`;
1027
+ };
1028
+ }
1029
+ /** The builder of a repetition: its count, then each element. */
1030
+ many(out, init, element, finish, bf) {
1031
+ if (out === "") return "";
1032
+ const n = this.v(bf);
1033
+ const k = this.v(bf);
1034
+ return `${init}${n}=T[i++];for(${k}=0;${k}<${n};${k}++){${element}}${finish}`;
1035
+ }
1036
+ /**
1037
+ * After a failed element or separator: fails unless it backtracked and
1038
+ * `n` reached `min`; otherwise restores the position and stops.
1039
+ */
1040
+ stop(b, fail, n, min, restore, done) {
1041
+ this.unlessBacktrack(b, fail);
1042
+ if (min > 0) {
1043
+ b.get(n).i32(min).op(Op.i32LtU);
1044
+ b.if(() => b.br(fail));
1045
+ }
1046
+ restore();
1047
+ b.br(done);
1048
+ }
1049
+ /** Counts an element in local `n` and goes on to the next. */
1050
+ nextElement(b, n, again) {
1051
+ b.get(n).i32(1).op(Op.i32Add).set(n);
1052
+ b.br(again);
1053
+ }
1054
+ /** Writes the count in local `n` to the trace word reserved at `slot`, if any. Returns no builder code. */
1055
+ counted(b, slot, n) {
1056
+ if (slot >= 0) b.get(slot).get(n).mem(Op.i32Store, 2, 0);
1057
+ return "";
1058
+ }
1059
+ /** An unbounded repetition that consumed nothing since `from` fails with `Cut`, as the interpreter does. */
1060
+ progress(b, fail, from) {
1061
+ b.get(0).get(from).op(Op.i32Eq);
1062
+ b.if(() => this.failWith(b, fail, Cut));
1063
+ }
1064
+ repeat(node, out, b, fail, bf, element, init = out === "" ? "" : `${out}=[];`, finish = "") {
1065
+ const { max, min } = node;
1066
+ const n = b.local();
1067
+ const slot = out === "" ? -1 : this.slot(b);
1068
+ let elementCode = "";
1069
+ b.i32(0).set(n);
1070
+ b.block((done) => {
1071
+ this.loop(b, (again) => {
1072
+ if (max !== Infinity) b.get(n).i32(max).op(Op.i32GeU).brIf(done);
1073
+ const saved = this.save(b);
1074
+ this.attempt(b, (bad) => {
1075
+ elementCode = element(b, bad, bf);
1076
+ if (max === Infinity) this.progress(b, fail, saved[0]);
1077
+ this.nextElement(b, n, again);
1078
+ }, () => this.stop(b, fail, n, min, () => this.restore(b, saved), done));
1079
+ });
1080
+ });
1081
+ return this.counted(b, slot, n) + this.many(out, init, elementCode, finish, bf);
1082
+ }
1083
+ fold(node, out, b, fail, bf, d) {
1084
+ const f = this.const(node.f);
1085
+ const element = (body, bad, vars) => {
1086
+ if (out === "") {
1087
+ this.gen(node.self, "", body, bad, vars, d);
1088
+ return "";
1089
+ }
1090
+ const x = this.v(vars);
1091
+ return `${this.gen(node.self, x, body, bad, vars, d)}${out}=${f}(${out},${x});`;
1092
+ };
1093
+ return this.repeat(node, out, b, fail, bf, element, out === "" ? "" : `${out}=${this.const(node.init)}();`);
1094
+ }
1095
+ separated(node, out, b, fail, bf, d, element, init = out === "" ? "" : `${out}=[];`, finish = "") {
1096
+ const { max, min } = node;
1097
+ if (max === 0) return out === "" ? "" : `${init}${finish}`;
1098
+ const n = b.local();
1099
+ const st = b.local();
1100
+ const t = b.local();
1101
+ const slot = out === "" ? -1 : this.slot(b);
1102
+ let elementCode = "";
1103
+ const mark = () => b.get(0).set(st).get(b.tp).set(t);
1104
+ const back = () => b.get(st).set(0).get(t).set(b.tp);
1105
+ b.i32(0).set(n);
1106
+ b.block((done) => {
1107
+ mark();
1108
+ this.attempt(b, (bad) => {
1109
+ elementCode = element(b, bad, bf);
1110
+ b.i32(1).set(n);
1111
+ }, () => {
1112
+ this.unlessBacktrack(b, fail);
1113
+ if (min > 0) b.br(fail);
1114
+ back();
1115
+ b.br(done);
1116
+ });
1117
+ this.loop(b, (again) => {
1118
+ if (max !== Infinity) b.get(n).i32(max).op(Op.i32GeU).brIf(done);
1119
+ mark();
1120
+ this.attempt(b, (bad) => this.gen(node.separator, "", b, bad, bf, d), () => this.stop(b, fail, n, min, back, done));
1121
+ if (max === Infinity) this.progress(b, fail, st);
1122
+ this.attempt(b, (bad) => {
1123
+ element(b, bad, new Vars());
1124
+ this.nextElement(b, n, again);
1125
+ }, () => this.stop(b, fail, n, min, back, done));
1126
+ });
1127
+ });
1128
+ return this.counted(b, slot, n) + this.many(out, init, elementCode, finish, bf);
1129
+ }
1130
+ /**
1131
+ * `map(self, Object.fromEntries)` where `buildsEntries(self)`: the scan is
1132
+ * the usual one, and the builder assigns each entry as it is read, as the
1133
+ * JIT does (see `internal/entries.ts`).
1134
+ */
1135
+ entries(p, out, b, fail, bf, d) {
1136
+ const node = nodeOf(p);
1137
+ if (Predicate.isTagged(node, "Mode")) return this.withMode(b, node, fail, (bad) => this.entries(node.self, out, b, bad, bf, d));
1138
+ if (Predicate.isTagged(node, "Seq") && Predicate.isNumber(node.output)) {
1139
+ const kept = node.output;
1140
+ return node.parsers.map((q, j) => j === kept ? this.entries(q, out, b, fail, bf, d) : this.gen(q, "", b, fail, bf, d)).join("");
1141
+ }
1142
+ if (isDiagnostic(node)) return this.entries(node.self, out, b, fail, bf, d);
1143
+ const pair = Predicate.isTagged(node, "Repeat") || Predicate.isTagged(node, "Separated") ? pairOf(node.self) : void 0;
1144
+ if ((Predicate.isTagged(node, "Repeat") || Predicate.isTagged(node, "Separated")) && pair !== void 0) {
1145
+ const deferred = this.v(bf);
1146
+ const element = (body, bad) => {
1147
+ const key = this.v(bf);
1148
+ const value = this.v(bf);
1149
+ return pair.parsers.map((q, j) => this.gen(q, j === pair.key ? key : j === pair.value ? value : "", body, bad, bf, d)).join("") + `if(${deferred}===void 0&&R.isPlainKey(${key}))${out}[${key}]=${value};else ${deferred}=R.addEntry(${out},${deferred},${key},${value});`;
1150
+ };
1151
+ const init = `${out}={};${deferred}=void 0;`;
1152
+ const finish = `if(${deferred}!==void 0)R.flushEntries(${out},${deferred});`;
1153
+ return Predicate.isTagged(node, "Repeat") ? this.repeat(node, out, b, fail, bf, element, init, finish) : this.separated(node, out, b, fail, bf, d, element, init, finish);
1154
+ }
1155
+ const x = this.v(bf);
1156
+ return this.gen(p, x, b, fail, bf, d) + `${out}=${this.const(fromEntries)}(${x});`;
1157
+ }
1158
+ /** How the scan reads an encoding's code points. */
1159
+ reader(enc) {
1160
+ if (enc === utf16le || enc === utf16be) {
1161
+ const [lo, hi] = enc === utf16le ? [0, 1] : [1, 0];
1162
+ return {
1163
+ width: 2,
1164
+ fast: 55296,
1165
+ guard: (b, pos) => this.end(b.get(pos).i32(1).op(Op.i32Add)).op(Op.i32LtU),
1166
+ unit: (b, pos) => {
1167
+ this.load(b, pos, lo);
1168
+ this.load(b, pos, hi);
1169
+ b.i32(8).op(Op.i32Shl, Op.i32Or);
1170
+ },
1171
+ decode: this.decoder(enc)
1172
+ };
1173
+ }
1174
+ return {
1175
+ width: 1,
1176
+ fast: enc === latin1 ? TableSize : fastLimit(enc),
1177
+ guard: (b, pos) => this.end(b.get(pos)).op(Op.i32LtU),
1178
+ unit: (b, pos) => this.load(b, pos),
1179
+ decode: enc === latin1 ? -1 : this.decoder(enc)
1180
+ };
1181
+ }
1182
+ /**
1183
+ * Pushes whether the code point in local `c`, known to be below `below`,
1184
+ * is in the set (taking `negate` into account). Known ranges compile to
1185
+ * comparisons, testing the accepted runs or the rejected ones, whichever
1186
+ * takes fewer; otherwise a table below `TableSize`, then the ranges or the
1187
+ * set's test above it.
1188
+ */
1189
+ member(cs, negate, c, b, below = 1114112) {
1190
+ const max = Math.min(below, this.kind === 1 && this.tokenBytes ? 256 : 1114112) - 1;
1191
+ const runs = acceptedRuns(cs, negate, max);
1192
+ const cost = (rs) => rs.reduce((n, [lo, hi]) => n + (lo === hi || lo === 0 || hi >= max ? 1 : 2), 0);
1193
+ /** Pushes whether `c` is in one of the runs. */
1194
+ const compare = (rs) => {
1195
+ if (Arr.isReadonlyArrayEmpty(rs)) {
1196
+ b.i32(0);
1197
+ return;
1198
+ }
1199
+ rs.forEach(([lo, hi], k) => {
1200
+ if (lo === hi) b.get(c).i32(lo).op(Op.i32Eq);
1201
+ else if (lo === 0) b.get(c).i32(hi).op(Op.i32LeU);
1202
+ else if (hi >= max) b.get(c).i32(lo).op(Op.i32GeU);
1203
+ else b.get(c).i32(lo).op(Op.i32Sub).i32(hi - lo).op(Op.i32LeU);
1204
+ if (k > 0) b.op(Op.i32Or);
1205
+ });
1206
+ };
1207
+ if (Option.isSome(runs)) {
1208
+ const accept = runs.value;
1209
+ const reject = Option.getOrElse(acceptedRuns({
1210
+ ...cs,
1211
+ ranges: accept
1212
+ }, true, max), () => []);
1213
+ if (Math.min(cost(accept), cost(reject)) <= 6) {
1214
+ if (cost(accept) <= cost(reject)) compare(accept);
1215
+ else {
1216
+ compare(reject);
1217
+ b.op(Op.i32Eqz);
1218
+ }
1219
+ return;
1220
+ }
1221
+ }
1222
+ const table = new Uint8Array(TableSize);
1223
+ for (let x = 0; x < TableSize; x++) table[x] = cs.table[x] === 1 !== negate ? 1 : 0;
1224
+ const callTest = () => {
1225
+ const test = cs.test;
1226
+ this.tests.push((x) => test(x) !== negate ? 1 : 0);
1227
+ b.i32(this.tests.length - 1).get(c).call(Imp.test);
1228
+ };
1229
+ const offset = this.table(table);
1230
+ if (offset < 0) {
1231
+ callTest();
1232
+ return;
1233
+ }
1234
+ if (max < TableSize) {
1235
+ b.get(c).mem(Op.i32Load8U, 0, offset);
1236
+ return;
1237
+ }
1238
+ const high = Option.map(runs, (rs) => rs.filter(([, hi]) => hi >= TableSize));
1239
+ b.get(c).i32(TableSize).op(Op.i32LtU);
1240
+ b.ifI32(() => b.get(c).mem(Op.i32Load8U, 0, offset), () => {
1241
+ if (Option.isSome(high) && cost(high.value) <= 6) compare(high.value);
1242
+ else callTest();
1243
+ });
1244
+ }
1245
+ /** Whether the token being compiled reads bytes as `Token` does (code points never exceed 255). */
1246
+ tokenBytes = false;
1247
+ /** Places a membership table in memory, returning its address. */
1248
+ table(t) {
1249
+ for (let i = 0; i < this.tables.length; i++) if (this.tables[i].every((x, j) => x === t[j])) return i * TableSize;
1250
+ if ((this.tables.length + 1) * TableSize > TablesEnd) return -1;
1251
+ this.tables.push(t);
1252
+ return (this.tables.length - 1) * TableSize;
1253
+ }
1254
+ /** Pushes whether a whole unit below `r.fast` is at `p`, leaving it in local `c`. `p < E` holds. */
1255
+ fastUnit(r, b, c) {
1256
+ if (r.width === 1) {
1257
+ r.unit(b, 0);
1258
+ b.tee(c).i32(r.fast).op(Op.i32LtU);
1259
+ return;
1260
+ }
1261
+ r.guard(b, 0);
1262
+ b.ifI32(() => {
1263
+ r.unit(b, 0);
1264
+ b.tee(c).i32(r.fast).op(Op.i32LtU);
1265
+ }, () => b.i32(0));
1266
+ }
1267
+ /**
1268
+ * Reads the code point at `p` into local `c` and its width into `w`,
1269
+ * branching to `stop` when it is malformed or cut short. `p < E` holds.
1270
+ */
1271
+ readCodePoint(enc, b, c, w, stop) {
1272
+ if (enc === void 0) {
1273
+ this.load(b, 0);
1274
+ b.set(c).i32(1).set(w);
1275
+ if (this.kind === 0) this.lenientPair(b, c, w);
1276
+ return;
1277
+ }
1278
+ const r = this.reader(enc);
1279
+ if (r.decode < 0) {
1280
+ r.unit(b, 0);
1281
+ b.set(c).i32(1).set(w);
1282
+ return;
1283
+ }
1284
+ this.fastUnit(r, b, c);
1285
+ b.if(() => b.i32(r.width).set(w), () => {
1286
+ b.get(0).call(r.decode).tee(c).i32(0).op(Op.i32LtS).brIf(stop);
1287
+ b.gget(G.w).set(w);
1288
+ });
1289
+ }
1290
+ /** `Token` on strings: a high surrogate in `c` followed by a low one is read as their pair. */
1291
+ lenientPair(b, c, w) {
1292
+ b.get(c).i32(64512).op(Op.i32And).i32(55296).op(Op.i32Eq);
1293
+ b.if(() => {
1294
+ b.get(0).i32(1).op(Op.i32Add).gget(G.len).op(Op.i32LtU);
1295
+ b.if(() => {
1296
+ this.load(b, 0, 1);
1297
+ const lo = b.local();
1298
+ b.tee(lo).i32(64512).op(Op.i32And).i32(56320).op(Op.i32Eq);
1299
+ b.if(() => {
1300
+ pair(b, c, lo);
1301
+ b.set(c);
1302
+ b.i32(2).set(w);
1303
+ });
1304
+ });
1305
+ });
1306
+ }
1307
+ token(s, node) {
1308
+ const enc = node.encoding;
1309
+ if (!this.native(enc)) return this.island(s.p, s.out, s.b, s.fail, "the encoding is decoded in JavaScript");
1310
+ this.tokenBytes = enc === void 0 && this.kind === 1;
1311
+ if (Predicate.isTagged(node, "Literal")) return this.literal(s, node);
1312
+ if (Predicate.isTagged(node, "TakeWhile")) return this.takeWhile(s, node);
1313
+ return this.single(s, node);
1314
+ }
1315
+ /** `any` and `oneOf`: one code point. */
1316
+ single(s, node) {
1317
+ const { b } = s;
1318
+ const enc = node.encoding;
1319
+ const c = b.local();
1320
+ const w = b.local();
1321
+ const st = b.local();
1322
+ b.get(0).set(st);
1323
+ this.attempt(b, (bad) => {
1324
+ this.atEnd(b, 0);
1325
+ b.brIf(bad);
1326
+ this.readCodePoint(enc, b, c, w, bad);
1327
+ if (Predicate.isTagged(node, "OneOf")) {
1328
+ this.member(enc === void 0 ? tokenSet(node.set, this.kind) : textSet(node.set), node.negate, c, b);
1329
+ b.op(Op.i32Eqz).brIf(bad);
1330
+ }
1331
+ b.get(0).get(w).op(Op.i32Add).set(0);
1332
+ }, () => this.failWith(b, s.fail, Backtrack));
1333
+ if (s.out === "") return "";
1334
+ if (enc !== void 0) {
1335
+ this.put(b, [() => b.get(c)]);
1336
+ return this.set(s, "R.charOf(T[i++])");
1337
+ }
1338
+ this.put(b, [() => b.get(st), () => b.get(0)]);
1339
+ return this.set(s, this.kind === 0 ? "I.slice(T[i],T[i+1]);i+=2" : "I[T[i]];i+=2");
1340
+ }
1341
+ takeWhile(s, node) {
1342
+ const { b } = s;
1343
+ const enc = node.encoding;
1344
+ const { max, min } = node;
1345
+ const set = {
1346
+ cs: enc === void 0 ? tokenSet(node.set, this.kind) : textSet(node.set),
1347
+ negate: node.negate,
1348
+ c: b.local()
1349
+ };
1350
+ const w = b.local();
1351
+ const st = b.local();
1352
+ b.get(0).set(st);
1353
+ const counted = max !== Infinity || min > 1;
1354
+ const n = b.local();
1355
+ if (counted) b.i32(0).set(n);
1356
+ const wide = enc === utf8 && s.out !== "" ? b.local() : -1;
1357
+ if (wide >= 0) b.i32(0).set(wide);
1358
+ b.block((stop) => {
1359
+ if (!counted && this.vectorRun(enc, set)) this.byteRun(b, set, stop);
1360
+ b.loop((again) => {
1361
+ this.atEnd(b, 0);
1362
+ b.brIf(stop);
1363
+ if (max !== Infinity) b.get(n).i32(max).op(Op.i32GeU).brIf(stop);
1364
+ this.whileStep(enc, b, set, w, wide, stop);
1365
+ if (counted) b.get(n).i32(1).op(Op.i32Add).set(n);
1366
+ b.br(again);
1367
+ });
1368
+ });
1369
+ if (min > 0) {
1370
+ if (counted) b.get(n).i32(min).op(Op.i32LtU);
1371
+ else b.get(0).get(st).op(Op.i32Eq);
1372
+ this.failIf(b, s.fail);
1373
+ }
1374
+ return this.sliceValue(s, enc, st, wide);
1375
+ }
1376
+ /**
1377
+ * The vector steps of an unbounded `takeWhile` on bytes, where every
1378
+ * byte is a token: sixteen bytes, up to the first that is not accepted,
1379
+ * which ends the run (most runs, tokens, end in the first sixteen); after
1380
+ * sixteen accepted, thirty-two at a time while all are. The
1381
+ * scalar loop takes the last fifteen bytes. Applies to `Token` and
1382
+ * Latin-1 text on bytes, where SIMD validates. (UTF-8, whose bytes from
1383
+ * 0x80 up are parts of code points, and strings, whose units are
1384
+ * sixteen-bit, stay scalar: on the JSON benchmark, whose runs are short,
1385
+ * a vector step there costs more than it saves.)
1386
+ */
1387
+ byteRun(b, set, stop) {
1388
+ const x = b.localV128();
1389
+ const y = b.localV128();
1390
+ const accepted = this.acceptedBytes(b, set);
1391
+ b.block((done) => {
1392
+ b.loop((again) => {
1393
+ this.end(b).get(0).op(Op.i32Sub).i32(16).op(Op.i32LtS).brIf(done);
1394
+ b.get(0).simd(Simd.v128Load, 0, Input$1).set(x);
1395
+ accepted(x);
1396
+ b.tee(x).simd(Simd.i8x16AllTrue);
1397
+ b.if(() => {
1398
+ this.advance(b, 16);
1399
+ b.block((short) => {
1400
+ b.loop((more) => {
1401
+ this.end(b).get(0).op(Op.i32Sub).i32(32).op(Op.i32LtS).brIf(short);
1402
+ b.get(0).simd(Simd.v128Load, 0, Input$1).set(x);
1403
+ b.get(0).simd(Simd.v128Load, 0, 131088).set(y);
1404
+ accepted(x);
1405
+ accepted(y);
1406
+ b.simd(Simd.v128And).simd(Simd.i8x16AllTrue).op(Op.i32Eqz).brIf(short);
1407
+ this.advance(b, 32);
1408
+ b.br(more);
1409
+ });
1410
+ });
1411
+ b.br(again);
1412
+ });
1413
+ b.get(0).get(x).simd(Simd.i8x16Bitmask).i32(-1).op(Op.i32Xor).op(Op.i32Ctz).op(Op.i32Add).set(0);
1414
+ b.br(stop);
1415
+ });
1416
+ });
1417
+ }
1418
+ /** Whether a `takeWhile` of `set` in `enc` has vector steps (see {@link byteRun}). */
1419
+ vectorRun(enc, set) {
1420
+ return this.kind === 1 && (enc === void 0 || enc === latin1) && simd() && accepts(set);
1421
+ }
1422
+ /**
1423
+ * Code that pushes, for the sixteen bytes in a local, 0xFF where the byte
1424
+ * is accepted and 0 where not: comparisons with the rejected bytes when
1425
+ * there are at most three of them (`takeTill` of a few stops), else two
1426
+ * swizzles of nibble tables for each half of the byte values. Its
1427
+ * constants are set up here, in locals.
1428
+ */
1429
+ acceptedBytes(b, set) {
1430
+ const rejected = [];
1431
+ for (let c = 0; c < 256 && rejected.length <= MaxStops; c++) if (set.cs.table[c] === 1 === set.negate) rejected.push(c);
1432
+ if (rejected.length <= MaxStops) {
1433
+ const stops = rejected.map((c) => {
1434
+ const l = b.localV128();
1435
+ b.i32(c).simd(Simd.i8x16Splat).set(l);
1436
+ return l;
1437
+ });
1438
+ return (x) => {
1439
+ b.v128(Zeros);
1440
+ for (const l of stops) b.get(x).get(l).simd(Simd.i8x16Eq).simd(Simd.v128Or);
1441
+ b.simd(Simd.v128Not);
1442
+ };
1443
+ }
1444
+ const tables = [nibbleTable(set, 0), nibbleTable(set, 8)].map((table, k) => {
1445
+ const lo = b.localV128();
1446
+ const bits = b.localV128();
1447
+ b.v128(table).set(lo).v128(k === 0 ? HighNibbleBits : UpperNibbleBits).set(bits);
1448
+ return [lo, bits];
1449
+ });
1450
+ return (x) => {
1451
+ tables.forEach(([lo, bits], k) => {
1452
+ b.get(lo).get(x).v128(LowNibbles).simd(Simd.v128And);
1453
+ nibbleSwizzle(b);
1454
+ b.get(bits).get(x).i32(4).simd(Simd.i8x16ShrU);
1455
+ nibbleSwizzle(b);
1456
+ b.simd(Simd.v128And);
1457
+ if (k > 0) b.simd(Simd.v128Or);
1458
+ });
1459
+ b.v128(Zeros).simd(Simd.i8x16Ne);
1460
+ };
1461
+ }
1462
+ /** One code point of a `takeWhile`: advances past it, or branches to `stop`. */
1463
+ whileStep(enc, b, set, w, wide, stop) {
1464
+ const r = Option.map(Option.fromUndefinedOr(enc), (e) => this.reader(e));
1465
+ if (Option.isSome(r) && r.value.decode >= 0) {
1466
+ const reader = r.value;
1467
+ this.fastUnit(reader, b, set.c);
1468
+ b.if(() => {
1469
+ this.member(set.cs, set.negate, set.c, b, reader.fast);
1470
+ b.op(Op.i32Eqz).brIf(stop);
1471
+ this.advance(b, reader.width);
1472
+ }, () => {
1473
+ b.get(0).call(reader.decode).tee(set.c).i32(0).op(Op.i32LtS).brIf(stop);
1474
+ if (wide >= 0) b.i32(1).set(wide);
1475
+ this.member(set.cs, set.negate, set.c, b);
1476
+ b.op(Op.i32Eqz).brIf(stop);
1477
+ b.get(0).gget(G.w).op(Op.i32Add).set(0);
1478
+ });
1479
+ return;
1480
+ }
1481
+ if (enc === void 0 && this.kind === 0) {
1482
+ this.load(b, 0);
1483
+ b.tee(set.c).i32(63488).op(Op.i32And).i32(55296).op(Op.i32Ne);
1484
+ b.if(() => {
1485
+ this.member(set.cs, set.negate, set.c, b, 65536);
1486
+ b.op(Op.i32Eqz).brIf(stop);
1487
+ this.advance(b, 1);
1488
+ }, () => this.codePointStep(enc, b, set, w, stop));
1489
+ return;
1490
+ }
1491
+ this.codePointStep(enc, b, set, w, stop);
1492
+ }
1493
+ /** Reads a code point and tests it, advancing past it, or branches to `stop`. */
1494
+ codePointStep(enc, b, set, w, stop) {
1495
+ this.readCodePoint(enc, b, set.c, w, stop);
1496
+ this.member(set.cs, set.negate, set.c, b);
1497
+ b.op(Op.i32Eqz).brIf(stop);
1498
+ b.get(0).get(w).op(Op.i32Add).set(0);
1499
+ }
1500
+ /**
1501
+ * `takeUntil` and `takeUntilAny` on bytes: Teddy (as in ripgrep). Sixteen
1502
+ * starts at a time, the first `m` bytes of every literal (up to three)
1503
+ * are tested at once, with nibble tables: a byte belongs to bucket k at
1504
+ * position j when bit k is set both in the low-nibble table at its low
1505
+ * nibble and in the high-nibble table at its high nibble, and a start is
1506
+ * a candidate when one bucket holds at every position. Each candidate is
1507
+ * checked against the literals in full; the last starts, fewer than
1508
+ * sixteen, are checked one at a time. Without SIMD, with a range, or on
1509
+ * other input, the search runs in JavaScript.
1510
+ */
1511
+ takeUntil(s, node) {
1512
+ const literals = Predicate.isTagged(node, "TakeUntil") ? [node.literal] : node.literals;
1513
+ const bytes = literals.filter(Predicate.isUint8Array);
1514
+ const shortest = Math.min(...bytes.map((lit) => lit.length));
1515
+ if (!(this.kind === 1 && node.encoding === void 0 && node.min === 0 && node.max === Infinity && bytes.length === literals.length && shortest > 0 && shortest !== Infinity && bytes.length <= MaxUntil && simd())) return this.island(s.p, s.out, s.b, s.fail, "the search runs in JavaScript");
1516
+ const { b, fail } = s;
1517
+ const m = Math.min(MaxPositions, shortest);
1518
+ const st = b.local();
1519
+ const c = b.local();
1520
+ const mask = b.local();
1521
+ const acc = b.localV128();
1522
+ const position = this.teddyPosition(b, bytes, m, acc);
1523
+ b.get(0).set(st);
1524
+ b.block((found) => {
1525
+ b.block((tail) => {
1526
+ b.loop((again) => {
1527
+ this.end(b).get(0).op(Op.i32Sub).i32(15 + m).op(Op.i32LtS).brIf(tail);
1528
+ for (let j = 0; j < m; j++) {
1529
+ position(j);
1530
+ if (j > 0) b.simd(Simd.v128And);
1531
+ }
1532
+ b.tee(acc).simd(Simd.v128AnyTrue).op(Op.i32Eqz);
1533
+ b.if(() => {
1534
+ this.advance(b, 16);
1535
+ b.br(again);
1536
+ });
1537
+ b.get(acc).v128(Zeros).simd(Simd.i8x16Ne).simd(Simd.i8x16Bitmask).set(mask);
1538
+ b.loop((bits) => {
1539
+ b.get(0).get(mask).op(Op.i32Ctz).op(Op.i32Add).set(c);
1540
+ this.literalAt(b, bytes, c, found);
1541
+ b.get(mask).get(mask).i32(1).op(Op.i32Sub).op(Op.i32And).tee(mask).brIf(bits);
1542
+ });
1543
+ this.advance(b, 16);
1544
+ b.br(again);
1545
+ });
1546
+ });
1547
+ b.loop((again) => {
1548
+ this.end(b).get(0).op(Op.i32Sub).i32(shortest).op(Op.i32LtS);
1549
+ this.failIf(b, fail);
1550
+ b.get(0).set(c);
1551
+ this.literalAt(b, bytes, c, found);
1552
+ this.advance(b, 1);
1553
+ b.br(again);
1554
+ });
1555
+ });
1556
+ return this.sliceValue(s, void 0, st, -1);
1557
+ }
1558
+ /**
1559
+ * Code that pushes, for the sixteen starts from the cursor, what position
1560
+ * `j` of the literals says: with at most three distinct bytes there,
1561
+ * 0xFF where the byte is one of them (`i8x16.eq`); otherwise Teddy's
1562
+ * bucket bits, from two nibble-table swizzles. Either way a start is a
1563
+ * candidate where the AND over the positions is not zero. The constants
1564
+ * are set up here, in locals; `v` is a scratch local.
1565
+ */
1566
+ teddyPosition(b, literals, m, v) {
1567
+ const distinct = Array.from({ length: m }, (_, j) => Arr.dedupe(literals.map((lit) => lit[j] ?? 0)));
1568
+ if (distinct.every((bytes) => bytes.length <= MaxStops)) {
1569
+ const splats = distinct.map((bytes) => bytes.map((byte) => {
1570
+ const l = b.localV128();
1571
+ b.i32(byte).simd(Simd.i8x16Splat).set(l);
1572
+ return l;
1573
+ }));
1574
+ return (j) => {
1575
+ b.get(0).simd(Simd.v128Load, 0, Input$1 + j).set(v);
1576
+ b.v128(Zeros);
1577
+ for (const l of splats[j] ?? []) b.get(v).get(l).simd(Simd.i8x16Eq).simd(Simd.v128Or);
1578
+ };
1579
+ }
1580
+ const nibbles = b.localV128();
1581
+ b.v128(LowNibbles).set(nibbles);
1582
+ const tables = teddyTables(literals, m).map(([lo, hi]) => {
1583
+ const l = b.localV128();
1584
+ const h = b.localV128();
1585
+ b.v128(lo).set(l).v128(hi).set(h);
1586
+ return [l, h];
1587
+ });
1588
+ return (j) => {
1589
+ const [lo, hi] = tables[j] ?? [-1, -1];
1590
+ b.get(0).simd(Simd.v128Load, 0, Input$1 + j).set(v);
1591
+ b.get(lo).get(v).get(nibbles).simd(Simd.v128And);
1592
+ nibbleSwizzle(b);
1593
+ b.get(hi).get(v).i32(4).simd(Simd.i8x16ShrU);
1594
+ nibbleSwizzle(b);
1595
+ b.simd(Simd.v128And);
1596
+ };
1597
+ }
1598
+ /** Moves the cursor to `c` and branches to `found` when one of `literals` starts at `c`. */
1599
+ literalAt(b, literals, c, found) {
1600
+ for (const lit of literals) b.block((next) => {
1601
+ this.end(b).get(c).op(Op.i32Sub).i32(lit.length).op(Op.i32LtS).brIf(next);
1602
+ const bytes = Array.from(lit);
1603
+ for (let i = 0; i < bytes.length;) {
1604
+ const n = chunkSize(bytes.length - i);
1605
+ b.get(c);
1606
+ compareChunk(b, bytes.slice(i, i + n), [], Input$1 + i);
1607
+ b.brIf(next);
1608
+ i += n;
1609
+ }
1610
+ b.get(c).set(0).br(found);
1611
+ });
1612
+ }
1613
+ /** The trace and builder code of a `takeWhile`'s slice `[st, p)`. */
1614
+ sliceValue(s, enc, st, wide) {
1615
+ const { b } = s;
1616
+ if (s.out === "") return "";
1617
+ if (enc === void 0 && this.kind === 1) {
1618
+ this.put(b, [() => b.get(st), () => b.get(0)]);
1619
+ return this.set(s, "I.subarray(T[i],T[i+1]);i+=2");
1620
+ }
1621
+ const start = () => {
1622
+ b.get(st);
1623
+ if (wide >= 0) b.get(wide).i32(31).op(Op.i32Shl).op(Op.i32Or);
1624
+ };
1625
+ if (this.plainStrings) {
1626
+ this.put(b, [start, () => b.get(0)]);
1627
+ return this.set(s, `${this.decodeSlice(enc)};i+=2`);
1628
+ }
1629
+ this.put(b, [
1630
+ start,
1631
+ () => b.get(0),
1632
+ () => this.internCall(b, st),
1633
+ () => b.gget(G.w)
1634
+ ]);
1635
+ return this.interned(s.out, this.decodeSlice(enc));
1636
+ }
1637
+ /** Pushes the cache slot of `[st, p)` (see `intern`), testing the length inline: most long slices aren't hashed. */
1638
+ internCall(b, st) {
1639
+ b.get(0).get(st).op(Op.i32Sub).i32(MaxInterned).op(Op.i32GtU);
1640
+ b.ifI32(() => b.i32(-1), () => b.get(st).get(0).call(this.intern()));
1641
+ }
1642
+ /**
1643
+ * Builder code for the string of the slice of a `takeWhile` at `T[i]`,
1644
+ * `T[i+1]`. A UTF-8 slice whose start is not negative is ASCII, which
1645
+ * `R.ascii` decodes without looking for longer sequences.
1646
+ */
1647
+ decodeSlice(enc) {
1648
+ if (enc === utf8 && this.kind === 1) return `(T[i]<0?${this.const(enc.text)}(I,T[i]&2147483647,T[i+1]):R.ascii(I,T[i],T[i+1]))`;
1649
+ return enc !== void 0 && this.kind === 1 ? `${this.const(enc.text)}(I,T[i],T[i+1])` : "I.slice(T[i],T[i+1])";
1650
+ }
1651
+ /** While generating the pieces of an `escaped` whose single-piece strings are interned. */
1652
+ plainStrings = false;
1653
+ literal(s, node) {
1654
+ const { b, fail } = s;
1655
+ const units = this.literalUnits(node);
1656
+ if (Result.isFailure(units)) return this.island(s.p, s.out, b, fail, units.failure);
1657
+ const { codes, constant } = units.success;
1658
+ const len = codes.length;
1659
+ const st = b.local();
1660
+ b.get(0).set(st);
1661
+ if (len > 0) {
1662
+ this.end(b).get(0).op(Op.i32Sub).i32(len).op(Op.i32LtS);
1663
+ this.failIf(b, fail);
1664
+ this.compareUnits(b, codes, node.caseless, fail);
1665
+ this.advance(b, len);
1666
+ }
1667
+ if (s.out === "") return "";
1668
+ if (constant) return this.set(s, this.lit(node.literal));
1669
+ this.put(b, [() => b.get(st)]);
1670
+ return this.set(s, this.kind === 0 ? `I.slice(T[i],T[i]+${len});i++` : `I.subarray(T[i],T[i]+${len});i++`);
1671
+ }
1672
+ /**
1673
+ * The units a literal matches, and whether its value is the literal itself
1674
+ * (rather than the input it matched, as a caseless one returns), or why it
1675
+ * runs in JavaScript.
1676
+ */
1677
+ /**
1678
+ * Fails unless the input at the cursor holds `codes` (folding ASCII
1679
+ * letters with `caseless`): the units' bytes compared sixteen, eight,
1680
+ * four, two and one at a time, with `v128`, `i64` and `i32` loads, a
1681
+ * caseless letter's byte ORed with 0x20 first.
1682
+ */
1683
+ compareUnits(b, codes, caseless, fail) {
1684
+ const { bytes, fold } = unitBytes(codes, caseless, this.kind === 0 ? 2 : 1);
1685
+ const at = b.local();
1686
+ if (this.kind === 0) b.get(0).i32(1).op(Op.i32Shl).set(at);
1687
+ else b.get(0).set(at);
1688
+ for (let i = 0; i < bytes.length;) {
1689
+ const n = chunkSize(bytes.length - i);
1690
+ b.get(at);
1691
+ compareChunk(b, bytes.slice(i, i + n), fold.slice(i, i + n), Input$1 + i);
1692
+ this.failIf(b, fail);
1693
+ i += n;
1694
+ }
1695
+ }
1696
+ literalUnits(node) {
1697
+ const lit = node.literal;
1698
+ const enc = node.encoding;
1699
+ if (enc !== void 0) {
1700
+ if (node.caseless || !Predicate.isString(lit)) return Result.fail("caseless text literal");
1701
+ const encoded = enc.encode(lit);
1702
+ return Result.succeed({
1703
+ codes: Predicate.isString(encoded) ? unitsOf(encoded) : Array.from(encoded),
1704
+ constant: true
1705
+ });
1706
+ }
1707
+ const constant = !node.caseless;
1708
+ if (Predicate.isString(lit)) return Result.succeed(this.kind === 0 ? {
1709
+ codes: unitsOf(lit),
1710
+ constant
1711
+ } : {
1712
+ codes: Array.from(utf8Encoder.encode(lit)),
1713
+ constant: false
1714
+ });
1715
+ if (lit instanceof Uint8Array && this.kind === 1) return Result.succeed({
1716
+ codes: Array.from(lit),
1717
+ constant
1718
+ });
1719
+ return Result.fail("the literal is not of the input's kind");
1720
+ }
1721
+ /** `escaped`: segments of `normal` and escapes after the control character. */
1722
+ escaped(s, node) {
1723
+ const { b } = s;
1724
+ const enc = node.encoding;
1725
+ if (!this.native(enc)) return this.island(s.p, s.out, b, s.fail, "the encoding is decoded in JavaScript");
1726
+ const r = Option.map(Option.fromUndefinedOr(enc), (e) => this.reader(e));
1727
+ if (Option.isSome(r) && !(node.control < r.value.fast)) return this.island(s.p, s.out, b, s.fail, "the control character is decoded");
1728
+ const pieces = !node.raw && s.out !== "";
1729
+ const e = {
1730
+ r,
1731
+ pieces,
1732
+ internsWhole: pieces && Predicate.isTagged(nodeOf(node.normal), "TakeWhile") && (enc !== void 0 || this.kind === 0),
1733
+ start: b.local(),
1734
+ seg: b.local(),
1735
+ ok: b.local(),
1736
+ ts: b.local(),
1737
+ count: b.local(),
1738
+ pieceStart: b.local(),
1739
+ slot: pieces ? this.slot(b) : -1,
1740
+ x: pieces ? this.v(s.bf) : ""
1741
+ };
1742
+ let normal = "";
1743
+ let escape = "";
1744
+ b.get(0).set(e.start);
1745
+ b.i32(0).set(e.count);
1746
+ b.block((exit) => {
1747
+ this.loop(b, (again) => {
1748
+ this.atEnd(b, 0);
1749
+ b.brIf(exit);
1750
+ normal = this.escapedNormal(s, node, e, again);
1751
+ if (Option.isNone(r)) {
1752
+ this.atEnd(b, 0);
1753
+ b.brIf(exit);
1754
+ this.load(b, 0);
1755
+ } else {
1756
+ r.value.guard(b, 0);
1757
+ b.op(Op.i32Eqz).brIf(exit);
1758
+ r.value.unit(b, 0);
1759
+ }
1760
+ b.i32(node.control).op(Op.i32Ne).brIf(exit);
1761
+ this.advance(b, Option.match(r, {
1762
+ onNone: () => 1,
1763
+ onSome: (x) => x.width
1764
+ }));
1765
+ if (pieces) this.put(b, [() => b.i32(1)]);
1766
+ escape = this.gen(node.escape, e.x, b, s.fail, s.bf, s.d);
1767
+ b.get(e.count).i32(1).op(Op.i32Add).set(e.count);
1768
+ b.br(again);
1769
+ });
1770
+ });
1771
+ return this.escapedValue(s, node, e, normal, escape);
1772
+ }
1773
+ /**
1774
+ * A segment of `normal`: one that consumed input continues the loop; one
1775
+ * that matched nothing, or failed with `Backtrack`, is dropped (with its
1776
+ * trace) for the control character to be tested.
1777
+ */
1778
+ escapedNormal(s, node, e, again) {
1779
+ const { b } = s;
1780
+ let code = "";
1781
+ b.get(0).set(e.seg).get(b.tp).set(e.ts).i32(0).set(e.ok);
1782
+ b.block((bad) => {
1783
+ if (e.pieces) this.put(b, [() => b.i32(0)]);
1784
+ const plain = this.plainStrings;
1785
+ this.plainStrings = e.internsWhole;
1786
+ code = this.gen(node.normal, e.x, b, bad, s.bf, s.d);
1787
+ this.plainStrings = plain;
1788
+ b.i32(1).set(e.ok);
1789
+ });
1790
+ b.get(e.ok);
1791
+ b.if(() => {
1792
+ b.get(0).get(e.seg).op(node.raw ? Op.i32Eq : Op.i32Ne);
1793
+ if (node.raw) {
1794
+ b.if(() => this.failWith(b, s.fail, Cut));
1795
+ b.br(again);
1796
+ return;
1797
+ }
1798
+ b.if(() => {
1799
+ b.get(e.count).i32(1).op(Op.i32Add).set(e.count);
1800
+ b.get(e.seg).set(e.pieceStart);
1801
+ b.br(again);
1802
+ });
1803
+ b.get(e.ts).set(b.tp);
1804
+ }, () => {
1805
+ this.unlessBacktrack(b, s.fail);
1806
+ b.get(e.seg).set(0).get(e.ts).set(b.tp);
1807
+ });
1808
+ return code;
1809
+ }
1810
+ /** The trace and builder code of an `escaped`'s value, from its pieces' code. */
1811
+ escapedValue(s, node, e, normal, escape) {
1812
+ const { b, out } = s;
1813
+ const enc = node.encoding;
1814
+ if (out === "") return "";
1815
+ if (node.raw) {
1816
+ this.put(b, [() => b.get(e.start), () => b.get(0)]);
1817
+ if (enc !== void 0 && this.kind === 1) return `${out}=${this.const(enc.text)}(I,T[i],T[i+1]);i+=2;`;
1818
+ return `${out}=${this.kind === 0 ? "I.slice(T[i],T[i+1])" : "I.subarray(T[i],T[i+1])"};i+=2;`;
1819
+ }
1820
+ b.get(e.slot).get(e.count).mem(Op.i32Store, 2, 0);
1821
+ const n = this.v(s.bf);
1822
+ const k = this.v(s.bf);
1823
+ const loop = `${out}="";for(${k}=0;${k}<${n};${k}++){if(T[i++]===0){${normal}}else{${escape}}${out}+=${e.x};}`;
1824
+ if (!e.internsWhole) return `${n}=T[i++];if(${n}===1&&T[i]===0){i++;${normal}${out}=${e.x}}else{${loop}}`;
1825
+ b.get(e.count).i32(1).op(Op.i32Eq);
1826
+ b.if(() => {
1827
+ b.get(e.slot).mem(Op.i32Load, 2, 4).op(Op.i32Eqz);
1828
+ b.if(() => this.put(b, [() => this.internCall(b, e.pieceStart), () => b.gget(G.w)]));
1829
+ });
1830
+ return `${n}=T[i++];if(${n}===1&&T[i]===0){i++;${this.interned(out, this.decodeSlice(enc))}}else{${loop}}`;
1831
+ }
1832
+ /** The strings of the cache slots, and the version of the slot each was decoded from. */
1833
+ interning = false;
1834
+ internedStrings = [];
1835
+ internedVersions = /*#__PURE__*/ new Int32Array(0);
1836
+ internIndex = -1;
1837
+ /**
1838
+ * Builder code for a string slice traced as start, end, slot and version
1839
+ * (see `intern`): the string decoded from that slot's version if there is
1840
+ * one, else `decode`, which is then kept for the slot.
1841
+ */
1842
+ interned(out, decode) {
1843
+ if (!this.interning) {
1844
+ this.interning = true;
1845
+ this.internedStrings = new Array(StringSlots).fill("");
1846
+ this.internedVersions = new Int32Array(StringSlots).fill(-1);
1847
+ }
1848
+ const ks = this.const(this.internedStrings);
1849
+ const kv = this.const(this.internedVersions);
1850
+ return `${out}=T[i+2];if(${out}>=0&&${kv}[${out}]===T[i+3])${out}=${ks}[${out}];else if(${out}>=0){${kv}[${out}]=T[i+3];${out}=${ks}[${out}]=${decode}}else ${out}=${decode};i+=4;`;
1851
+ }
1852
+ /**
1853
+ * `(start, end) -> slot`: the cache slot of the units of `[start, end)`,
1854
+ * or -1 if there are more than `MaxInterned`, with the slot's version in
1855
+ * `G.w`. A slot holds the units of the latest slice hashed to it, and its
1856
+ * version changes whenever they do, so every slice traced with a slot and
1857
+ * a version has the same units, and the same string: the builder decodes
1858
+ * it once per version. The cache outlives a parse, and backtracking can't
1859
+ * invalidate it.
1860
+ */
1861
+ intern() {
1862
+ if (this.internIndex >= 0) return this.internIndex;
1863
+ const [index, b] = this.reserve(Ty.pair, 2);
1864
+ this.internIndex = index;
1865
+ const start = 0;
1866
+ const end = 1;
1867
+ const len = b.local();
1868
+ const h = b.local();
1869
+ const k = b.local();
1870
+ const addr = b.local();
1871
+ const ver = b.local();
1872
+ const width = this.kind === 0 ? 2 : 1;
1873
+ const unitAt = (pos) => this.kind === 0 ? (pos(), b.i32(1).op(Op.i32Shl).mem(Op.i32Load16U, 1, Input$1)) : (pos(), b.mem(Op.i32Load8U, 0, Input$1));
1874
+ const cached = (j) => {
1875
+ b.get(addr);
1876
+ j();
1877
+ if (width === 2) b.i32(1).op(Op.i32Shl);
1878
+ b.op(Op.i32Add);
1879
+ b.mem(width === 2 ? Op.i32Load16U : Op.i32Load8U, width === 2 ? 1 : 0, 8);
1880
+ };
1881
+ b.get(end).get(start).op(Op.i32Sub).tee(len).i32(MaxInterned).op(Op.i32GtU);
1882
+ b.if(() => b.i32(-1).op(Op.return));
1883
+ b.get(len).set(h);
1884
+ b.get(start).set(k);
1885
+ b.block((done) => b.loop((again) => {
1886
+ b.get(k).get(end).op(Op.i32GeU).brIf(done);
1887
+ b.get(h).i32(31).op(Op.i32Mul);
1888
+ unitAt(() => b.get(k));
1889
+ b.op(Op.i32Add).set(h);
1890
+ b.get(k).i32(1).op(Op.i32Add).set(k);
1891
+ b.br(again);
1892
+ }));
1893
+ b.get(h).get(h).i32(10).op(Op.i32ShrU).op(Op.i32Xor).i32(1023).op(Op.i32And).set(h);
1894
+ b.get(h).i32(SlotBytes).op(Op.i32Mul).i32(Strings).op(Op.i32Add).set(addr);
1895
+ b.block((differ) => {
1896
+ b.get(addr).mem(Op.i32Load, 2, 4).get(len).op(Op.i32Ne).brIf(differ);
1897
+ b.i32(0).set(k);
1898
+ b.block((same) => b.loop((again) => {
1899
+ b.get(k).get(len).op(Op.i32GeU).brIf(same);
1900
+ cached(() => b.get(k));
1901
+ unitAt(() => b.get(start).get(k).op(Op.i32Add));
1902
+ b.op(Op.i32Ne).brIf(differ);
1903
+ b.get(k).i32(1).op(Op.i32Add).set(k);
1904
+ b.br(again);
1905
+ }));
1906
+ b.get(addr).mem(Op.i32Load, 2, 0).gset(G.w);
1907
+ b.get(h).op(Op.return);
1908
+ });
1909
+ b.get(addr).mem(Op.i32Load, 2, 0).i32(1).op(Op.i32Add).set(ver);
1910
+ b.get(addr).get(ver).mem(Op.i32Store, 2, 0);
1911
+ b.get(addr).get(len).mem(Op.i32Store, 2, 4);
1912
+ b.i32(0).set(k);
1913
+ b.block((done) => b.loop((again) => {
1914
+ b.get(k).get(len).op(Op.i32GeU).brIf(done);
1915
+ b.get(addr).get(k);
1916
+ if (width === 2) b.i32(1).op(Op.i32Shl);
1917
+ b.op(Op.i32Add);
1918
+ unitAt(() => b.get(start).get(k).op(Op.i32Add));
1919
+ b.mem(width === 2 ? Op.i32Store16 : Op.i32Store8, width === 2 ? 1 : 0, 8);
1920
+ b.get(k).i32(1).op(Op.i32Add).set(k);
1921
+ b.br(again);
1922
+ }));
1923
+ b.get(ver).gset(G.w);
1924
+ b.get(h);
1925
+ return index;
1926
+ }
1927
+ /**
1928
+ * `(pos, end, len, tp, tlim) -> p | -1`: sets up the globals of a parse
1929
+ * and runs the root, in one call from JavaScript (setting a global from
1930
+ * JavaScript costs about as much as a call).
1931
+ */
1932
+ starter(root) {
1933
+ const [index, b] = this.reserve(Ty.start, 5);
1934
+ b.get(1).gset(G.end).get(2).gset(G.len).get(3).gset(G.tp).get(4).gset(G.tlim);
1935
+ b.i32(0).gset(G.nv).i32(0).gset(G.mode);
1936
+ b.get(0).call(root);
1937
+ return index;
1938
+ }
1939
+ /**
1940
+ * `(src, n) -> count`, for string input: widens the `n` bytes of UTF-8 at
1941
+ * `src`, which `TextEncoder#encodeInto` wrote, to the string's UTF-16
1942
+ * units at `Input`, sixteen ASCII bytes at a time with SIMD (where it is
1943
+ * available) and eight without. `encodeInto` writes each
1944
+ * lone surrogate as U+FFFD, which is one unit as well, so every unit is in
1945
+ * place; the units that are U+FFFD (or were a lone surrogate) are listed
1946
+ * as 32-bit indices from `(src + n + 3) & -4`, for JavaScript to copy from
1947
+ * the string. Returns their number.
1948
+ */
1949
+ widener() {
1950
+ const [index, b] = this.reserve(Ty.pair, 2);
1951
+ const src = 0;
1952
+ const n = 1;
1953
+ const end = b.local();
1954
+ const k = b.local();
1955
+ const c = b.local();
1956
+ const cp = b.local();
1957
+ const count = b.local();
1958
+ const list = b.local();
1959
+ const x = b.localI64();
1960
+ const byte = (at) => b.get(src).mem(Op.i32Load8U, 0, at);
1961
+ const cont = (at, shift) => {
1962
+ byte(at);
1963
+ b.i32(63).op(Op.i32And);
1964
+ if (shift > 0) b.i32(shift).op(Op.i32Shl);
1965
+ b.op(Op.i32Or);
1966
+ };
1967
+ const unit = (delta, push) => {
1968
+ b.get(k).i32(1).op(Op.i32Shl);
1969
+ push();
1970
+ b.mem(Op.i32Store16, 1, Input$1 + 2 * delta);
1971
+ };
1972
+ const step = (bytes, units, again) => {
1973
+ b.get(src).i32(bytes).op(Op.i32Add).set(src);
1974
+ b.get(k).i32(units).op(Op.i32Add).set(k);
1975
+ b.br(again);
1976
+ };
1977
+ /** Spreads four bytes (the low 32 bits of `x`, shifted right by `shift`) to four 16-bit units. */
1978
+ const spread = (shift) => {
1979
+ b.get(x);
1980
+ if (shift > 0) b.i64(BigInt(shift)).op(Op.i64ShrU);
1981
+ b.i64(4294967295n).op(Op.i64And);
1982
+ b.tee(x).get(x).i64(16n).op(Op.i64Shl).op(Op.i64Or).i64(281470681808895n).op(Op.i64And);
1983
+ b.tee(x).get(x).i64(8n).op(Op.i64Shl).op(Op.i64Or).i64(71777214294589695n).op(Op.i64And);
1984
+ };
1985
+ b.get(src).get(n).op(Op.i32Add).tee(end).i32(3).op(Op.i32Add).i32(-4).op(Op.i32And).set(list);
1986
+ b.block((done) => b.loop((again) => {
1987
+ b.get(src).get(end).op(Op.i32GeU).brIf(done);
1988
+ if (simd()) {
1989
+ b.get(src).i32(16).op(Op.i32Add).get(end).op(Op.i32LeU);
1990
+ b.if(() => {
1991
+ b.get(src).simd(Simd.v128Load, 0, 0).simd(Simd.i8x16Bitmask).op(Op.i32Eqz);
1992
+ b.if(() => {
1993
+ b.get(k).i32(1).op(Op.i32Shl);
1994
+ b.get(src).simd(Simd.v128Load, 0, 0).simd(Simd.i16x8ExtendLowI8x16U).simd(Simd.v128Store, 0, Input$1);
1995
+ b.get(k).i32(1).op(Op.i32Shl);
1996
+ b.get(src).simd(Simd.v128Load, 0, 0).simd(Simd.i16x8ExtendHighI8x16U).simd(Simd.v128Store, 0, 131088);
1997
+ step(16, 16, again);
1998
+ });
1999
+ });
2000
+ }
2001
+ b.get(src).i32(8).op(Op.i32Add).get(end).op(Op.i32LeU);
2002
+ b.if(() => {
2003
+ b.get(src).mem(Op.i64Load, 0, 0).tee(x).i64(-9187201950435737472n).op(Op.i64And).op(Op.i64Eqz);
2004
+ b.if(() => {
2005
+ const word = b.localI64();
2006
+ b.get(x).set(word);
2007
+ b.get(k).i32(1).op(Op.i32Shl);
2008
+ spread(0);
2009
+ b.mem(Op.i64Store, 0, Input$1);
2010
+ b.get(word).set(x);
2011
+ b.get(k).i32(1).op(Op.i32Shl);
2012
+ spread(32);
2013
+ b.mem(Op.i64Store, 0, 131080);
2014
+ step(8, 8, again);
2015
+ });
2016
+ });
2017
+ byte(0);
2018
+ b.tee(c).i32(128).op(Op.i32LtU);
2019
+ b.if(() => {
2020
+ unit(0, () => b.get(c));
2021
+ step(1, 1, again);
2022
+ });
2023
+ b.get(c).i32(224).op(Op.i32LtU);
2024
+ b.if(() => {
2025
+ unit(0, () => {
2026
+ b.get(c).i32(31).op(Op.i32And).i32(6).op(Op.i32Shl);
2027
+ cont(1, 0);
2028
+ });
2029
+ step(2, 1, again);
2030
+ });
2031
+ b.get(c).i32(240).op(Op.i32LtU);
2032
+ b.if(() => {
2033
+ b.get(c).i32(15).op(Op.i32And).i32(12).op(Op.i32Shl);
2034
+ cont(1, 6);
2035
+ cont(2, 0);
2036
+ b.tee(cp).i32(65533).op(Op.i32Eq);
2037
+ b.if(() => {
2038
+ b.get(count).i32(2).op(Op.i32Shl).get(list).op(Op.i32Add).get(k).mem(Op.i32Store, 2, 0);
2039
+ b.get(count).i32(1).op(Op.i32Add).set(count);
2040
+ });
2041
+ unit(0, () => b.get(cp));
2042
+ step(3, 1, again);
2043
+ });
2044
+ b.get(c).i32(7).op(Op.i32And).i32(18).op(Op.i32Shl);
2045
+ cont(1, 12);
2046
+ cont(2, 6);
2047
+ cont(3, 0);
2048
+ b.i32(65536).op(Op.i32Sub).set(cp);
2049
+ unit(0, () => b.get(cp).i32(10).op(Op.i32ShrU).i32(55296).op(Op.i32Or));
2050
+ unit(1, () => b.get(cp).i32(1023).op(Op.i32And).i32(56320).op(Op.i32Or));
2051
+ step(4, 2, again);
2052
+ }));
2053
+ b.get(count);
2054
+ return index;
2055
+ }
2056
+ /** The decoder of a built-in encoding: `(p) -> code point | -1 | -2`, the width in `G.w`. */
2057
+ decoder(enc) {
2058
+ const known = this.decoders.get(enc);
2059
+ if (known !== void 0) return known;
2060
+ const [index, b] = this.reserve(Ty.rule);
2061
+ this.decoders.set(enc, index);
2062
+ const c = b.local();
2063
+ const d = b.local();
2064
+ const ret = (code, width) => {
2065
+ b.i32(width).gset(G.w);
2066
+ code();
2067
+ b.op(Op.return);
2068
+ };
2069
+ const fail = (code) => b.i32(code).op(Op.return);
2070
+ const at = (k) => this.load(b, 0, k);
2071
+ const inRange = (k) => this.end(b.get(0).i32(k).op(Op.i32Add)).op(Op.i32GeU);
2072
+ if (enc === string) {
2073
+ at(0);
2074
+ b.tee(c).i32(63488).op(Op.i32And).i32(55296).op(Op.i32Ne);
2075
+ b.if(() => ret(() => b.get(c), 1));
2076
+ b.get(c).i32(56319).op(Op.i32LeU);
2077
+ b.if(() => {
2078
+ inRange(1);
2079
+ b.if(() => fail(-2));
2080
+ at(1);
2081
+ b.tee(d).i32(64512).op(Op.i32And).i32(56320).op(Op.i32Eq);
2082
+ b.if(() => ret(() => pair(b, c, d), 2));
2083
+ });
2084
+ fail(-1);
2085
+ } else if (enc === utf16le || enc === utf16be) {
2086
+ const [lo, hi] = enc === utf16le ? [0, 1] : [1, 0];
2087
+ const unitAt = (k) => {
2088
+ at(k + lo);
2089
+ at(k + hi);
2090
+ b.i32(8).op(Op.i32Shl, Op.i32Or);
2091
+ };
2092
+ inRange(1);
2093
+ b.if(() => fail(-2));
2094
+ unitAt(0);
2095
+ b.tee(c).i32(63488).op(Op.i32And).i32(55296).op(Op.i32Ne);
2096
+ b.if(() => ret(() => b.get(c), 2));
2097
+ b.get(c).i32(56319).op(Op.i32GtU);
2098
+ b.if(() => fail(-1));
2099
+ inRange(3);
2100
+ b.if(() => fail(-2));
2101
+ unitAt(2);
2102
+ b.tee(d).i32(64512).op(Op.i32And).i32(56320).op(Op.i32Eq);
2103
+ b.if(() => ret(() => pair(b, c, d), 4));
2104
+ fail(-1);
2105
+ } else {
2106
+ const e = b.local();
2107
+ const f = b.local();
2108
+ const cont = (l) => b.get(l).i32(192).op(Op.i32And).i32(128).op(Op.i32Ne);
2109
+ /** Fails unless the second byte, in `d`, may follow the lead byte: `a` and `b` are the leads with a range of their own. */
2110
+ const second = (a, z) => {
2111
+ b.get(c).i32(a[0]).op(Op.i32Eq);
2112
+ b.ifI32(() => b.get(d).i32(a[1]).op(Op.i32Sub).i32(a[2]).op(Op.i32GtU), () => {
2113
+ b.get(c).i32(z[0]).op(Op.i32Eq);
2114
+ b.ifI32(() => b.get(d).i32(z[1]).op(Op.i32Sub).i32(z[2]).op(Op.i32GtU), () => cont(d));
2115
+ });
2116
+ b.if(() => fail(-1));
2117
+ };
2118
+ /** Reads the continuation byte `k` into local `l`, failing if it is missing or malformed. */
2119
+ const next = (k, l) => {
2120
+ inRange(k);
2121
+ b.if(() => fail(-2));
2122
+ at(k);
2123
+ b.set(l);
2124
+ cont(l);
2125
+ b.if(() => fail(-1));
2126
+ };
2127
+ at(0);
2128
+ b.tee(c).i32(128).op(Op.i32LtU);
2129
+ b.if(() => ret(() => b.get(c), 1));
2130
+ b.get(c).i32(194).op(Op.i32LtU);
2131
+ b.if(() => fail(-1));
2132
+ inRange(1);
2133
+ b.if(() => fail(-2));
2134
+ at(1);
2135
+ b.set(d);
2136
+ b.get(c).i32(224).op(Op.i32LtU);
2137
+ b.if(() => {
2138
+ cont(d);
2139
+ b.if(() => fail(-1));
2140
+ ret(() => {
2141
+ b.get(c).i32(31).op(Op.i32And).i32(6).op(Op.i32Shl);
2142
+ b.get(d).i32(63).op(Op.i32And).op(Op.i32Or);
2143
+ }, 2);
2144
+ });
2145
+ b.get(c).i32(240).op(Op.i32LtU);
2146
+ b.if(() => {
2147
+ second([
2148
+ 224,
2149
+ 160,
2150
+ 31
2151
+ ], [
2152
+ 237,
2153
+ 128,
2154
+ 31
2155
+ ]);
2156
+ next(2, e);
2157
+ ret(() => {
2158
+ b.get(c).i32(15).op(Op.i32And).i32(12).op(Op.i32Shl);
2159
+ b.get(d).i32(63).op(Op.i32And).i32(6).op(Op.i32Shl).op(Op.i32Or);
2160
+ b.get(e).i32(63).op(Op.i32And).op(Op.i32Or);
2161
+ }, 3);
2162
+ });
2163
+ b.get(c).i32(245).op(Op.i32LtU);
2164
+ b.if(() => {
2165
+ second([
2166
+ 240,
2167
+ 144,
2168
+ 47
2169
+ ], [
2170
+ 244,
2171
+ 128,
2172
+ 15
2173
+ ]);
2174
+ next(2, e);
2175
+ next(3, f);
2176
+ ret(() => {
2177
+ b.get(c).i32(7).op(Op.i32And).i32(18).op(Op.i32Shl);
2178
+ b.get(d).i32(63).op(Op.i32And).i32(12).op(Op.i32Shl).op(Op.i32Or);
2179
+ b.get(e).i32(63).op(Op.i32And).i32(6).op(Op.i32Shl).op(Op.i32Or);
2180
+ b.get(f).i32(63).op(Op.i32And).op(Op.i32Or);
2181
+ }, 4);
2182
+ });
2183
+ fail(-1);
2184
+ }
2185
+ return index;
2186
+ }
2187
+ /**
2188
+ * `scanFloatString` / `scanFloatBytes` at `p`: returns where the number
2189
+ * ends, with its value in `G.f`; -1 when the text doesn't start like a
2190
+ * decimal number; -2 when the float parser fails there. Numbers with more
2191
+ * than 15 significant digits or an exponent beyond ±22 are converted by
2192
+ * the JavaScript scan, so the value is always `Number`'s.
2193
+ */
2194
+ scanFloat(enc) {
2195
+ const known = enc === void 0 ? this.tokenFloatScanner : this.floatScanners.get(enc) ?? -1;
2196
+ if (known >= 0) return known;
2197
+ const [index, b] = this.reserve(Ty.rule);
2198
+ if (enc === void 0) this.tokenFloatScanner = index;
2199
+ else this.floatScanners.set(enc, index);
2200
+ const r = enc === void 0 ? void 0 : this.reader(enc);
2201
+ const width = r?.width ?? 1;
2202
+ const unit = (k) => r === void 0 ? this.load(b, k) : r.unit(b, k);
2203
+ const i = 0;
2204
+ const c = b.local();
2205
+ const digits = b.local();
2206
+ const e10 = b.local();
2207
+ const e = b.local();
2208
+ const j = b.local();
2209
+ const neg = b.local();
2210
+ const start = b.local();
2211
+ const high = b.localF64();
2212
+ const low = b.localF64();
2213
+ const v = b.localF64();
2214
+ const isDigit = () => b.get(c).i32(48).op(Op.i32Sub).i32(9).op(Op.i32LeU);
2215
+ /** `c = unit(k)`, or -1 if there is no whole unit at `k` */
2216
+ const read = (k) => {
2217
+ if (r === void 0) this.end(b.get(k)).op(Op.i32LtU);
2218
+ else r.guard(b, k);
2219
+ b.ifI32(() => unit(k), () => b.i32(-1));
2220
+ b.set(c);
2221
+ };
2222
+ const adv = (l) => b.get(l).i32(width).op(Op.i32Add).set(l);
2223
+ const inc = (l) => b.get(l).i32(1).op(Op.i32Add).set(l);
2224
+ const digit = (frac) => {
2225
+ b.get(digits).i32(15).op(Op.i32LtU);
2226
+ b.if(() => {
2227
+ b.get(c).i32(48).op(Op.i32Ne).get(high).f64(0).op(Op.f64Ne).op(Op.i32Or);
2228
+ b.if(() => {
2229
+ b.get(high).f64(10).op(Op.f64Mul).get(c).i32(48).op(Op.i32Sub).op(Op.f64ConvertI32U).op(Op.f64Add);
2230
+ b.set(high);
2231
+ inc(digits);
2232
+ });
2233
+ if (frac) b.get(e10).i32(1).op(Op.i32Sub).set(e10);
2234
+ }, () => {
2235
+ const addLow = () => b.get(low).f64(10).op(Op.f64Mul).get(c).i32(48).op(Op.i32Sub).op(Op.f64ConvertI32U).op(Op.f64Add).set(low);
2236
+ b.get(digits).i32(19).op(Op.i32LtU);
2237
+ if (frac) b.if(() => {
2238
+ addLow();
2239
+ b.get(e10).i32(1).op(Op.i32Sub).set(e10);
2240
+ });
2241
+ else b.if(addLow, () => inc(e10));
2242
+ inc(digits);
2243
+ });
2244
+ };
2245
+ b.get(i).set(start);
2246
+ read(i);
2247
+ b.get(c).i32(45).op(Op.i32Eq).get(c).i32(43).op(Op.i32Eq).op(Op.i32Or);
2248
+ b.if(() => {
2249
+ b.get(i).i32(width).op(Op.i32Add).set(j);
2250
+ read(j);
2251
+ isDigit();
2252
+ b.get(c).i32(46).op(Op.i32Eq).op(Op.i32Or).op(Op.i32Eqz);
2253
+ b.if(() => b.i32(-1).op(Op.return));
2254
+ adv(i);
2255
+ }, () => {
2256
+ isDigit();
2257
+ b.get(c).i32(46).op(Op.i32Eq).op(Op.i32Or).op(Op.i32Eqz);
2258
+ b.if(() => b.i32(-1).op(Op.return));
2259
+ });
2260
+ b.get(c).i32(46).op(Op.i32Ne);
2261
+ b.if(() => {
2262
+ b.loop((more) => {
2263
+ digit(false);
2264
+ adv(i);
2265
+ read(i);
2266
+ isDigit();
2267
+ b.brIf(more);
2268
+ });
2269
+ b.get(c).i32(46).op(Op.i32Eq);
2270
+ b.if(() => {
2271
+ adv(i);
2272
+ read(i);
2273
+ });
2274
+ }, () => {
2275
+ adv(i);
2276
+ read(i);
2277
+ isDigit();
2278
+ b.op(Op.i32Eqz);
2279
+ b.if(() => b.i32(-2).op(Op.return));
2280
+ });
2281
+ b.block((done) => b.loop((more) => {
2282
+ isDigit();
2283
+ b.op(Op.i32Eqz).brIf(done);
2284
+ digit(true);
2285
+ adv(i);
2286
+ read(i);
2287
+ b.br(more);
2288
+ }));
2289
+ b.get(c).i32(32).op(Op.i32Or).i32(101).op(Op.i32Eq);
2290
+ b.if(() => {
2291
+ b.get(i).i32(width).op(Op.i32Add).set(j);
2292
+ read(j);
2293
+ b.get(c).i32(45).op(Op.i32Eq).set(neg);
2294
+ b.get(neg).get(c).i32(43).op(Op.i32Eq).op(Op.i32Or);
2295
+ b.if(() => {
2296
+ adv(j);
2297
+ read(j);
2298
+ });
2299
+ isDigit();
2300
+ b.if(() => {
2301
+ b.i32(0).set(e);
2302
+ b.loop((more) => {
2303
+ b.get(e).i32(1e6).op(Op.i32LtS);
2304
+ b.if(() => b.get(e).i32(10).op(Op.i32Mul).get(c).i32(48).op(Op.i32Sub).op(Op.i32Add).set(e));
2305
+ adv(j);
2306
+ read(j);
2307
+ isDigit();
2308
+ b.brIf(more);
2309
+ });
2310
+ b.get(e10).i32(0).get(e).op(Op.i32Sub).get(e).get(neg).op(Op.select).op(Op.i32Add).set(e10);
2311
+ b.get(j).set(i);
2312
+ });
2313
+ });
2314
+ unit(start);
2315
+ b.i32(45).op(Op.i32Eq).set(neg);
2316
+ b.get(high).f64(0).op(Op.f64Eq);
2317
+ b.if(() => {
2318
+ b.f64(-0).f64(0).get(neg).op(Op.select).gset(G.f);
2319
+ b.get(i).op(Op.return);
2320
+ });
2321
+ /** `exact[k]`, for `k` in local `l` (or `-l` when `negate`). */
2322
+ const pow = (l, negate = false) => {
2323
+ if (negate) b.i32(0).get(l).op(Op.i32Sub);
2324
+ else b.get(l);
2325
+ b.i32(3).op(Op.i32Shl).mem(Op.f64Load, 3, Pow10);
2326
+ };
2327
+ const [ph, pl, t, ah, al, bh, bl, wh, wl, xh, xl, pp, err] = Array.from({ length: 13 }, () => b.localF64());
2328
+ const lowDigits = b.local();
2329
+ /** `twoProduct(a, b)`: `ph + pl` is exactly `a * b`. */
2330
+ const twoProduct = (x, y) => {
2331
+ x();
2332
+ y();
2333
+ b.op(Op.f64Mul).set(ph);
2334
+ b.f64(134217729);
2335
+ x();
2336
+ b.op(Op.f64Mul).set(t);
2337
+ b.get(t).get(t);
2338
+ x();
2339
+ b.op(Op.f64Sub).op(Op.f64Sub).set(ah);
2340
+ x();
2341
+ b.get(ah).op(Op.f64Sub).set(al);
2342
+ b.f64(134217729);
2343
+ y();
2344
+ b.op(Op.f64Mul).set(t);
2345
+ b.get(t).get(t);
2346
+ y();
2347
+ b.op(Op.f64Sub).op(Op.f64Sub).set(bh);
2348
+ y();
2349
+ b.get(bh).op(Op.f64Sub).set(bl);
2350
+ b.get(ah).get(bh).op(Op.f64Mul).get(ph).op(Op.f64Sub);
2351
+ b.get(ah).get(bl).op(Op.f64Mul).op(Op.f64Add);
2352
+ b.get(al).get(bh).op(Op.f64Mul).op(Op.f64Add);
2353
+ b.get(al).get(bl).op(Op.f64Mul).op(Op.f64Add).set(pl);
2354
+ };
2355
+ b.block((slow) => {
2356
+ b.get(digits).i32(19).op(Op.i32GtU).brIf(slow);
2357
+ b.get(e10).i32(22).op(Op.i32Add).i32(44).op(Op.i32GtU).brIf(slow);
2358
+ b.get(digits).i32(15).op(Op.i32LeU);
2359
+ b.if(() => {
2360
+ b.get(e10).i32(0).op(Op.i32Eq);
2361
+ b.if(() => b.get(high).set(v), () => {
2362
+ b.get(e10).i32(0).op(Op.i32GtS);
2363
+ b.if(() => {
2364
+ b.get(high);
2365
+ pow(e10);
2366
+ b.op(Op.f64Mul).set(v);
2367
+ }, () => {
2368
+ b.get(high);
2369
+ pow(e10, true);
2370
+ b.op(Op.f64Div).set(v);
2371
+ });
2372
+ });
2373
+ }, () => {
2374
+ b.get(digits).i32(15).op(Op.i32Sub).set(lowDigits);
2375
+ twoProduct(() => b.get(high), () => pow(lowDigits));
2376
+ b.get(ph).get(low).op(Op.f64Add).set(wh);
2377
+ b.get(pl).get(low).get(wh).get(ph).op(Op.f64Sub).op(Op.f64Sub).op(Op.f64Add).set(wl);
2378
+ b.get(e10).i32(0).op(Op.i32GeS);
2379
+ b.if(() => {
2380
+ pow(e10);
2381
+ b.set(pp);
2382
+ twoProduct(() => b.get(wh), () => b.get(pp));
2383
+ b.get(ph).set(xh);
2384
+ b.get(pl).get(wl).get(pp).op(Op.f64Mul).op(Op.f64Add).set(xl);
2385
+ }, () => {
2386
+ pow(e10, true);
2387
+ b.set(pp);
2388
+ b.get(wh).get(pp).op(Op.f64Div).set(xh);
2389
+ twoProduct(() => b.get(xh), () => b.get(pp));
2390
+ b.get(wh).get(ph).op(Op.f64Sub).get(pl).op(Op.f64Sub).get(wl).op(Op.f64Add).get(pp).op(Op.f64Div).set(xl);
2391
+ });
2392
+ b.get(xh).get(xl).op(Op.f64Add).set(v);
2393
+ b.get(xh).op(Op.f64Abs).f64(1 / 2 ** 96).op(Op.f64Mul).set(err);
2394
+ b.get(xh).get(xl).get(err).op(Op.f64Add).op(Op.f64Add).get(v).op(Op.f64Ne).brIf(slow);
2395
+ b.get(xh).get(xl).get(err).op(Op.f64Sub).op(Op.f64Add).get(v).op(Op.f64Ne).brIf(slow);
2396
+ });
2397
+ b.get(v).op(Op.f64Neg).get(v).get(neg).op(Op.select).gset(G.f);
2398
+ b.get(i).op(Op.return);
2399
+ });
2400
+ b.get(start).get(i).call(Imp.float).gset(G.f);
2401
+ b.get(i);
2402
+ return index;
2403
+ }
2404
+ };
2405
+ const unitsOf = (s) => Array.from({ length: s.length }, (_, i) => s.charCodeAt(i));
2406
+ const utf8Encoder = /*#__PURE__*/ new TextEncoder();
2407
+ /** The powers of ten that doubles represent exactly, as stored at `Pow10`. */
2408
+ const powersOfTen = /*#__PURE__*/ new Uint8Array((/*#__PURE__*/ new Float64Array(/*#__PURE__*/ Array.from({ length: 23 }, (_, k) => 10 ** k))).buffer);
2409
+ /** Runtime helpers of the builder (`R`). */
2410
+ const fromCharCode = String.fromCharCode;
2411
+ /**
2412
+ * The text of ASCII bytes. Short ones are built from their codes, about a
2413
+ * third faster than `utf8.text`, which tests every byte for a longer
2414
+ * sequence; long ones are decoded by `TextDecoder`.
2415
+ */
2416
+ const ascii = (b, start, end) => {
2417
+ const n = end - start;
2418
+ if (n > 24) return utf8.text(b, start, end);
2419
+ if (n <= 4) {
2420
+ if (n === 0) return "";
2421
+ if (n === 1) return charOf(b[start]);
2422
+ if (n === 2) return fromCharCode(b[start], b[start + 1]);
2423
+ if (n === 3) return fromCharCode(b[start], b[start + 1], b[start + 2]);
2424
+ return fromCharCode(b[start], b[start + 1], b[start + 2], b[start + 3]);
2425
+ }
2426
+ let s = fromCharCode(b[start], b[start + 1], b[start + 2], b[start + 3]);
2427
+ for (let i = start + 4; i < end; i++) s += charOf(b[i]);
2428
+ return s;
2429
+ };
2430
+ const runtime = {
2431
+ some: Option.some,
2432
+ none: Option.none,
2433
+ charOf,
2434
+ isPlainKey,
2435
+ addEntry,
2436
+ flushEntries,
2437
+ ascii
2438
+ };
2439
+ /** The state outside a parse: islands only run during one. */
2440
+ const idle = /*#__PURE__*/ new State("");
2441
+ const compileWasm = (root, kind) => {
2442
+ const c = new WasmCompiler(kind);
2443
+ c.countRefs(root);
2444
+ const rootIndex = c.rule(root, true);
2445
+ c.flush();
2446
+ const widen = kind === 0 ? c.widener() : -1;
2447
+ const start = c.starter(rootIndex);
2448
+ if (c.functions.some(([, body]) => body.invalid)) return Result.fail("a branch to a label out of scope");
2449
+ const globals = [
2450
+ {
2451
+ type: I32,
2452
+ init: 0
2453
+ },
2454
+ {
2455
+ type: I32,
2456
+ init: 0
2457
+ },
2458
+ {
2459
+ type: I32,
2460
+ init: 0
2461
+ },
2462
+ {
2463
+ type: I32,
2464
+ init: 0
2465
+ },
2466
+ {
2467
+ type: I32,
2468
+ init: 0
2469
+ },
2470
+ {
2471
+ type: I32,
2472
+ init: 0
2473
+ },
2474
+ {
2475
+ type: I32,
2476
+ init: 0
2477
+ },
2478
+ {
2479
+ type: F64,
2480
+ init: 0
2481
+ }
2482
+ ];
2483
+ const tables = new Uint8Array(c.tables.length * TableSize);
2484
+ c.tables.forEach((t, i) => tables.set(t, i * TableSize));
2485
+ const bytes = encodeModule({
2486
+ types: [
2487
+ {
2488
+ params: [I32],
2489
+ results: [I32]
2490
+ },
2491
+ {
2492
+ params: [I32, I32],
2493
+ results: [I32]
2494
+ },
2495
+ {
2496
+ params: [],
2497
+ results: [I32]
2498
+ },
2499
+ {
2500
+ params: [I32, I32],
2501
+ results: [F64]
2502
+ },
2503
+ {
2504
+ params: [
2505
+ I32,
2506
+ I32,
2507
+ I32,
2508
+ I32,
2509
+ I32
2510
+ ],
2511
+ results: [I32]
2512
+ }
2513
+ ],
2514
+ imports: [
2515
+ [
2516
+ "env",
2517
+ "island",
2518
+ Ty.pair
2519
+ ],
2520
+ [
2521
+ "env",
2522
+ "grow",
2523
+ Ty.grow
2524
+ ],
2525
+ [
2526
+ "env",
2527
+ "test",
2528
+ Ty.pair
2529
+ ],
2530
+ [
2531
+ "env",
2532
+ "float",
2533
+ Ty.toF64
2534
+ ],
2535
+ [
2536
+ "env",
2537
+ "check",
2538
+ Ty.pair
2539
+ ]
2540
+ ],
2541
+ memoryPages: 2,
2542
+ functions: c.functions,
2543
+ globals,
2544
+ exports: [
2545
+ [
2546
+ "root",
2547
+ 0,
2548
+ rootIndex
2549
+ ],
2550
+ ...widen < 0 ? [] : [[
2551
+ "widen",
2552
+ 0,
2553
+ widen
2554
+ ]],
2555
+ [
2556
+ "start",
2557
+ 0,
2558
+ start
2559
+ ],
2560
+ [
2561
+ "mode",
2562
+ 3,
2563
+ G.mode
2564
+ ],
2565
+ [
2566
+ "end",
2567
+ 3,
2568
+ G.end
2569
+ ],
2570
+ [
2571
+ "len",
2572
+ 3,
2573
+ G.len
2574
+ ],
2575
+ [
2576
+ "tp",
2577
+ 3,
2578
+ G.tp
2579
+ ],
2580
+ [
2581
+ "tlim",
2582
+ 3,
2583
+ G.tlim
2584
+ ],
2585
+ [
2586
+ "nv",
2587
+ 3,
2588
+ G.nv
2589
+ ]
2590
+ ],
2591
+ data: [[0, tables], [Pow10, powersOfTen]]
2592
+ });
2593
+ const source = `"use strict";let T,F,I,E,V,S,N=0;${c.builders.join("")}${c.valueFns.join("")}const W=[${c.valueFns.map((_, k) => `w${k}`).join(",")}];return{bind(t,f,inp,e,vals,s){T=t;F=f;I=inp;E=e;V=vals;S=s},unbind(){T=F=I=V=S=void 0},root(i){return b${rootIndex}(i)},value(w,i){return W[w](i)}}`;
2594
+ const build = new globalThis.Function("C", "R", source)(c.constants, runtime);
2595
+ return run(root, c, bytes, kind, build, source);
2596
+ };
2597
+ /** A global of a module's exports. */
2598
+ const exportedGlobal = (exports, name) => {
2599
+ const g = exports[name];
2600
+ return g instanceof WebAssembly.Global ? Result.succeed(g) : Result.fail(`no global ${name}`);
2601
+ };
2602
+ const run = (root, c, bytes, kind, build, source) => {
2603
+ const memory = new WebAssembly.Memory({ initial: 2 });
2604
+ let size = memory.buffer.byteLength;
2605
+ let i32 = new Int32Array(memory.buffer);
2606
+ let f64 = new Float64Array(memory.buffer);
2607
+ let u8 = new Uint8Array(memory.buffer);
2608
+ const views = () => {
2609
+ i32 = new Int32Array(memory.buffer);
2610
+ f64 = new Float64Array(memory.buffer);
2611
+ u8 = new Uint8Array(memory.buffer);
2612
+ };
2613
+ /** Grows the memory to at least `bytes`, doubling it. */
2614
+ const reserve = (bytes) => {
2615
+ const have = size;
2616
+ if (have >= bytes) return;
2617
+ memory.grow(Math.ceil((Math.max(bytes, have * 2) - have) / PageSize));
2618
+ size = memory.buffer.byteLength;
2619
+ views();
2620
+ };
2621
+ const steps = c.islands.map(({ parser }) => backend$1.build(parser, kind, false).step ?? parser.step);
2622
+ const used = c.islands.map(({ used }) => used);
2623
+ const tests = c.tests;
2624
+ const checks = c.checks;
2625
+ let state = idle;
2626
+ const values = [];
2627
+ const imports = { env: {
2628
+ mem: memory,
2629
+ island: (id, pos) => {
2630
+ const s = state;
2631
+ s.pos = pos;
2632
+ const a = steps[id](s);
2633
+ if (a === Fail) return s.mode === "Cut" ? -2 : -1;
2634
+ if (used[id]) values.push(a);
2635
+ return s.pos;
2636
+ },
2637
+ grow: () => {
2638
+ reserve(size * 2);
2639
+ build.bind(i32, f64, state.input, state.end, values, state);
2640
+ return size - Slack;
2641
+ },
2642
+ test: (id, cp) => tests[id](cp),
2643
+ check: (id, from) => {
2644
+ const s = state;
2645
+ const a = checks[id](build.value(id, from >> 2));
2646
+ if (a === Fail) {
2647
+ s.mode = "Backtrack";
2648
+ return 0;
2649
+ }
2650
+ values.push(a);
2651
+ return 1;
2652
+ },
2653
+ float: (start, end) => {
2654
+ const input = state.input;
2655
+ return toFloat(Predicate.isString(input) ? input.slice(start, end) : latin1.text(input, start, end).replace(/\0/g, ""));
2656
+ }
2657
+ } };
2658
+ const exported = new WebAssembly.Instance(new WebAssembly.Module(bytes), imports).exports;
2659
+ const rootFn = exported.root;
2660
+ if (!Predicate.isFunction(rootFn)) return Result.fail("no root function");
2661
+ const widenFn = kind === 0 ? exported.widen : rootFn;
2662
+ if (!Predicate.isFunction(widenFn)) return Result.fail("no widen function");
2663
+ const startFn = exported.start;
2664
+ if (!Predicate.isFunction(startFn)) return Result.fail("no start function");
2665
+ const globals = Result.all(["mode"].map((name) => exportedGlobal(exported, name)));
2666
+ if (Result.isFailure(globals)) return Result.fail(globals.failure);
2667
+ const [mode] = globals.success;
2668
+ let busy = false;
2669
+ /** The JIT's step for the parser, built on first use. */
2670
+ let fallback = (s) => {
2671
+ fallback = backend$1.build(root, kind, false).step ?? root.step;
2672
+ return fallback(s);
2673
+ };
2674
+ /** Copies the input into memory, scans it and builds the value. */
2675
+ /**
2676
+ * Copies a string's UTF-16 units into memory, at `staging` for its UTF-8
2677
+ * (see `widener`): standard `ArrayBuffer` views and `TextEncoder`, so the
2678
+ * same code runs everywhere, and a memory backed by a `SharedArrayBuffer`
2679
+ * would take it as well.
2680
+ */
2681
+ const copyString = (input, staging) => {
2682
+ const { written } = utf8Encoder.encodeInto(input, u8.subarray(staging, staging + 3 * input.length));
2683
+ const replaced = widenFn(staging, written);
2684
+ if (replaced === 0) return;
2685
+ const view = new DataView(memory.buffer);
2686
+ const list = staging + written + 3 >> 2;
2687
+ for (let r = 0; r < replaced; r++) {
2688
+ const at = i32[list + r];
2689
+ view.setUint16(Input$1 + 2 * at, input.charCodeAt(at), true);
2690
+ }
2691
+ };
2692
+ /** The string whose units are in memory, if any (`""`: none). */
2693
+ let copied = "";
2694
+ const parse = (s) => {
2695
+ const input = s.input;
2696
+ const n = input.length;
2697
+ const inputBytes = kind === 0 ? 2 * n : n;
2698
+ const traceStart = Input$1 + inputBytes + 15 & -16;
2699
+ reserve(traceStart + Math.max(Slack * 4, inputBytes * 4, kind === 0 ? 7 * n + 16 : 0));
2700
+ if (Predicate.isString(input)) {
2701
+ if (input !== copied) {
2702
+ copied = "";
2703
+ copyString(input, traceStart);
2704
+ copied = input;
2705
+ }
2706
+ } else u8.set(s.pos === 0 && s.end === n ? input : input.subarray(s.pos, s.end), Input$1 + s.pos);
2707
+ values.length = 0;
2708
+ state = s;
2709
+ build.bind(i32, f64, input, s.end, values, s);
2710
+ const r = startFn(s.pos, s.end, n, traceStart, size - Slack);
2711
+ if (r < 0) {
2712
+ s.mode = mode.value === Cut ? "Cut" : "Backtrack";
2713
+ return Fail;
2714
+ }
2715
+ s.pos = r;
2716
+ return build.root(traceStart >> 2);
2717
+ };
2718
+ /** The bytes copied by the latest parse: parsing them again from further on is a driver at work. */
2719
+ let lastBytes = /* @__PURE__ */ new Uint8Array(0);
2720
+ /** The state of the parse `parsePending` runs: `Result.try` takes a function without arguments. */
2721
+ let pending = idle;
2722
+ const parsePending = () => parse(pending);
2723
+ const step = (s) => {
2724
+ if (busy) return fallback(s);
2725
+ const input = s.input;
2726
+ if (!Predicate.isString(input)) {
2727
+ const again = input === lastBytes && s.pos > 0 && s.end - s.pos > LargeRest;
2728
+ lastBytes = input;
2729
+ if (again) return fallback(s);
2730
+ }
2731
+ busy = true;
2732
+ pending = s;
2733
+ const result = Result.try(parsePending);
2734
+ build.unbind();
2735
+ state = idle;
2736
+ pending = idle;
2737
+ busy = false;
2738
+ values.length = 0;
2739
+ if (Result.isFailure(result)) throw result.failure;
2740
+ return result.success;
2741
+ };
2742
+ return Result.succeed({
2743
+ backend: "wasm",
2744
+ step,
2745
+ guarded: false,
2746
+ fallbacks: c.fallbacks,
2747
+ error: void 0,
2748
+ source
2749
+ });
2750
+ };
2751
+ /**
2752
+ * The WebAssembly compiler as a backend. Streaming builds, array input and
2753
+ * environments without `WebAssembly` or `new Function` use the JIT, as does
2754
+ * a parser whose module fails to build.
2755
+ */
2756
+ const backend = { build: (p, kind, resumable) => {
2757
+ if (resumable || kind === 2 || !supported()) return backend$1.build(p, kind, resumable);
2758
+ const built = Result.flatMap(Result.try(() => compileWasm(p, kind)), (r) => r);
2759
+ return Result.match(built, {
2760
+ onSuccess: (compiled) => compiled,
2761
+ onFailure: (error) => ({
2762
+ ...backend$1.build(p, kind, resumable),
2763
+ wasmError: error
2764
+ })
2765
+ });
2766
+ } };
2767
+ export { backend };
2768
+
2769
+ //# sourceMappingURL=wasm.js.map