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