@thomasfosterau/effect-parse 0.0.0-stage → 0.1.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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +550 -2
  3. package/dist/Ascii.d.ts +392 -0
  4. package/dist/Ascii.d.ts.map +1 -0
  5. package/dist/Ascii.js +610 -0
  6. package/dist/Ascii.js.map +1 -0
  7. package/dist/Binary.d.ts +153 -0
  8. package/dist/Binary.d.ts.map +1 -0
  9. package/dist/Binary.js +171 -0
  10. package/dist/Binary.js.map +1 -0
  11. package/dist/Bits.d.ts +60 -0
  12. package/dist/Bits.d.ts.map +1 -0
  13. package/dist/Bits.js +144 -0
  14. package/dist/Bits.js.map +1 -0
  15. package/dist/Encoding.d.ts +116 -0
  16. package/dist/Encoding.d.ts.map +1 -0
  17. package/dist/Encoding.js +85 -0
  18. package/dist/Encoding.js.map +1 -0
  19. package/dist/Expression.d.ts +124 -0
  20. package/dist/Expression.d.ts.map +1 -0
  21. package/dist/Expression.js +139 -0
  22. package/dist/Expression.js.map +1 -0
  23. package/dist/Input.d.ts +301 -0
  24. package/dist/Input.d.ts.map +1 -0
  25. package/dist/Input.js +312 -0
  26. package/dist/Input.js.map +1 -0
  27. package/dist/Nom.d.ts +518 -0
  28. package/dist/Nom.d.ts.map +1 -0
  29. package/dist/Nom.js +519 -0
  30. package/dist/Nom.js.map +1 -0
  31. package/dist/ParseError.d.ts +120 -0
  32. package/dist/ParseError.d.ts.map +1 -0
  33. package/dist/ParseError.js +301 -0
  34. package/dist/ParseError.js.map +1 -0
  35. package/dist/Parser.d.ts +1312 -0
  36. package/dist/Parser.d.ts.map +1 -0
  37. package/dist/Parser.js +1936 -0
  38. package/dist/Parser.js.map +1 -0
  39. package/dist/ParserSchema.d.ts +31 -0
  40. package/dist/ParserSchema.d.ts.map +1 -0
  41. package/dist/ParserSchema.js +56 -0
  42. package/dist/ParserSchema.js.map +1 -0
  43. package/dist/ParserStream.d.ts +127 -0
  44. package/dist/ParserStream.d.ts.map +1 -0
  45. package/dist/ParserStream.js +270 -0
  46. package/dist/ParserStream.js.map +1 -0
  47. package/dist/Text.d.ts +330 -0
  48. package/dist/Text.d.ts.map +1 -0
  49. package/dist/Text.js +529 -0
  50. package/dist/Text.js.map +1 -0
  51. package/dist/Token.d.ts +225 -0
  52. package/dist/Token.d.ts.map +1 -0
  53. package/dist/Token.js +294 -0
  54. package/dist/Token.js.map +1 -0
  55. package/dist/index.d.ts +17 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +17 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/internal/compiler/closure.d.ts +25 -0
  60. package/dist/internal/compiler/closure.d.ts.map +1 -0
  61. package/dist/internal/compiler/closure.js +1668 -0
  62. package/dist/internal/compiler/closure.js.map +1 -0
  63. package/dist/internal/compiler/entries.d.ts +19 -0
  64. package/dist/internal/compiler/entries.d.ts.map +1 -0
  65. package/dist/internal/compiler/entries.js +32 -0
  66. package/dist/internal/compiler/entries.js.map +1 -0
  67. package/dist/internal/compiler/first.d.ts +33 -0
  68. package/dist/internal/compiler/first.d.ts.map +1 -0
  69. package/dist/internal/compiler/first.js +235 -0
  70. package/dist/internal/compiler/first.js.map +1 -0
  71. package/dist/internal/compiler/jit.d.ts +20 -0
  72. package/dist/internal/compiler/jit.d.ts.map +1 -0
  73. package/dist/internal/compiler/jit.js +1030 -0
  74. package/dist/internal/compiler/jit.js.map +1 -0
  75. package/dist/internal/compiler/registry.d.ts +34 -0
  76. package/dist/internal/compiler/registry.d.ts.map +1 -0
  77. package/dist/internal/compiler/registry.js +46 -0
  78. package/dist/internal/compiler/registry.js.map +1 -0
  79. package/dist/internal/compiler/sets.d.ts +29 -0
  80. package/dist/internal/compiler/sets.d.ts.map +1 -0
  81. package/dist/internal/compiler/sets.js +85 -0
  82. package/dist/internal/compiler/sets.js.map +1 -0
  83. package/dist/internal/entries.d.ts +27 -0
  84. package/dist/internal/entries.d.ts.map +1 -0
  85. package/dist/internal/entries.js +42 -0
  86. package/dist/internal/entries.js.map +1 -0
  87. package/dist/internal/node.d.ts +251 -0
  88. package/dist/internal/node.d.ts.map +1 -0
  89. package/dist/internal/node.js +73 -0
  90. package/dist/internal/node.js.map +1 -0
  91. package/dist/internal/numbers.d.ts +41 -0
  92. package/dist/internal/numbers.d.ts.map +1 -0
  93. package/dist/internal/numbers.js +302 -0
  94. package/dist/internal/numbers.js.map +1 -0
  95. package/dist/internal/resume.d.ts +39 -0
  96. package/dist/internal/resume.d.ts.map +1 -0
  97. package/dist/internal/resume.js +37 -0
  98. package/dist/internal/resume.js.map +1 -0
  99. package/dist/internal/text.d.ts +72 -0
  100. package/dist/internal/text.d.ts.map +1 -0
  101. package/dist/internal/text.js +391 -0
  102. package/dist/internal/text.js.map +1 -0
  103. package/dist/internal/tokens.d.ts +93 -0
  104. package/dist/internal/tokens.d.ts.map +1 -0
  105. package/dist/internal/tokens.js +400 -0
  106. package/dist/internal/tokens.js.map +1 -0
  107. package/package.json +115 -3
  108. package/src/Ascii.ts +741 -0
  109. package/src/Binary.ts +228 -0
  110. package/src/Bits.ts +192 -0
  111. package/src/Encoding.ts +128 -0
  112. package/src/Expression.ts +245 -0
  113. package/src/Input.ts +429 -0
  114. package/src/Nom.ts +642 -0
  115. package/src/ParseError.ts +378 -0
  116. package/src/Parser.ts +2763 -0
  117. package/src/ParserSchema.ts +87 -0
  118. package/src/ParserStream.ts +390 -0
  119. package/src/Text.ts +757 -0
  120. package/src/Token.ts +416 -0
  121. package/src/index.ts +16 -0
  122. package/src/internal/compiler/closure.ts +1583 -0
  123. package/src/internal/compiler/entries.ts +36 -0
  124. package/src/internal/compiler/first.ts +252 -0
  125. package/src/internal/compiler/jit.ts +1091 -0
  126. package/src/internal/compiler/registry.ts +79 -0
  127. package/src/internal/compiler/sets.ts +100 -0
  128. package/src/internal/entries.ts +51 -0
  129. package/src/internal/node.ts +207 -0
  130. package/src/internal/numbers.ts +291 -0
  131. package/src/internal/resume.ts +55 -0
  132. package/src/internal/text.ts +411 -0
  133. package/src/internal/tokens.ts +409 -0
@@ -0,0 +1,1030 @@
1
+ /**
2
+ * The JIT: emits JavaScript source for a parser's description and builds
3
+ * it with `new Function`.
4
+ *
5
+ * Every rule (the root, every `suspend` target and every non-leaf parser
6
+ * with several parents) becomes a function `f(p)` taking the cursor and
7
+ * returning the value, or `Fail`, leaving the new cursor in the register
8
+ * `P`. Everything else is inlined as straight-line code, with labelled
9
+ * blocks for failure. The cursor is a local; the input and its end are
10
+ * hoisted into locals. Failures only set `state.mode`, as in the closure
11
+ * compiler.
12
+ *
13
+ * Nodes without an inline form run their closure-compiled steps (which run
14
+ * the interpreter for what they can't compile) on the shared state, with
15
+ * `state.pos` kept in sync.
16
+ */
17
+ import * as Option from "effect/Option";
18
+ import { Fail } from "../../Input.js";
19
+ import { addEntry, flushEntries, fromEntries, isPlainKey } from "../entries.js";
20
+ import { children, nodeOf } from "../node.js";
21
+ import { floatScan, floatTexts, scanFloatBytes, scanFloatString, toFloat } from "../numbers.js";
22
+ import * as Resume from "../resume.js";
23
+ import { charOf, fastLimit, latin1, string, utf16be, utf16le, utf8, validate } from "../text.js";
24
+ import { createClosureCompiler } from "./closure.js";
25
+ import { entriesShape, pairOf } from "./entries.js";
26
+ import { planAlt, Strict } from "./first.js";
27
+ import { kindOfEncoding, reachesAbove, TableSize, textSet, tokenSet } from "./sets.js";
28
+ /** Helpers available to generated code as `R`. */
29
+ const runtime = {
30
+ take: Resume.take,
31
+ save: Resume.save,
32
+ Done: Resume.Done,
33
+ /** Records the result of a resumed repetition (see `Resume.done`). */
34
+ done: (state, key, entry, value, pos) => Resume.save(state, key, entry, new Resume.Done(value, pos)),
35
+ some: Option.some,
36
+ none: Option.none,
37
+ charOf,
38
+ scanFloatString,
39
+ scanFloatBytes,
40
+ isPlainKey,
41
+ addEntry,
42
+ flushEntries,
43
+ /** `Text.taken`: the text of `[start, end)`, or `Fail` if it is malformed. */
44
+ textOf: (enc, fast, s, start, end) => {
45
+ const input = s.input;
46
+ let i = start;
47
+ if (s.inputKind === 0)
48
+ while (i < end && input.charCodeAt(i) < fast)
49
+ i++;
50
+ else
51
+ while (i < end && input[i] < fast)
52
+ i++;
53
+ if (i < end && validate(enc, s, i, end) < 0) {
54
+ s.mode = "Backtrack";
55
+ return Fail;
56
+ }
57
+ return enc.text(input, start, end);
58
+ }
59
+ };
60
+ let checked;
61
+ let supported = false;
62
+ /**
63
+ * Whether `new Function` works here (it doesn't under a Content Security
64
+ * Policy). Checked once, and again if `globalThis.Function` is replaced.
65
+ */
66
+ export const jitSupported = () => {
67
+ if (checked !== globalThis.Function) {
68
+ checked = globalThis.Function;
69
+ try {
70
+ supported = checked("return true")() === true;
71
+ }
72
+ catch {
73
+ supported = false;
74
+ }
75
+ }
76
+ return supported;
77
+ };
78
+ const BT = `$S.mode="Backtrack";`;
79
+ const builtinEncodings = new Set([string, utf8, utf16le, utf16be, latin1]);
80
+ /** How many units past the cursor a single token can depend on (see the closure compiler). */
81
+ const Margin = 4;
82
+ /** Per generated function: its local variables. */
83
+ class Fn {
84
+ vars = [];
85
+ }
86
+ const isLeaf = (node) => {
87
+ switch (node._tag) {
88
+ case "Succeed":
89
+ case "Fail":
90
+ case "Eof":
91
+ case "Location":
92
+ case "RestLen":
93
+ case "Any":
94
+ case "Literal":
95
+ case "OneOf":
96
+ case "TakeWhile":
97
+ return true;
98
+ default:
99
+ return false;
100
+ }
101
+ };
102
+ const lowerAscii = (c) => c >= 65 && c <= 90 ? c + 32 : c;
103
+ const isLetter = (c) => (c >= 65 && c <= 90) || (c >= 97 && c <= 122);
104
+ /** The inclusive ranges of 1s in a table. */
105
+ const runsOf = (table) => {
106
+ const out = [];
107
+ for (let i = 0; i < table.length; i++) {
108
+ if (table[i] !== 1)
109
+ continue;
110
+ let j = i;
111
+ while (j + 1 < table.length && table[j + 1] === 1)
112
+ j++;
113
+ out.push([i, j]);
114
+ i = j;
115
+ }
116
+ return out;
117
+ };
118
+ /** A JavaScript expression testing `v` against ranges, or `undefined` if too long. */
119
+ const rangeTest = (runs, v) => {
120
+ if (runs.length === 0)
121
+ return "false";
122
+ if (runs.length > 4)
123
+ return undefined;
124
+ return runs.map(([a, b]) => a === b ? `${v}===${a}` : `(${v}>=${a}&&${v}<=${b})`).join("||");
125
+ };
126
+ /** The inclusive ranges of `[0, size)` where `table[c] === value`. */
127
+ const runsWhere = (table, size, value) => {
128
+ const out = [];
129
+ for (let i = 0; i < size; i++) {
130
+ if (table[i] !== value)
131
+ continue;
132
+ let j = i;
133
+ while (j + 1 < size && table[j + 1] === value)
134
+ j++;
135
+ out.push([i, j]);
136
+ i = j;
137
+ }
138
+ return out;
139
+ };
140
+ /** How many comparisons it takes to test a run of `[0, size)`. */
141
+ const runCost = ([a, b], size) => a === b || a === 0 || b === size - 1 ? 1 : 2;
142
+ /**
143
+ * A JavaScript expression testing whether `v`, known to be in `[0, size)`,
144
+ * is accepted by `table`, or `undefined` if that takes too many comparisons.
145
+ * It tests the accepted runs or the rejected ones, whichever is cheaper:
146
+ * `c!==34&&c!==92&&c>=32` rather than three two-sided ranges.
147
+ */
148
+ const tableTest = (table, v, size) => {
149
+ const accept = runsWhere(table, size, 1);
150
+ const reject = runsWhere(table, size, 0);
151
+ if (accept.length === 0)
152
+ return "false";
153
+ if (reject.length === 0)
154
+ return "true";
155
+ const cost = (runs) => runs.reduce((n, r) => n + runCost(r, size), 0);
156
+ const acceptCost = cost(accept);
157
+ const rejectCost = cost(reject);
158
+ if (Math.min(acceptCost, rejectCost) > 6)
159
+ return undefined;
160
+ const terms = acceptCost <= rejectCost
161
+ ? accept.map(([a, b]) => a === b ? `${v}===${a}` : a === 0 ? `${v}<=${b}` : b === size - 1 ? `${v}>=${a}` : `(${v}>=${a}&&${v}<=${b})`).join("||")
162
+ : reject.map(([a, b]) => a === b ? `${v}!==${a}` : a === 0 ? `${v}>${b}` : b === size - 1 ? `${v}<${a}` : `(${v}<${a}||${v}>${b})`).join("&&");
163
+ return `(${terms})`;
164
+ };
165
+ class Emitter {
166
+ root;
167
+ kind;
168
+ resumable;
169
+ constants = [];
170
+ constantIndex = new Map();
171
+ functions = [];
172
+ rules = [new Map(), new Map()];
173
+ refs = new Map();
174
+ closure;
175
+ next = 0;
176
+ constructor(root, kind, resumable = false) {
177
+ this.root = root;
178
+ this.kind = kind;
179
+ this.resumable = resumable;
180
+ this.closure = createClosureCompiler(kind, resumable);
181
+ this.countRefs(root);
182
+ }
183
+ get fallbacks() {
184
+ return this.closure.fallbacks;
185
+ }
186
+ /** Counts the distinct parents of each parser. */
187
+ countRefs(root) {
188
+ const seen = new Set();
189
+ const stack = [root];
190
+ while (stack.length > 0) {
191
+ const p = stack.pop();
192
+ if (seen.has(p))
193
+ continue;
194
+ seen.add(p);
195
+ for (const c of new Set(children(nodeOf(p)))) {
196
+ this.refs.set(c, (this.refs.get(c) ?? 0) + 1);
197
+ stack.push(c);
198
+ }
199
+ }
200
+ }
201
+ const(value) {
202
+ let i = this.constantIndex.get(value);
203
+ if (i === undefined) {
204
+ i = this.constants.length;
205
+ this.constants.push(value);
206
+ this.constantIndex.set(value, i);
207
+ }
208
+ return `C[${i}]`;
209
+ }
210
+ /** A JavaScript literal for simple values, otherwise a constant. */
211
+ lit(value) {
212
+ if (value === undefined)
213
+ return "void 0";
214
+ if (value === null || typeof value === "boolean")
215
+ return String(value);
216
+ if (typeof value === "number" && Number.isFinite(value) && !Object.is(value, -0))
217
+ return String(value);
218
+ if (typeof value === "string" && value.length < 64)
219
+ return JSON.stringify(value);
220
+ return this.const(value);
221
+ }
222
+ v(fn) {
223
+ const name = `v${this.next++}`;
224
+ fn.vars.push(name);
225
+ return name;
226
+ }
227
+ label() {
228
+ return `L${this.next++}`;
229
+ }
230
+ unit(i) {
231
+ return this.kind === 0 ? `I.charCodeAt(${i})` : `I[${i}]`;
232
+ }
233
+ /**
234
+ * How generated code reads an encoding's code units: units below `fast`
235
+ * are whole code points, `width` input units long. `guard(i)` says that a
236
+ * whole unit is available at `i`.
237
+ */
238
+ reader(enc) {
239
+ if (enc === utf16le || enc === utf16be) {
240
+ const [lo, hi] = enc === utf16le ? ["", "+1"] : ["+1", ""];
241
+ return {
242
+ width: 2,
243
+ fast: 0xd800,
244
+ guard: (i) => `${i}+1<E`,
245
+ unit: (i) => `(I[${i}${lo}]|I[${i}${hi}]<<8)`
246
+ };
247
+ }
248
+ return { width: 1, fast: enc.unit === 1 ? fastLimit(enc) : 0, guard: (i) => `${i}<E`, unit: (i) => this.unit(i) };
249
+ }
250
+ /** The function implementing a rule, generating it on first use. */
251
+ rule(p, used) {
252
+ const rules = this.rules[used ? 1 : 0];
253
+ let name = rules.get(p);
254
+ if (name !== undefined)
255
+ return name;
256
+ name = `f${this.next++}`;
257
+ rules.set(p, name);
258
+ const fn = new Fn();
259
+ const out = used ? this.v(fn) : null;
260
+ const done = this.label();
261
+ const body = this.inline(p, used, out, `break ${done};`, fn, 0);
262
+ this.functions.push(`function ${name}(p){const I=$I,E=$E;${fn.vars.length > 0 ? `let ${fn.vars.join(",")};` : ""}` +
263
+ `${done}:{${body}P=p;return ${out ?? "void 0"}}return F}`);
264
+ return name;
265
+ }
266
+ /**
267
+ * Code for `p`: on success it falls through with `p` advanced and, when
268
+ * `out` is given, the value in `out`; on failure it runs `fail`.
269
+ */
270
+ gen(p, used, out, fail, fn, depth) {
271
+ const node = nodeOf(p);
272
+ if (node._tag === "Suspend")
273
+ return this.call(this.rule(node.resolve(), used), out, fail);
274
+ if (!isLeaf(node) && (((this.refs.get(p) ?? 0) > 1 && !this.small(p)) || depth > 32)) {
275
+ return this.call(this.rule(p, used), out, fail);
276
+ }
277
+ return this.inline(p, used, out, fail, fn, depth);
278
+ }
279
+ /** Whether a parser is small enough to inline wherever it is used. */
280
+ small(p) {
281
+ let budget = 6;
282
+ const visit = (q) => {
283
+ const node = nodeOf(q);
284
+ if (--budget < 0 || node._tag === "Suspend" || node._tag === "Escaped" || node._tag === "Dispatch")
285
+ return false;
286
+ return children(node).every(visit);
287
+ };
288
+ return visit(p);
289
+ }
290
+ /**
291
+ * In a resumable build: token code (which fails by breaking out of `bad`)
292
+ * that read within `lookahead` units of the end of a partial input re-runs
293
+ * interpreted, since it may have to report `Incomplete` there. Token code
294
+ * leaves `p` where it stopped reading, even when it fails.
295
+ */
296
+ partialSafe(p, code, bad, lookahead, out, fail, fn) {
297
+ const ahead = Math.max(lookahead, Margin);
298
+ const st = this.v(fn);
299
+ const ok = this.v(fn);
300
+ const t = this.v(fn);
301
+ const leaf = this.label();
302
+ return `${st}=p;${ok}=false;${leaf}:{${bad}:{${code}${ok}=true;}` +
303
+ `if(!$S.partial||p+${ahead}<=E){if(${ok})break ${leaf};${fail}}` +
304
+ `p=${st};$S.pos=p;${t}=${this.const(p.step)}($S);if(${t}===F){${fail}}p=$S.pos;${out === null ? "" : `${out}=${t};`}}`;
305
+ }
306
+ call(name, out, fail) {
307
+ if (out === null)
308
+ return `if(${name}(p)===F){${fail}}p=P;`;
309
+ return `${out}=${name}(p);if(${out}===F){${fail}}p=P;`;
310
+ }
311
+ /** Runs the closure-compiled step of `p` on the shared state. */
312
+ delegate(p, used, out, fail, fn) {
313
+ const step = this.const(this.closure.compile(p, used));
314
+ const t = out ?? this.v(fn);
315
+ return `$S.pos=p;${t}=${step}($S);if(${t}===F){${fail}}p=$S.pos;`;
316
+ }
317
+ native(enc) {
318
+ return enc === undefined ? this.kind !== 2 : kindOfEncoding(enc) === this.kind;
319
+ }
320
+ inline(p, used, out, fail, fn, depth) {
321
+ const node = nodeOf(p);
322
+ const set = (value) => out === null ? "" : `${out}=${value};`;
323
+ const d = depth + 1;
324
+ switch (node._tag) {
325
+ case "Succeed":
326
+ return set(this.lit(node.value));
327
+ case "Sync":
328
+ return used ? set(`${this.const(node.evaluate)}()`) : "";
329
+ case "Fail":
330
+ return `$S.mode=${JSON.stringify(node.mode)};${fail}`;
331
+ case "Eof":
332
+ return `if(p<E){${BT}${fail}}` + (this.resumable ? `if($S.partial){$S.mode="Incomplete";${fail}}` : "") +
333
+ set("void 0");
334
+ case "Location":
335
+ return set("p");
336
+ case "RestLen":
337
+ return set("E-p");
338
+ case "Suspend":
339
+ return this.call(this.rule(node.resolve(), used), out, fail);
340
+ case "Any":
341
+ case "Literal":
342
+ case "OneOf":
343
+ case "TakeWhile": {
344
+ if (!this.native(node.encoding))
345
+ return this.delegate(p, used, out, fail, fn);
346
+ if (!this.resumable)
347
+ return this.token(node, out, fail, fn) ?? this.delegate(p, used, out, fail, fn);
348
+ const bad = this.label();
349
+ const code = this.token(node, out, `break ${bad};`, fn);
350
+ if (code === undefined)
351
+ return this.delegate(p, used, out, fail, fn);
352
+ return this.partialSafe(p, code, bad, node._tag === "Literal" ? node.literal.length * 4 : Margin, out, fail, fn);
353
+ }
354
+ case "Escaped": {
355
+ // Streaming builds use the closure compiler's escapes, which keep checkpoints
356
+ if (!this.native(node.encoding) || this.resumable)
357
+ return this.delegate(p, used, out, fail, fn);
358
+ return this.escaped(p, node, out, fail, fn, d);
359
+ }
360
+ case "Map": {
361
+ if (!used)
362
+ return this.gen(node.self, false, null, fail, fn, d);
363
+ if (node.f === toFloat && out !== null) {
364
+ const code = this.float(node, out, fail, fn, d);
365
+ if (code !== undefined)
366
+ return code;
367
+ }
368
+ // Streaming builds keep the array, which their checkpoints hold
369
+ if (node.f === fromEntries && out !== null && !this.resumable && entriesShape(node.self)) {
370
+ return this.entries(node.self, out, fail, fn, d);
371
+ }
372
+ const t = this.v(fn);
373
+ return this.gen(node.self, true, t, fail, fn, d) + set(`${this.const(node.f)}(${t})`);
374
+ }
375
+ case "As":
376
+ return this.gen(node.self, false, null, fail, fn, d) + (used ? set(this.lit(node.value)) : "");
377
+ case "Tap": {
378
+ const t = out ?? this.v(fn);
379
+ return this.gen(node.self, true, t, fail, fn, d) + `${this.const(node.f)}(${t});`;
380
+ }
381
+ case "TryMap":
382
+ case "FilterMap": {
383
+ const t = this.v(fn);
384
+ const r = this.v(fn);
385
+ const [tag, field] = node._tag === "TryMap" ? ["Success", "success"] : ["Some", "value"];
386
+ return this.gen(node.self, true, t, fail, fn, d) +
387
+ `${r}=${this.const(node.f)}(${t});if(${r}._tag!=="${tag}"){${BT}${fail}}${set(`${r}.${field}`)}`;
388
+ }
389
+ case "Filter": {
390
+ const t = out ?? this.v(fn);
391
+ return this.gen(node.self, true, t, fail, fn, d) + `if(!${this.const(node.predicate)}(${t})){${BT}${fail}}`;
392
+ }
393
+ case "FlatMap": {
394
+ const t = this.v(fn);
395
+ const r = out ?? this.v(fn);
396
+ this.closure.note(p, node, "the parser returned by the function runs interpreted");
397
+ return this.gen(node.self, true, t, fail, fn, d) +
398
+ `$S.pos=p;${r}=${this.const(node.f)}(${t}).step($S);if(${r}===F){${fail}}p=$S.pos;`;
399
+ }
400
+ case "Taken": {
401
+ if (node.encoding !== undefined && !this.native(node.encoding))
402
+ return this.delegate(p, used, out, fail, fn);
403
+ const st = this.v(fn);
404
+ const body = `${st}=p;` + this.gen(node.self, false, null, fail, fn, d);
405
+ if (out === null && node.encoding === undefined)
406
+ return body;
407
+ if (node.encoding === undefined) {
408
+ return body + set(this.kind === 0 ? `I.slice(${st},p)` : this.kind === 1 ? `I.subarray(${st},p)` : `$S.slice(${st},p)`);
409
+ }
410
+ const t = out ?? this.v(fn);
411
+ const enc = this.const(node.encoding);
412
+ return body + `${t}=R.textOf(${enc},${fastLimit(node.encoding)},$S,${st},p);if(${t}===F){${fail}}`;
413
+ }
414
+ case "WithTaken":
415
+ case "WithSpan": {
416
+ const st = this.v(fn);
417
+ const t = this.v(fn);
418
+ const extra = node._tag === "WithSpan" ? `{start:${st},end:p}` : `$S.slice(${st},p)`;
419
+ return `${st}=p;` + this.gen(node.self, true, t, fail, fn, d) + set(`[${t},${extra}]`);
420
+ }
421
+ case "Span": {
422
+ const st = this.v(fn);
423
+ return `${st}=p;` + this.gen(node.self, false, null, fail, fn, d) + set(`{start:${st},end:p}`);
424
+ }
425
+ case "Mode": {
426
+ const ok = this.label();
427
+ const bad = this.label();
428
+ return `${ok}:{${bad}:{${this.gen(node.self, used, out, `break ${bad};`, fn, d)}break ${ok};}` +
429
+ `if($S.mode===${JSON.stringify(node.from)})$S.mode=${JSON.stringify(node.to)};${fail}}`;
430
+ }
431
+ case "Context":
432
+ case "Expected":
433
+ case "MapError":
434
+ case "OrFail":
435
+ case "Trace":
436
+ case "RetryAfter":
437
+ return this.gen(node.self, used, out, fail, fn, d);
438
+ case "ResumeAfter": {
439
+ if (!used)
440
+ return this.gen(node.self, false, null, fail, fn, d);
441
+ const t = this.v(fn);
442
+ return this.gen(node.self, true, t, fail, fn, d) + set(`R.some(${t})`);
443
+ }
444
+ case "Opt":
445
+ case "OrElseSucceed": {
446
+ const st = this.v(fn);
447
+ const ok = this.label();
448
+ const bad = this.label();
449
+ const t = out === null ? null : this.v(fn);
450
+ const some = node._tag === "Opt" ? `R.some(${t})` : t;
451
+ const orElse = node._tag === "Opt" ? "R.none()" : `${this.const(node.value)}()`;
452
+ return `${st}=p;${ok}:{${bad}:{${this.gen(node.self, used, t, `break ${bad};`, fn, d)}${set(some)}break ${ok};}` +
453
+ `if($S.mode!=="Backtrack"){${fail}}p=${st};${set(orElse)}}`;
454
+ }
455
+ case "Peek": {
456
+ const st = this.v(fn);
457
+ return `${st}=p;${this.gen(node.self, used, out, fail, fn, d)}p=${st};`;
458
+ }
459
+ case "Not": {
460
+ const st = this.v(fn);
461
+ const ok = this.label();
462
+ const bad = this.label();
463
+ return `${st}=p;${ok}:{${bad}:{${this.gen(node.self, false, null, `break ${bad};`, fn, d)}p=${st};${BT}${fail}}` +
464
+ `if($S.mode!=="Backtrack"){${fail}}p=${st};}${set("void 0")}`;
465
+ }
466
+ case "Seq":
467
+ return this.seq(node, used, out, fail, fn, d);
468
+ case "Struct": {
469
+ if (out === null)
470
+ return node.parsers.map((q) => this.gen(q, false, null, fail, fn, d)).join("");
471
+ const vars = node.parsers.map(() => this.v(fn));
472
+ const code = node.parsers.map((q, i) => this.gen(q, true, vars[i], fail, fn, d)).join("");
473
+ if (node.keys.includes("__proto__")) {
474
+ return code + `${out}={};` + node.keys.map((k, i) => `${out}[${JSON.stringify(k)}]=${vars[i]};`).join("");
475
+ }
476
+ return code + `${out}={${node.keys.map((k, i) => `${JSON.stringify(k)}:${vars[i]}`).join(",")}};`;
477
+ }
478
+ case "ZipWith": {
479
+ if (out === null)
480
+ return this.gen(node.self, false, null, fail, fn, d) + this.gen(node.that, false, null, fail, fn, d);
481
+ const x = this.v(fn);
482
+ const y = this.v(fn);
483
+ return this.gen(node.self, true, x, fail, fn, d) + this.gen(node.that, true, y, fail, fn, d) +
484
+ `${out}=${this.const(node.f)}(${x},${y});`;
485
+ }
486
+ case "Alt":
487
+ return this.alt(node, used, out, fail, fn, d);
488
+ case "Dispatch":
489
+ return this.dispatch(p, node, used, out, fail, fn, d);
490
+ case "Repeat":
491
+ case "Fold":
492
+ return this.repeat(node, used, out, fail, fn, d);
493
+ case "Separated":
494
+ return this.separated(node, used, out, fail, fn, d);
495
+ default:
496
+ return this.delegate(p, used, out, fail, fn);
497
+ }
498
+ }
499
+ /**
500
+ * `Ascii.float` and `Text.float` (`map(floatText, toFloat)`): numbers in
501
+ * decimal notation are matched and converted in one pass by
502
+ * `scanFloatString` or `scanFloatBytes`, without slicing the input; the
503
+ * rest (`nan`, `inf`, failures before a digit) runs the parser. Returns
504
+ * `undefined` when this does not apply.
505
+ */
506
+ float(node, out, fail, fn, d) {
507
+ if (!floatTexts.has(node.self) || this.kind === 2)
508
+ return undefined;
509
+ let taken = nodeOf(node.self);
510
+ while (taken._tag === "Expected")
511
+ taken = nodeOf(taken.self);
512
+ if (taken._tag !== "Taken")
513
+ return undefined;
514
+ const enc = taken.encoding;
515
+ // Decimal notation is ASCII, which these encodings read unit by unit
516
+ if (enc !== undefined && !(this.native(enc) && enc.unit === 1 && enc.asciiCompatible))
517
+ return undefined;
518
+ const t = this.v(fn);
519
+ const scan = this.const(floatScan);
520
+ // Near the end of a partial input, the parser may have to report `Incomplete`
521
+ const near = this.resumable ? `||$S.partial&&${scan}.read+${Margin}>E` : "";
522
+ return `${out}=${this.kind === 0 ? "R.scanFloatString" : "R.scanFloatBytes"}(I,p,E);` +
523
+ `if(${out}===void 0${near}){${this.gen(node.self, true, t, fail, fn, d)}${out}=${this.const(toFloat)}(${t})}` +
524
+ `else if(${out}===F){${BT}${fail}}else p=${scan}.end;`;
525
+ }
526
+ seq(node, used, out, fail, fn, d) {
527
+ const output = node.output;
528
+ if (out === null || !used)
529
+ return node.parsers.map((q) => this.gen(q, false, null, fail, fn, d)).join("");
530
+ if (typeof output === "number") {
531
+ return node.parsers.map((q, i) => this.gen(q, i === output, i === output ? out : null, fail, fn, d)).join("");
532
+ }
533
+ const keep = (i) => output === "tuple" || output.includes(i);
534
+ const vars = node.parsers.map((_, i) => keep(i) ? this.v(fn) : null);
535
+ const code = node.parsers.map((q, i) => this.gen(q, keep(i), vars[i], fail, fn, d)).join("");
536
+ return code + `${out}=[${vars.filter((v) => v !== null).join(",")}];`;
537
+ }
538
+ /** A test that the unit `u` may start `first` (false for -1, the end of the input). */
539
+ startTest(first, u) {
540
+ const runs = runsOf(first.units);
541
+ const small = rangeTest(runs, u);
542
+ const low = small ?? `${this.const(first.units)}[${u}]===1`;
543
+ if (!first.high)
544
+ return small !== undefined ? `(${low})` : `(${u}<${TableSize}&&${low})`;
545
+ return `(${u}>=${TableSize}||${low})`;
546
+ }
547
+ alt(node, used, out, fail, fn, d) {
548
+ const parsers = node.parsers;
549
+ if (parsers.length === 0)
550
+ return `${BT}${fail}`;
551
+ if (parsers.length === 1)
552
+ return this.gen(parsers[0], used, out, fail, fn, d);
553
+ const firsts = this.kind === 2 ? undefined : parsers.map((q) => this.closure.firsts.of(q));
554
+ const prune = firsts !== undefined && planAlt(firsts) !== undefined;
555
+ const st = this.v(fn);
556
+ const u = prune ? this.v(fn) : "";
557
+ const done = this.label();
558
+ // Near the end of a partial input, no branch is skipped: it may be incomplete rather than fail
559
+ const read = this.resumable ? `$S.partial&&p+${Margin}>E?-2:p<E?${this.unit("p")}:-1` : `p<E?${this.unit("p")}:-1`;
560
+ let code = `${st}=p;${prune ? `${u}=${read};` : ""}${done}:{`;
561
+ parsers.forEach((q, i) => {
562
+ const bad = this.label();
563
+ const branch = `${bad}:{${this.gen(q, used, out, `break ${bad};`, fn, d)}break ${done};}` +
564
+ `if($S.mode!=="Backtrack"){${fail}}p=${st};`;
565
+ const f = firsts?.[i];
566
+ code += prune && f.mode === Strict
567
+ ? `if(${this.resumable ? `${u}===-2||` : ""}${this.startTest(f, u)}){${branch}}`
568
+ : branch;
569
+ });
570
+ return code + `${BT}${fail}}`;
571
+ }
572
+ dispatch(p, node, used, out, fail, fn, d) {
573
+ const choose = this.const(node.choose);
574
+ // The general path: run the selector, choose, then run the case's compiled step
575
+ const cases = new Map();
576
+ const caseStep = (q) => {
577
+ let s = cases.get(q);
578
+ if (s === undefined)
579
+ cases.set(q, s = this.closure.compile(q, used));
580
+ return s;
581
+ };
582
+ if (node.cases !== undefined) {
583
+ for (const key of Reflect.ownKeys(node.cases))
584
+ caseStep(node.cases[key]);
585
+ if (node.otherwise !== undefined)
586
+ caseStep(node.otherwise);
587
+ }
588
+ const table = this.const(cases);
589
+ const general = () => {
590
+ const st = this.v(fn);
591
+ const k = this.v(fn);
592
+ const q = this.v(fn);
593
+ const r = out ?? this.v(fn);
594
+ return `${st}=p;${this.gen(node.selector, true, k, fail, fn, d)}${q}=${choose}(${k});` +
595
+ `if(${q}===void 0){p=${st};${BT}${fail}}$S.pos=p;${r}=(${table}.get(${q})??${q}.step)($S);` +
596
+ `if(${r}===F){${fail}}p=$S.pos;`;
597
+ };
598
+ if (node.cases === undefined) {
599
+ this.closure.note(p, node, "the parser returned by the function of cases runs interpreted");
600
+ return general();
601
+ }
602
+ let sel = nodeOf(node.selector);
603
+ const peek = sel._tag === "Peek";
604
+ if (peek)
605
+ sel = nodeOf(sel.self);
606
+ if (sel._tag !== "Any" || !this.native(sel.encoding))
607
+ return general();
608
+ const enc = sel.encoding;
609
+ const r = enc === undefined ? undefined : this.reader(enc);
610
+ const limit = r === undefined ? (this.kind === 0 ? 0xd800 : TableSize) : Math.min(r.fast, 0xd800);
611
+ const size = Math.min(limit, TableSize);
612
+ if (size === 0)
613
+ return general();
614
+ // Group the units by the case they select
615
+ const groups = new Map();
616
+ for (let unit = 0; unit < size; unit++) {
617
+ const q = (node.choose)(enc === undefined && this.kind === 1 ? unit : charOf(unit));
618
+ if (q === undefined)
619
+ continue;
620
+ let g = groups.get(q);
621
+ if (g === undefined)
622
+ groups.set(q, g = []);
623
+ g.push(unit);
624
+ }
625
+ const u = this.v(fn);
626
+ const sw = this.label();
627
+ // A unit cut short by the end of the input takes the general path
628
+ const read = r === undefined
629
+ ? `p<E?${this.unit("p")}:-1`
630
+ : `${r.guard("p")}?${r.unit("p")}:p<E?${size}:-1`;
631
+ // Near the end of a partial input, the general path handles incomplete units
632
+ const near = this.resumable ? `$S.partial&&p+${Margin}>E?${size}:` : "";
633
+ let code = `${u}=${near}${read};${sw}:switch(${u}){`;
634
+ for (const [q, units] of groups) {
635
+ code += units.map((x) => `case ${x}:`).join("") +
636
+ `{${peek ? "" : `p+=${r?.width ?? 1};`}${this.gen(q, used, out, fail, fn, d)}break ${sw};}`;
637
+ }
638
+ code += `case -1:{${BT}${fail}}default:{if(${u}<${size}){${BT}${fail}}${general()}}}`;
639
+ return code;
640
+ }
641
+ repeat(node, used, out, fail, fn, d, collect) {
642
+ const { max, min } = node;
643
+ const loop = this.label();
644
+ const bad = this.label();
645
+ const n = this.v(fn);
646
+ const st = this.v(fn);
647
+ const isFold = node._tag === "Fold";
648
+ const keep = out !== null && used && collect === undefined;
649
+ const x = keep ? this.v(fn) : null;
650
+ const acc = keep ? out : this.v(fn);
651
+ let init = collect?.init ?? "";
652
+ let add = "";
653
+ if (keep) {
654
+ if (isFold) {
655
+ init = `${acc}=${this.const(node.init)}();`;
656
+ add = `${acc}=${this.const(node.f)}(${acc},${x});`;
657
+ }
658
+ else {
659
+ init = `${acc}=[];`;
660
+ add = `${acc}.push(${x});`;
661
+ }
662
+ }
663
+ const check = max === Infinity ? `if(p===${st}){$S.mode="Cut";${fail}}` : "";
664
+ const bound = max === Infinity ? "" : `${n}<${max}`;
665
+ const r = this.resumable ? this.resumePoint(fn) : undefined;
666
+ const save = r === undefined
667
+ ? ""
668
+ : `if($S.mode==="Incomplete"&&$S.resume!==void 0)R.save($S,${r.key},${r.entry},{acc:${acc},count:${n},pos:${st}});`;
669
+ // With `collect` (never in resumable builds), the element adds itself once the loop check passed
670
+ const element = collect === undefined
671
+ ? `${this.gen(node.self, keep, x, `break ${bad};`, fn, d)}${check}${add}`
672
+ : collect.element(`break ${bad};`, check);
673
+ const body = `${loop}:for(;${bound};${n}++){${st}=p;` +
674
+ `${bad}:{${element}continue ${loop};}` +
675
+ `${save}if($S.mode!=="Backtrack"${min > 0 ? `||${n}<${min}` : ""}){${fail}}p=${st};break ${loop};}`;
676
+ if (r === undefined)
677
+ return `${init}${n}=0;${body}${collect?.finish ?? ""}`;
678
+ return r.wrap(acc, `${acc}=cp.acc;${n}=cp.count;p=cp.pos;`, `${init}${n}=0;`, body);
679
+ }
680
+ /**
681
+ * In a resumable build, a repetition entered at `entry` may restart from a
682
+ * checkpoint (`restore`, with the checkpoint in `cp`), or return the result
683
+ * of a `Done` one; a resumed repetition records its result when it ends.
684
+ */
685
+ resumePoint(fn) {
686
+ const key = this.const({});
687
+ const entry = this.v(fn);
688
+ const resumed = this.v(fn);
689
+ const done = this.label();
690
+ return {
691
+ key,
692
+ entry,
693
+ resumed,
694
+ wrap: (value, restore, fresh, body) => `${entry}=p;${resumed}=false;${done}:{if($S.resume!==void 0){const cp=R.take($S,${key},p);` +
695
+ `if(cp instanceof R.Done){p=cp.pos;${value}=cp.value;break ${done};}` +
696
+ `if(cp!==void 0){${restore}${resumed}=true;}}if(!${resumed}){${fresh}}${body}` +
697
+ `if(${resumed})R.done($S,${key},${entry},${value},p);}`
698
+ };
699
+ }
700
+ separated(node, used, out, fail, fn, d, collect) {
701
+ const { max, min } = node;
702
+ const keep = out !== null && used && collect === undefined;
703
+ if (max === 0)
704
+ return collect !== undefined ? collect.init + collect.finish : keep ? `${out}=[];` : "";
705
+ const x = keep ? this.v(fn) : null;
706
+ const acc = keep ? out : this.v(fn);
707
+ const n = this.v(fn);
708
+ const st = this.v(fn);
709
+ const done = this.label();
710
+ const loop = this.label();
711
+ const push = keep ? `${acc}.push(${x});` : "";
712
+ const r = this.resumable ? this.resumePoint(fn) : undefined;
713
+ const save = r === undefined
714
+ ? ""
715
+ : `if($S.mode==="Incomplete"&&$S.resume!==void 0)R.save($S,${r.key},${r.entry},{acc:${acc},count:${n},pos:${st}});`;
716
+ // Runs `body`; on its failure, stops the repetition (or fails if `fatal`)
717
+ const attempt = (body, success, fatal, checkpoint) => {
718
+ const ok = this.label();
719
+ const bad = this.label();
720
+ return `${ok}:{${bad}:{${body(`break ${bad};`)}${success}break ${ok};}` +
721
+ `${checkpoint}if($S.mode!=="Backtrack"${fatal}){${fail}}p=${st};break ${done};}`;
722
+ };
723
+ const self = (f) => collect === undefined ? this.gen(node.self, keep, x, f, fn, d) : collect.element(f, "");
724
+ const sep = (f) => this.gen(node.separator, false, null, f, fn, d);
725
+ const check = max === Infinity ? `if(p===${st}){$S.mode="Cut";${fail}}` : "";
726
+ const first = `${collect?.init ?? (keep ? `${acc}=[];` : "")}${n}=0;${st}=p;` + attempt(self, `${push}${n}++;`, min > 0 ? "||true" : "", "");
727
+ const rest = `${loop}:while(${max === Infinity ? "true" : `${n}<${max}`}){${st}=p;` +
728
+ attempt(sep, "", `||${n}<${min}`, save) + check +
729
+ attempt(self, `${push}${n}++;continue ${loop};`, `||${n}<${min}`, save) +
730
+ `}`;
731
+ if (r === undefined)
732
+ return `${done}:{${first}${rest}}${collect?.finish ?? ""}`;
733
+ // `done` ends the repetition; the checkpoint wrapper records the result after it
734
+ return r.wrap(acc, `${acc}=cp.acc;${n}=cp.count;p=cp.pos;`, "", `${done}:{if(!${r.resumed}){${first}}${rest}}`);
735
+ }
736
+ /**
737
+ * `map(self, Object.fromEntries)`, where `entriesShape(self)`: builds the
738
+ * object directly, assigning each entry as it is parsed (see
739
+ * `internal/entries.ts`), without the pairs and their array. `cut`,
740
+ * `preceded`, `terminated` and diagnostics around the repetition are
741
+ * compiled as usual around it.
742
+ */
743
+ entries(p, out, fail, fn, d) {
744
+ const node = nodeOf(p);
745
+ switch (node._tag) {
746
+ case "Mode": {
747
+ const ok = this.label();
748
+ const bad = this.label();
749
+ return `${ok}:{${bad}:{${this.entries(node.self, out, `break ${bad};`, fn, d)}break ${ok};}` +
750
+ `if($S.mode===${JSON.stringify(node.from)})$S.mode=${JSON.stringify(node.to)};${fail}}`;
751
+ }
752
+ case "Seq": {
753
+ const i = node.output;
754
+ return node.parsers.map((q, j) => j === i ? this.entries(q, out, fail, fn, d) : this.gen(q, false, null, fail, fn, d)).join("");
755
+ }
756
+ case "Repeat":
757
+ case "Separated": {
758
+ const pair = pairOf(node.self);
759
+ const deferred = this.v(fn);
760
+ const key = this.v(fn);
761
+ const value = this.v(fn);
762
+ const collect = {
763
+ init: `${out}={};${deferred}=void 0;`,
764
+ element: (f, check) => pair.parsers.map((q, j) => this.gen(q, j === pair.key || j === pair.value, j === pair.key ? key : j === pair.value ? value : null, f, fn, d)).join("") + check +
765
+ `if(${deferred}===void 0&&R.isPlainKey(${key}))${out}[${key}]=${value};` +
766
+ `else ${deferred}=R.addEntry(${out},${deferred},${key},${value});`,
767
+ finish: `if(${deferred}!==void 0)R.flushEntries(${out},${deferred});`
768
+ };
769
+ return node._tag === "Repeat"
770
+ ? this.repeat(node, true, out, fail, fn, d, collect)
771
+ : this.separated(node, true, out, fail, fn, d, collect);
772
+ }
773
+ default:
774
+ return this.entries(node.self, out, fail, fn, d);
775
+ }
776
+ }
777
+ // ---------------------------------------------------------------------------
778
+ // Tokens
779
+ // ---------------------------------------------------------------------------
780
+ /** An expression: is the unit `c`, known to be below `size` (at most `TableSize`), accepted? */
781
+ member(accept, c, size = TableSize) {
782
+ return tableTest(accept, c, size) ?? `${this.const(accept)}[${c}]===1`;
783
+ }
784
+ /** An expression: is the code point `c` (at least `TableSize`) accepted? */
785
+ memberHigh(set, negate, c) {
786
+ if (set.ranges !== undefined && !set.ranges.some(([, b]) => b >= TableSize))
787
+ return negate ? "true" : "false";
788
+ return `${this.const(set.test)}(${c})!==${negate}`;
789
+ }
790
+ /**
791
+ * An expression: does a `Text` set accept the unit `c`, known to be below
792
+ * `r.fast`? Code points from `TableSize` up are tested by the set's
793
+ * function, unless its ranges show they are all rejected.
794
+ */
795
+ textAccepts(r, cs, accept, negate, c) {
796
+ if (r.fast <= TableSize)
797
+ return `(${this.member(accept, c, r.fast)})`;
798
+ const member = this.member(accept, c);
799
+ if (reachesAbove(cs, TableSize))
800
+ return `(${c}<${TableSize}?${member}:${this.const(cs.test)}(${c})!==${negate})`;
801
+ return negate ? `(${c}>=${TableSize}||${member})` : `(${c}<${TableSize}&&${member})`;
802
+ }
803
+ /**
804
+ * An expression: does a `Text` set reject `c`, a code point that `decode`
805
+ * returned? The built-in encodings only decode code points from `r.fast`
806
+ * up there.
807
+ */
808
+ textRejectsDecoded(enc, r, cs, negate, c) {
809
+ if (r.fast > 0 && builtinEncodings.has(enc) && !reachesAbove(cs, r.fast))
810
+ return String(!negate);
811
+ return `${this.const(cs.test)}(${c})===${negate}`;
812
+ }
813
+ token(node, out, fail, fn) {
814
+ const set = (value) => out === null ? "" : `${out}=${value};`;
815
+ const enc = node.encoding;
816
+ const kind = this.kind;
817
+ const failBT = `{${BT}${fail}}`;
818
+ switch (node._tag) {
819
+ case "Any": {
820
+ if (enc === undefined) {
821
+ if (kind === 1)
822
+ return `if(p>=E)${failBT}${set("I[p]")}p++;`;
823
+ const c = this.v(fn);
824
+ return `if(p>=E)${failBT}${c}=I.charCodeAt(p);` +
825
+ `if(${c}>=55296&&${c}<=56319&&p+1<I.length&&(I.charCodeAt(p+1)&64512)===56320){${set("I.slice(p,p+2)")}p+=2}` +
826
+ `else{${set("I[p]")}p++}`;
827
+ }
828
+ const r = this.reader(enc);
829
+ const c = this.v(fn);
830
+ const dec = `${this.const(enc.decode)}(I,p,E)`;
831
+ return `if(p>=E)${failBT}` +
832
+ (r.fast > 0 ? `if(${r.guard("p")}&&(${c}=${r.unit("p")})<${r.fast}){${set(`R.charOf(${c})`)}p+=${r.width}}else` : "") +
833
+ `{${c}=${dec};if(${c}<0)${failBT}${set(`R.charOf(${c})`)}p+=${this.const(enc.width)}(${c})}`;
834
+ }
835
+ case "Literal": {
836
+ const lit = node.literal;
837
+ if (enc !== undefined) {
838
+ if (node.caseless)
839
+ return undefined;
840
+ const encoded = enc.encode(lit);
841
+ return this.literalUnits(typeof encoded === "string" ? unitsOf(encoded) : Array.from(encoded), false, fail) + set(this.lit(lit));
842
+ }
843
+ const literalKind = typeof lit === "string" ? 0 : lit instanceof Uint8Array ? 1 : 2;
844
+ if (kind === 0 && literalKind !== 0)
845
+ return undefined;
846
+ if (literalKind === 2)
847
+ return undefined;
848
+ const codes = kind === 0
849
+ ? unitsOf(lit)
850
+ : Array.from(literalKind === 0 ? new TextEncoder().encode(lit) : lit);
851
+ const len = codes.length;
852
+ const value = !node.caseless && literalKind === kind
853
+ ? this.lit(lit)
854
+ : kind === 0
855
+ ? `I.slice(p-${len},p)`
856
+ : `I.subarray(p-${len},p)`;
857
+ return this.literalUnits(codes, node.caseless, fail) + set(value);
858
+ }
859
+ case "OneOf": {
860
+ const negate = node.negate;
861
+ const cs = enc === undefined ? tokenSet(node.set, kind) : textSet(node.set);
862
+ const accept = acceptTable(cs, negate);
863
+ const c = this.v(fn);
864
+ const value = (len) => this.kind === 0 ? `I.slice(p,p+${len})` : `I[p]`;
865
+ if (enc === undefined) {
866
+ if (kind === 1)
867
+ return `if(p>=E)${failBT}${c}=I[p];if(!(${this.member(accept, c)}))${failBT}${set("I[p]")}p++;`;
868
+ const cp = this.v(fn);
869
+ if (!negate && this.memberHigh(cs, negate, cp) === "false") {
870
+ return `if(p>=E)${failBT}${c}=I.charCodeAt(p);if(${c}>=${TableSize}||!(${this.member(accept, c)}))${failBT}${set("I[p]")}p++;`;
871
+ }
872
+ return `if(p>=E)${failBT}${c}=I.charCodeAt(p);` +
873
+ `if(${c}<${TableSize}){if(!(${this.member(accept, c)}))${failBT}${set("I[p]")}p++}` +
874
+ `else{${cp}=${c};if(${c}>=55296&&${c}<=56319&&p+1<I.length){const d=I.charCodeAt(p+1);` +
875
+ `if((d&64512)===56320)${cp}=((${c}-55296)<<10)+(d-56320)+65536}` +
876
+ `if(!(${this.memberHigh(cs, negate, cp)}))${failBT}` +
877
+ `if(${cp}>65535){${set(value("2"))}p+=2}else{${set("I[p]")}p++}}`;
878
+ }
879
+ const r = this.reader(enc);
880
+ return `if(p>=E)${failBT}` +
881
+ (r.fast > 0
882
+ ? `if(${r.guard("p")}&&(${c}=${r.unit("p")})<${r.fast}){if(!${this.textAccepts(r, cs, accept, negate, c)})${failBT}${set(`R.charOf(${c})`)}p+=${r.width}}else`
883
+ : "") +
884
+ `{${c}=${this.const(enc.decode)}(I,p,E);if(${c}<0||${this.textRejectsDecoded(enc, r, cs, negate, c)})${failBT}` +
885
+ `${set(`R.charOf(${c})`)}p+=${this.const(enc.width)}(${c})}`;
886
+ }
887
+ case "TakeWhile":
888
+ return this.takeWhile(node, out, fail, fn);
889
+ }
890
+ }
891
+ /** Matches literal units at `p`, advancing past them. */
892
+ literalUnits(codes, caseless, fail) {
893
+ const len = codes.length;
894
+ if (len === 0)
895
+ return "";
896
+ const test = (c, i) => {
897
+ const at = this.unit(i === 0 ? "p" : `p+${i}`);
898
+ if (caseless && isLetter(c))
899
+ return `(${at}|32)===${lowerAscii(c)}`;
900
+ return `${at}===${c}`;
901
+ };
902
+ if (len <= 8) {
903
+ // Reading past the end gives NaN or undefined, which matches nothing
904
+ return `if(!(${codes.map(test).join("&&")})){${BT}${fail}}p+=${len};`;
905
+ }
906
+ if (this.kind === 0 && !caseless) {
907
+ const str = String.fromCharCode(...codes);
908
+ return `if(!I.startsWith(${JSON.stringify(str)},p)){${BT}${fail}}p+=${len};`;
909
+ }
910
+ const expect = this.const(Uint8Array.from(caseless ? codes.map(lowerAscii) : codes));
911
+ const lower = caseless ? `${this.const(lowerAscii)}` : "";
912
+ return `if(E-p<${len}){${BT}${fail}}for(let i=0;i<${len};i++)if(${lower}(${this.unit("p+i")})!==${expect}[i]){${BT}${fail}}p+=${len};`;
913
+ }
914
+ takeWhile(node, out, fail, fn) {
915
+ const enc = node.encoding;
916
+ const { max, min, negate } = node;
917
+ const kind = this.kind;
918
+ const cs = enc === undefined ? tokenSet(node.set, kind) : textSet(node.set);
919
+ const accept = acceptTable(cs, negate);
920
+ const st = this.v(fn);
921
+ const c = this.v(fn);
922
+ const n = this.v(fn);
923
+ const loop = this.label();
924
+ const counted = max !== Infinity || min > 1;
925
+ const count = counted ? `${n}++;` : "";
926
+ const bound = max !== Infinity ? `&&${n}<${max}` : "";
927
+ const slice = enc !== undefined
928
+ ? `${this.const(enc.text)}(I,${st},p)`
929
+ : kind === 0
930
+ ? `I.slice(${st},p)`
931
+ : `I.subarray(${st},p)`;
932
+ const finish = (min > 0 ? `if(${counted ? n : `p-${st}`}<${min}){${BT}${fail}}` : "") +
933
+ (out === null ? "" : `${out}=${slice};`);
934
+ const head = `${st}=p;${counted ? `${n}=0;` : ""}${loop}:while(p<E${bound}){${c}=${this.unit("p")};`;
935
+ const member = this.member(accept, c);
936
+ if (kind === 1 && (enc === undefined || fastLimit(enc) >= TableSize)) {
937
+ // Bytes, one token each
938
+ return `${head}if(!(${member}))break;p++;${count}}${finish}`;
939
+ }
940
+ if (enc !== undefined) {
941
+ // Text: inline the encoding's single-unit code points, decode the rest
942
+ const r = this.reader(enc);
943
+ // The loop condition already checks a unit of width 1
944
+ const guard = r.width === 1 ? "" : `${r.guard("p")}&&`;
945
+ return `${st}=p;${counted ? `${n}=0;` : ""}${loop}:while(p<E${bound}){` +
946
+ (r.fast > 0
947
+ ? `if(${guard}(${c}=${r.unit("p")})<${r.fast}){if(!${this.textAccepts(r, cs, accept, negate, c)})break ${loop};p+=${r.width}}else`
948
+ : "") +
949
+ `{${c}=${this.const(enc.decode)}(I,p,E);if(${c}<0||${this.textRejectsDecoded(enc, r, cs, negate, c)})break ${loop};` +
950
+ `p+=${this.const(enc.width)}(${c})}${count}}${finish}`;
951
+ }
952
+ const fast = 0xd800;
953
+ const small = TableSize;
954
+ const highTest = (v) => this.memberHigh(cs, negate, v);
955
+ // Token on strings: code points, with lenient surrogates
956
+ const cp = this.v(fn);
957
+ const never = highTest(c) === "false";
958
+ // Every code point from `TableSize` up is accepted: without a count,
959
+ // surrogate pairs can be skipped a unit at a time
960
+ const always = highTest(c) === "true";
961
+ const rest = never && !negate
962
+ ? `break;`
963
+ : always && !counted
964
+ ? `p++;`
965
+ : `if(${c}<${fast}||${c}>56319){if(!(${highTest(c)}))break ${loop};p++}` +
966
+ `else{${cp}=${c};if(p+1<I.length){const d=I.charCodeAt(p+1);if((d&64512)===56320)${cp}=((${c}-55296)<<10)+(d-56320)+65536}` +
967
+ `if(!(${highTest(cp)}))break ${loop};p+=${cp}>65535?2:1}`;
968
+ return `${head}if(${c}<${small}){if(!(${member}))break;p++}else ${rest}${count}}${finish}`;
969
+ }
970
+ escaped(p, node, out, fail, fn, d) {
971
+ const enc = node.encoding;
972
+ const ctrl = node.control;
973
+ const r = enc === undefined ? undefined : this.reader(enc);
974
+ if (r !== undefined && !(ctrl < r.fast))
975
+ return this.delegate(p, !node.raw, out, fail, fn);
976
+ const raw = node.raw;
977
+ const acc = raw ? null : out ?? this.v(fn);
978
+ const x = raw ? null : this.v(fn);
979
+ const b = this.v(fn);
980
+ const st = this.v(fn);
981
+ const okv = this.v(fn);
982
+ const loop = this.label();
983
+ const bad = this.label();
984
+ const normal = this.gen(node.normal, !raw, x, `break ${bad};`, fn, d);
985
+ const escape = this.gen(node.escape, !raw, x, fail, fn, d);
986
+ const onNormal = raw
987
+ ? `if(p===${b}){$S.mode="Cut";${fail}}continue ${loop};`
988
+ : `if(p!==${b}){${acc}+=${x};continue ${loop}}`;
989
+ const slice = enc !== undefined
990
+ ? `${this.const(enc.text)}(I,${st},p)`
991
+ : this.kind === 0
992
+ ? `I.slice(${st},p)`
993
+ : `I.subarray(${st},p)`;
994
+ const ctrlTest = r === undefined ? `p<E&&${this.unit("p")}===${ctrl}` : `${r.guard("p")}&&${r.unit("p")}===${ctrl}`;
995
+ return `${raw ? `${st}=p;` : `${acc}="";`}${loop}:while(p<E){${b}=p;${okv}=false;` +
996
+ `${bad}:{${normal}${okv}=true;}` +
997
+ `if(${okv}){${onNormal}}else{if($S.mode!=="Backtrack"){${fail}}p=${b}}` +
998
+ `if(${ctrlTest}){p+=${r?.width ?? 1};${escape}${raw ? "" : `${acc}+=${x};`}}else break ${loop};}` +
999
+ (raw && out !== null ? `${out}=${slice};` : "");
1000
+ }
1001
+ }
1002
+ /** The UTF-16 code units of a string. */
1003
+ const unitsOf = (s) => Array.from({ length: s.length }, (_, i) => s.charCodeAt(i));
1004
+ /** 1 where a small code is accepted (taking `negate` into account). */
1005
+ const acceptTable = (set, negate) => {
1006
+ const t = new Uint8Array(TableSize);
1007
+ for (let c = 0; c < TableSize; c++)
1008
+ t[c] = (set.table[c] === 1) !== negate ? 1 : 0;
1009
+ return t;
1010
+ };
1011
+ /** Generates the source of a compiled parser, without building it. */
1012
+ export const generate = (root, kind, resumable = false) => {
1013
+ const e = new Emitter(root, kind, resumable);
1014
+ const main = e.rule(root, true);
1015
+ const source = `"use strict";let $I,$E,$S,P;${e.functions.join("\n")}\n` +
1016
+ `return function run(state){const sI=$I,sE=$E,sS=$S,sP=P;$I=state.input;$E=state.end;$S=state;` +
1017
+ `try{const v=${main}(state.pos);if(v!==F)state.pos=P;return v}finally{$I=sI;$E=sE;$S=sS;P=sP}}`;
1018
+ return { source, constants: e.constants, fallbacks: e.fallbacks };
1019
+ };
1020
+ /** Compiles a root parser for one input kind with `new Function`. */
1021
+ export const compileJit = (root, kind, resumable = false) => {
1022
+ const { constants, fallbacks, source } = generate(root, kind, resumable);
1023
+ const run = globalThis.Function("C", "F", "R", source)(constants, Fail, runtime);
1024
+ // Generated code reads past `end` expecting nothing to match there, which
1025
+ // holds when `end` is the input's length, as it is in the runners.
1026
+ let closure;
1027
+ const step = (state) => state.end === state.input.length ? run(state) : (closure ??= createClosureCompiler(kind, resumable).compile(root, true))(state);
1028
+ return { step, fallbacks, source };
1029
+ };
1030
+ //# sourceMappingURL=jit.js.map