@thomasfosterau/effect-parse 0.4.1 → 0.6.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.
- package/CHANGELOG.md +202 -0
- package/README.md +56 -14
- package/dist/Ascii.d.ts +11 -4
- package/dist/Ascii.d.ts.map +1 -1
- package/dist/Ascii.js +12 -4
- package/dist/Ascii.js.map +1 -1
- package/dist/Binary.d.ts +5 -2
- package/dist/Binary.d.ts.map +1 -1
- package/dist/Binary.js +83 -37
- package/dist/Binary.js.map +1 -1
- package/dist/Bits.d.ts.map +1 -1
- package/dist/Bits.js +11 -4
- package/dist/Bits.js.map +1 -1
- package/dist/Compiler.d.ts +74 -2
- package/dist/Compiler.d.ts.map +1 -1
- package/dist/Compiler.js +78 -1
- package/dist/Compiler.js.map +1 -1
- package/dist/Expression.d.ts.map +1 -1
- package/dist/Expression.js +86 -74
- package/dist/Expression.js.map +1 -1
- package/dist/Input.d.ts +56 -5
- package/dist/Input.d.ts.map +1 -1
- package/dist/Input.js +70 -1
- package/dist/Input.js.map +1 -1
- package/dist/Nom.d.ts +5 -15
- package/dist/Nom.d.ts.map +1 -1
- package/dist/Nom.js.map +1 -1
- package/dist/ParseError.d.ts +69 -11
- package/dist/ParseError.d.ts.map +1 -1
- package/dist/ParseError.js +129 -28
- package/dist/ParseError.js.map +1 -1
- package/dist/Parser.d.ts +375 -29
- package/dist/Parser.d.ts.map +1 -1
- package/dist/Parser.js +394 -37
- package/dist/Parser.js.map +1 -1
- package/dist/ParserSchema.d.ts.map +1 -1
- package/dist/ParserSchema.js +2 -3
- package/dist/ParserSchema.js.map +1 -1
- package/dist/ParserStream.d.ts +122 -14
- package/dist/ParserStream.d.ts.map +1 -1
- package/dist/ParserStream.js +293 -62
- package/dist/ParserStream.js.map +1 -1
- package/dist/Syntax.d.ts +23 -5
- package/dist/Syntax.d.ts.map +1 -1
- package/dist/Syntax.js +1 -1
- package/dist/Syntax.js.map +1 -1
- package/dist/Text.d.ts.map +1 -1
- package/dist/Text.js +21 -15
- package/dist/Text.js.map +1 -1
- package/dist/Token.d.ts +65 -11
- package/dist/Token.d.ts.map +1 -1
- package/dist/Token.js +73 -26
- package/dist/Token.js.map +1 -1
- package/dist/internal/compiler/closure.d.ts +1 -1
- package/dist/internal/compiler/closure.d.ts.map +1 -1
- package/dist/internal/compiler/closure.js +263 -113
- package/dist/internal/compiler/closure.js.map +1 -1
- package/dist/internal/compiler/entries.d.ts +3 -1
- package/dist/internal/compiler/entries.d.ts.map +1 -1
- package/dist/internal/compiler/entries.js +3 -2
- package/dist/internal/compiler/entries.js.map +1 -1
- package/dist/internal/compiler/first.d.ts.map +1 -1
- package/dist/internal/compiler/first.js +9 -2
- package/dist/internal/compiler/first.js.map +1 -1
- package/dist/internal/compiler/graph.d.ts +39 -0
- package/dist/internal/compiler/graph.d.ts.map +1 -0
- package/dist/internal/compiler/graph.js +78 -0
- package/dist/internal/compiler/graph.js.map +1 -0
- package/dist/internal/compiler/jit.d.ts +5 -0
- package/dist/internal/compiler/jit.d.ts.map +1 -1
- package/dist/internal/compiler/jit.js +208 -106
- package/dist/internal/compiler/jit.js.map +1 -1
- package/dist/internal/compiler/registry.d.ts +11 -3
- package/dist/internal/compiler/registry.d.ts.map +1 -1
- package/dist/internal/compiler/registry.js.map +1 -1
- package/dist/internal/compiler/search.d.ts +32 -0
- package/dist/internal/compiler/search.d.ts.map +1 -0
- package/dist/internal/compiler/search.js +68 -0
- package/dist/internal/compiler/search.js.map +1 -0
- package/dist/internal/compiler/sets.d.ts.map +1 -1
- package/dist/internal/compiler/sets.js +1 -1
- package/dist/internal/compiler/sets.js.map +1 -1
- package/dist/internal/compiler/wasm.d.ts +8 -0
- package/dist/internal/compiler/wasm.d.ts.map +1 -0
- package/dist/internal/compiler/wasm.js +2840 -0
- package/dist/internal/compiler/wasm.js.map +1 -0
- package/dist/internal/compiler/wasmAsm.d.ts +199 -0
- package/dist/internal/compiler/wasmAsm.d.ts.map +1 -0
- package/dist/internal/compiler/wasmAsm.js +427 -0
- package/dist/internal/compiler/wasmAsm.js.map +1 -0
- package/dist/internal/entries.d.ts +3 -1
- package/dist/internal/entries.d.ts.map +1 -1
- package/dist/internal/entries.js.map +1 -1
- package/dist/internal/node.d.ts +77 -3
- package/dist/internal/node.d.ts.map +1 -1
- package/dist/internal/node.js +54 -10
- package/dist/internal/node.js.map +1 -1
- package/dist/internal/numbers.d.ts.map +1 -1
- package/dist/internal/numbers.js.map +1 -1
- package/dist/internal/run.d.ts +14 -0
- package/dist/internal/run.d.ts.map +1 -1
- package/dist/internal/run.js +53 -11
- package/dist/internal/run.js.map +1 -1
- package/dist/internal/stack.d.ts +14 -0
- package/dist/internal/stack.d.ts.map +1 -1
- package/dist/internal/stack.js +24 -2
- package/dist/internal/stack.js.map +1 -1
- package/dist/internal/syntax.d.ts +4 -4
- package/dist/internal/syntax.d.ts.map +1 -1
- package/dist/internal/syntax.js +18 -10
- package/dist/internal/syntax.js.map +1 -1
- package/dist/internal/text.d.ts +32 -0
- package/dist/internal/text.d.ts.map +1 -1
- package/dist/internal/text.js +68 -14
- package/dist/internal/text.js.map +1 -1
- package/dist/internal/tokens.d.ts +20 -0
- package/dist/internal/tokens.d.ts.map +1 -1
- package/dist/internal/tokens.js +72 -39
- package/dist/internal/tokens.js.map +1 -1
- package/dist/internal/tuple.d.ts +6 -0
- package/dist/internal/tuple.d.ts.map +1 -0
- package/dist/internal/tuple.js +170 -0
- package/dist/internal/tuple.js.map +1 -0
- package/package.json +18 -10
- package/src/Ascii.ts +47 -12
- package/src/Binary.ts +174 -73
- package/src/Bits.ts +16 -6
- package/src/Compiler.ts +101 -10
- package/src/Expression.ts +94 -81
- package/src/Input.ts +99 -7
- package/src/Nom.ts +15 -5
- package/src/ParseError.ts +209 -52
- package/src/Parser.ts +684 -143
- package/src/ParserSchema.ts +1 -2
- package/src/ParserStream.ts +361 -68
- package/src/Syntax.ts +60 -36
- package/src/Text.ts +32 -27
- package/src/Token.ts +152 -34
- package/src/internal/compiler/closure.ts +371 -153
- package/src/internal/compiler/entries.ts +4 -2
- package/src/internal/compiler/first.ts +16 -0
- package/src/internal/compiler/graph.ts +96 -0
- package/src/internal/compiler/jit.ts +319 -169
- package/src/internal/compiler/registry.ts +10 -2
- package/src/internal/compiler/search.ts +68 -0
- package/src/internal/compiler/sets.ts +7 -3
- package/src/internal/compiler/wasm.ts +3276 -0
- package/src/internal/compiler/wasmAsm.ts +484 -0
- package/src/internal/entries.ts +8 -2
- package/src/internal/node.ts +103 -7
- package/src/internal/numbers.ts +3 -1
- package/src/internal/run.ts +73 -12
- package/src/internal/stack.ts +25 -1
- package/src/internal/syntax.ts +39 -18
- package/src/internal/text.ts +97 -9
- package/src/internal/tokens.ts +106 -14
- package/src/internal/tuple.ts +141 -0
|
@@ -3,17 +3,20 @@ import * as Result from "effect/Result";
|
|
|
3
3
|
import { Fail } from "../../Input.js";
|
|
4
4
|
import { floatScan, floatTexts, scanFloatBytes, scanFloatString, toFloat } from "../numbers.js";
|
|
5
5
|
import { Key } from "../key.js";
|
|
6
|
+
import { Defer, NodeId, nodeOf, scansFloat } from "../node.js";
|
|
6
7
|
import * as Resume from "../resume.js";
|
|
7
8
|
import { compileAny } from "../tokens.js";
|
|
8
9
|
import { backend as backend$1, createClosureCompiler } from "./closure.js";
|
|
9
10
|
import * as Option from "effect/Option";
|
|
10
|
-
import { charOf, fastLimit, latin1, string, utf16be, utf16le, utf8, validate } from "../text.js";
|
|
11
|
+
import { ShortText, charOf, fastLimit, latin1, string, textIn, utf16be, utf16le, utf8, utf8Text, validate } from "../text.js";
|
|
11
12
|
import * as Arr from "effect/Array";
|
|
12
13
|
import { addEntry, flushEntries, fromEntries, isPlainKey } from "../entries.js";
|
|
13
|
-
import
|
|
14
|
+
import * as Stack from "../stack.js";
|
|
14
15
|
import { buildsEntries, pairOf } from "./entries.js";
|
|
15
16
|
import { Strict, planAlt } from "./first.js";
|
|
17
|
+
import { SearchHead, StopCache, nextStop, stopChars } from "./search.js";
|
|
16
18
|
import { TableSize, acceptTable, kindOfEncoding, reachesAbove, textSet, tokenSet } from "./sets.js";
|
|
19
|
+
import { countInlined, countRefs, isLeaf, isLetter, isSmall, lowerAscii, selectorOf } from "./graph.js";
|
|
17
20
|
// src/internal/compiler/jit.ts
|
|
18
21
|
/**
|
|
19
22
|
* The JIT: emits JavaScript source for a parser's description and builds
|
|
@@ -33,11 +36,15 @@ import { TableSize, acceptTable, kindOfEncoding, reachesAbove, textSet, tokenSet
|
|
|
33
36
|
*/
|
|
34
37
|
/** Helpers available to generated code as `R`. */
|
|
35
38
|
const runtime = {
|
|
39
|
+
StopCache,
|
|
40
|
+
nextStop,
|
|
36
41
|
take: Resume.take,
|
|
37
42
|
save: Resume.save,
|
|
38
43
|
Done: Resume.Done,
|
|
39
44
|
/** Records the result of a resumed repetition (see `Resume.done`). */
|
|
40
45
|
done: (state, key, entry, value, pos) => Resume.save(state, key, entry, new Resume.Done(value, pos)),
|
|
46
|
+
isStackOverflow: Stack.isStackOverflow,
|
|
47
|
+
tooDeep: Stack.tooDeep,
|
|
41
48
|
some: Option.some,
|
|
42
49
|
none: Option.none,
|
|
43
50
|
charOf,
|
|
@@ -56,8 +63,9 @@ const runtime = {
|
|
|
56
63
|
s.mode = "Backtrack";
|
|
57
64
|
return Fail;
|
|
58
65
|
}
|
|
59
|
-
return enc
|
|
60
|
-
}
|
|
66
|
+
return textIn(enc, s, start, end);
|
|
67
|
+
},
|
|
68
|
+
utf8Text
|
|
61
69
|
};
|
|
62
70
|
let checked;
|
|
63
71
|
let supported = false;
|
|
@@ -87,22 +95,6 @@ const Margin = 4;
|
|
|
87
95
|
var Fn = class {
|
|
88
96
|
vars = [];
|
|
89
97
|
};
|
|
90
|
-
const isLeaf = (node) => {
|
|
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
|
-
}
|
|
103
|
-
};
|
|
104
|
-
const lowerAscii = (c) => c >= 65 && c <= 90 ? c + 32 : c;
|
|
105
|
-
const isLetter = (c) => c >= 65 && c <= 90 || c >= 97 && c <= 122;
|
|
106
98
|
/** The inclusive ranges of 1s in a table. */
|
|
107
99
|
const runsOf = (table) => {
|
|
108
100
|
const out = [];
|
|
@@ -160,7 +152,9 @@ var Emitter = class {
|
|
|
160
152
|
constantIndex = /* @__PURE__ */ new Map();
|
|
161
153
|
functions = [];
|
|
162
154
|
rules = [/* @__PURE__ */ new Map(), /* @__PURE__ */ new Map()];
|
|
163
|
-
refs
|
|
155
|
+
refs;
|
|
156
|
+
/** How many parsers have been inlined (see `countInlined`). */
|
|
157
|
+
inlined = 0;
|
|
164
158
|
closure;
|
|
165
159
|
next = 0;
|
|
166
160
|
constructor(root, kind, resumable = false) {
|
|
@@ -168,24 +162,11 @@ var Emitter = class {
|
|
|
168
162
|
this.kind = kind;
|
|
169
163
|
this.resumable = resumable;
|
|
170
164
|
this.closure = createClosureCompiler(kind, resumable);
|
|
171
|
-
this.countRefs(root);
|
|
165
|
+
this.refs = countRefs(root);
|
|
172
166
|
}
|
|
173
167
|
get fallbacks() {
|
|
174
168
|
return this.closure.fallbacks;
|
|
175
169
|
}
|
|
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
170
|
const(value) {
|
|
190
171
|
let i = this.constantIndex.get(value);
|
|
191
172
|
if (i === void 0) {
|
|
@@ -195,6 +176,21 @@ var Emitter = class {
|
|
|
195
176
|
}
|
|
196
177
|
return `C[${i}]`;
|
|
197
178
|
}
|
|
179
|
+
/** The text of `[start, p)` in `enc`: UTF-8 decodes through the state's ASCII run (see `utf8Text`). */
|
|
180
|
+
text(enc, start) {
|
|
181
|
+
const text = `${this.const(enc.text)}(I,${start},p)`;
|
|
182
|
+
return enc === utf8 ? `(p-${start}>${ShortText}?R.utf8Text($S,${start},p):${text})` : text;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* A count or bound as source text. Every number a description contributes
|
|
186
|
+
* to the generated source is written here, so nothing but a non-negative
|
|
187
|
+
* integer can reach it: a bound is a `number` only in the types, and a
|
|
188
|
+
* string written as given would run as code (#121).
|
|
189
|
+
*/
|
|
190
|
+
num(n) {
|
|
191
|
+
if (!Number.isSafeInteger(n) || n < 0) throw new TypeError("effect-parse: a compiled bound must be a non-negative integer");
|
|
192
|
+
return String(n);
|
|
193
|
+
}
|
|
198
194
|
/** A JavaScript literal for simple values, otherwise a constant. */
|
|
199
195
|
lit(value) {
|
|
200
196
|
if (value === void 0) return "void 0";
|
|
@@ -257,19 +253,9 @@ var Emitter = class {
|
|
|
257
253
|
gen(p, used, out, fail, fn, depth) {
|
|
258
254
|
const node = nodeOf(p);
|
|
259
255
|
if (Predicate.isTagged(node, "Suspend")) return this.call(this.rule(node.resolve(), used), out, fail);
|
|
260
|
-
if (!isLeaf(node) && ((this.refs.get(p) ?? 0) > 1 && !
|
|
256
|
+
if (!isLeaf(node) && ((this.refs.get(p) ?? 0) > 1 && !isSmall(p) || depth > 32)) return this.call(this.rule(p, used), out, fail);
|
|
261
257
|
return this.inline(p, used, out, fail, fn, depth);
|
|
262
258
|
}
|
|
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 || Predicate.isTagged(node, "Suspend") || Predicate.isTagged(node, "Escaped") || Predicate.isTagged(node, "Dispatch")) return false;
|
|
269
|
-
return children(node).every(visit);
|
|
270
|
-
};
|
|
271
|
-
return visit(p);
|
|
272
|
-
}
|
|
273
259
|
/**
|
|
274
260
|
* In a resumable build: token code (which fails by breaking out of `bad`)
|
|
275
261
|
* that read within `lookahead` units of the end of a partial input re-runs
|
|
@@ -316,12 +302,12 @@ var Emitter = class {
|
|
|
316
302
|
return `if(p>=E){${BT}${fail}}${out === null ? "" : `${out}=I[p];`}p++;`;
|
|
317
303
|
}
|
|
318
304
|
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++;`;
|
|
305
|
+
return `if(p>=E||${this.const(compileAny(node.set).forCode.token)}(I[p])===${node.negate === true}){${BT}${fail}}${out === null ? "" : `${out}=I[p];`}p++;`;
|
|
320
306
|
}
|
|
321
307
|
arrayTakeWhile(node, out, fail, fn) {
|
|
322
308
|
const m = this.const(compileAny(node.set).forCode.token);
|
|
323
309
|
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);`);
|
|
310
|
+
return `${st}=p;while(p<E${node.max === Infinity ? "" : `&&p-${st}<${this.num(node.max)}`}&&${m}(I[p])!==${node.negate === true})p++;` + (node.min > 0 ? `if(p-${st}<${this.num(node.min)}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=I.slice(${st},p);`);
|
|
325
311
|
}
|
|
326
312
|
call(name, out, fail) {
|
|
327
313
|
if (out === null) return `if(${name}(p)===F){${fail}}p=P;`;
|
|
@@ -337,6 +323,7 @@ var Emitter = class {
|
|
|
337
323
|
return enc === void 0 ? this.kind !== 2 : kindOfEncoding(enc) === this.kind;
|
|
338
324
|
}
|
|
339
325
|
inline(p, used, out, fail, fn, depth) {
|
|
326
|
+
this.inlined = countInlined(this.inlined);
|
|
340
327
|
const node = nodeOf(p);
|
|
341
328
|
const set = (value) => out === null ? "" : `${out}=${value};`;
|
|
342
329
|
const d = depth + 1;
|
|
@@ -344,7 +331,7 @@ var Emitter = class {
|
|
|
344
331
|
case "Succeed": return set(this.lit(node.value));
|
|
345
332
|
case "Sync": return used ? set(`${this.const(node.evaluate)}()`) : "";
|
|
346
333
|
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.
|
|
334
|
+
case "Eof": return `if(p<E){${BT}${fail}}` + (this.resumable ? `if($S.partial){$S.incomplete(1);${fail}}` : "") + set("void 0");
|
|
348
335
|
case "Location": return set("p");
|
|
349
336
|
case "RestLen": return set("E-p");
|
|
350
337
|
case "Suspend": return this.call(this.rule(node.resolve(), used), out, fail);
|
|
@@ -367,7 +354,7 @@ var Emitter = class {
|
|
|
367
354
|
const code = this.float(node, out, fail, fn, d);
|
|
368
355
|
if (code !== void 0) return code;
|
|
369
356
|
}
|
|
370
|
-
if (node.f === fromEntries && out !== null &&
|
|
357
|
+
if (node.f === fromEntries && out !== null && buildsEntries(node.self)) return this.entries(node.self, out, fail, fn, d);
|
|
371
358
|
const t = this.v(fn);
|
|
372
359
|
return this.gen(node.self, true, t, fail, fn, d) + set(`${this.const(node.f)}(${t})`);
|
|
373
360
|
}
|
|
@@ -383,6 +370,17 @@ var Emitter = class {
|
|
|
383
370
|
const [tag, field] = Predicate.isTagged(node, "TryMap") ? ["Success", "success"] : ["Some", "value"];
|
|
384
371
|
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
372
|
}
|
|
373
|
+
case "FastPath": {
|
|
374
|
+
const st = this.v(fn);
|
|
375
|
+
const t = out ?? this.v(fn);
|
|
376
|
+
const done = this.label();
|
|
377
|
+
return `${st}=p;$S.pos=p;${t}=${this.const(node.fast)}($S);${done}:{if(${t}!==${this.const(Defer)}){p=$S.pos;break ${done}}p=${st};${this.gen(node.self, used, out, fail, fn, d)}}`;
|
|
378
|
+
}
|
|
379
|
+
case "MapOrFail": {
|
|
380
|
+
const t = this.v(fn);
|
|
381
|
+
const r = out ?? this.v(fn);
|
|
382
|
+
return this.gen(node.self, true, t, fail, fn, d) + `${r}=${this.const(node.f)}(${t});if(${r}===F){${BT}${fail}}`;
|
|
383
|
+
}
|
|
386
384
|
case "Filter": {
|
|
387
385
|
const t = out ?? this.v(fn);
|
|
388
386
|
return this.gen(node.self, true, t, fail, fn, d) + `if(!${this.const(node.predicate)}(${t})){${BT}${fail}}`;
|
|
@@ -409,6 +407,12 @@ var Emitter = class {
|
|
|
409
407
|
const extra = Predicate.isTagged(node, "WithSpan") ? `{start:${st},end:p}` : `$S.slice(${st},p)`;
|
|
410
408
|
return `${st}=p;` + this.gen(node.self, true, t, fail, fn, d) + set(`[${t},${extra}]`);
|
|
411
409
|
}
|
|
410
|
+
case "MapSpan": {
|
|
411
|
+
if (!used) return this.gen(node.self, false, null, fail, fn, d);
|
|
412
|
+
const st = this.v(fn);
|
|
413
|
+
const t = this.v(fn);
|
|
414
|
+
return `${st}=p;` + this.gen(node.self, true, t, fail, fn, d) + set(`${this.const(node.f)}(${t},${st},p)`);
|
|
415
|
+
}
|
|
412
416
|
case "Span": {
|
|
413
417
|
const st = this.v(fn);
|
|
414
418
|
return `${st}=p;` + this.gen(node.self, false, null, fail, fn, d) + set(`{start:${st},end:p}`);
|
|
@@ -420,6 +424,7 @@ var Emitter = class {
|
|
|
420
424
|
}
|
|
421
425
|
case "Context":
|
|
422
426
|
case "Expected":
|
|
427
|
+
case "Quiet":
|
|
423
428
|
case "MapError":
|
|
424
429
|
case "OrFail":
|
|
425
430
|
case "Trace":
|
|
@@ -458,6 +463,11 @@ var Emitter = class {
|
|
|
458
463
|
if (node.keys.includes("__proto__")) return code + `${out}={};` + node.keys.map((k, i) => `${out}[${JSON.stringify(k)}]=${vars[i]};`).join("");
|
|
459
464
|
return code + `${out}={${node.keys.map((k, i) => `${JSON.stringify(k)}:${vars[i]}`).join(",")}};`;
|
|
460
465
|
}
|
|
466
|
+
case "SeqWith": {
|
|
467
|
+
if (out === null) return node.parsers.map((q) => this.gen(q, false, null, fail, fn, d)).join("");
|
|
468
|
+
const vars = node.parsers.map(() => this.v(fn));
|
|
469
|
+
return node.parsers.map((q, i) => this.gen(q, true, vars[i], fail, fn, d)).join("") + `${out}=${this.const(node.f)}(${vars.join(",")});`;
|
|
470
|
+
}
|
|
461
471
|
case "ZipWith": {
|
|
462
472
|
if (out === null) return this.gen(node.self, false, null, fail, fn, d) + this.gen(node.that, false, null, fail, fn, d);
|
|
463
473
|
const x = this.v(fn);
|
|
@@ -467,8 +477,13 @@ var Emitter = class {
|
|
|
467
477
|
case "Alt": return this.alt(node, used, out, fail, fn, d);
|
|
468
478
|
case "Dispatch": return this.dispatch(p, node, used, out, fail, fn, d);
|
|
469
479
|
case "Repeat":
|
|
470
|
-
case "Fold": return this.repeat(node, used, out, fail, fn, d);
|
|
480
|
+
case "Fold": return (out === null && Predicate.isTagged(node, "Repeat") ? this.repeatRun(p, node, fail, fn, d) : void 0) ?? this.repeat(node, used, out, fail, fn, d);
|
|
471
481
|
case "Separated": return this.separated(node, used, out, fail, fn, d);
|
|
482
|
+
case "Fixed": {
|
|
483
|
+
if (this.kind !== 1) return this.delegate(p, used, out, fail, fn);
|
|
484
|
+
const read = used ? `${out ?? this.v(fn)}=${this.const(node.read)}(I,p,$S);` : "";
|
|
485
|
+
return `if(E-p>=${this.num(node.size)}){${read}p+=${this.num(node.size)}}else{${this.delegate(p, used, out, fail, fn)}}`;
|
|
486
|
+
}
|
|
472
487
|
default: return this.delegate(p, used, out, fail, fn);
|
|
473
488
|
}
|
|
474
489
|
}
|
|
@@ -552,9 +567,7 @@ var Emitter = class {
|
|
|
552
567
|
const r = out ?? this.v(fn);
|
|
553
568
|
return code + `default:{$S.pos=p;${r}=${q}.step($S);if(${r}===F){${fail}}p=$S.pos;}}`;
|
|
554
569
|
};
|
|
555
|
-
|
|
556
|
-
const peek = Predicate.isTagged(sel, "Peek");
|
|
557
|
-
if (peek) sel = nodeOf(sel.self);
|
|
570
|
+
const { node: sel, peek } = selectorOf(node.selector);
|
|
558
571
|
if (!Predicate.isTagged(sel, "Any") || !this.native(sel.encoding)) return general(true);
|
|
559
572
|
const enc = sel.encoding;
|
|
560
573
|
const r = enc === void 0 ? void 0 : this.reader(enc);
|
|
@@ -577,6 +590,57 @@ var Emitter = class {
|
|
|
577
590
|
code += `case -1:{${BT}${fail}}default:{if(${u}<${size}){${BT}${fail}}${general(false)}}}`;
|
|
578
591
|
return code;
|
|
579
592
|
}
|
|
593
|
+
/**
|
|
594
|
+
* A repetition whose elements are not kept, rewritten to scan a run of a
|
|
595
|
+
* character set in one loop instead of one element at a time (#79):
|
|
596
|
+
*
|
|
597
|
+
* - `repeat(oneOf(S), range)` matches what `takeWhile(S, range)` matches,
|
|
598
|
+
* stopping, failing and reporting `Incomplete` where it does, so it
|
|
599
|
+
* compiles as that `takeWhile`, with the repetition's own step as the
|
|
600
|
+
* fallback near the end of a partial input.
|
|
601
|
+
* - `repeat(alt(oneOf(S), ...rest))` with `min` at most 1 and no `max`
|
|
602
|
+
* matches what `repeat(alt(takeWhile(S, { min: 1 }), ...rest))` matches:
|
|
603
|
+
* a run of `S` is a run of one-character elements, and the counts that
|
|
604
|
+
* differ only matter for other ranges. The first branch is a synthetic
|
|
605
|
+
* `takeWhile` node; outside resumable builds, which never run its step.
|
|
606
|
+
*
|
|
607
|
+
* Returns `undefined` when neither applies.
|
|
608
|
+
*/
|
|
609
|
+
repeatRun(p, node, fail, fn, d) {
|
|
610
|
+
if (this.kind === 2) return void 0;
|
|
611
|
+
const element = nodeOf(node.self);
|
|
612
|
+
if (Predicate.isTagged(element, "OneOf") && this.native(element.encoding)) {
|
|
613
|
+
const { encoding, negate, set } = element;
|
|
614
|
+
return this.leaf(p, {
|
|
615
|
+
_tag: "TakeWhile",
|
|
616
|
+
set,
|
|
617
|
+
negate,
|
|
618
|
+
encoding,
|
|
619
|
+
min: node.min,
|
|
620
|
+
max: node.max
|
|
621
|
+
}, false, null, fail, fn);
|
|
622
|
+
}
|
|
623
|
+
if (this.resumable || node.min > 1 || node.max !== Infinity || !Predicate.isTagged(element, "Alt")) return void 0;
|
|
624
|
+
const [first, ...rest] = element.parsers;
|
|
625
|
+
const head = first === void 0 ? void 0 : nodeOf(first);
|
|
626
|
+
if (head === void 0 || !Predicate.isTagged(head, "OneOf") || !this.native(head.encoding) || Arr.isReadonlyArrayEmpty(rest)) return;
|
|
627
|
+
const run = synthetic({
|
|
628
|
+
_tag: "TakeWhile",
|
|
629
|
+
set: head.set,
|
|
630
|
+
negate: head.negate,
|
|
631
|
+
encoding: head.encoding,
|
|
632
|
+
min: 1,
|
|
633
|
+
max: Infinity
|
|
634
|
+
}, node.self.step);
|
|
635
|
+
const alt = synthetic({
|
|
636
|
+
_tag: "Alt",
|
|
637
|
+
parsers: [run, ...rest]
|
|
638
|
+
}, node.self.step);
|
|
639
|
+
return this.repeat({
|
|
640
|
+
...node,
|
|
641
|
+
self: alt
|
|
642
|
+
}, false, null, fail, fn, d);
|
|
643
|
+
}
|
|
580
644
|
repeat(node, used, out, fail, fn, d, collect) {
|
|
581
645
|
const { max, min } = node;
|
|
582
646
|
const loop = this.label();
|
|
@@ -600,14 +664,15 @@ var Emitter = class {
|
|
|
600
664
|
add = `${acc}.push(${x});`;
|
|
601
665
|
}
|
|
602
666
|
}
|
|
603
|
-
const check =
|
|
604
|
-
const bound = max === Infinity ? "" : `${n}<${max}`;
|
|
667
|
+
const check = `if(p===${st}){$S.mode="Cut";${fail}}`;
|
|
668
|
+
const bound = max === Infinity ? "" : `${n}<${this.num(max)}`;
|
|
605
669
|
const r = this.resumable ? this.resumePoint(fn) : void 0;
|
|
606
|
-
const
|
|
670
|
+
const held = collect?.value ?? acc;
|
|
671
|
+
const save = r === void 0 ? "" : `if($S.mode==="Incomplete"&&$S.resume!==void 0)R.save($S,${r.key},${r.entry},{acc:${held},${collect?.saved ?? ""}count:${n},pos:${st}});`;
|
|
607
672
|
const element = collect === void 0 ? `${this.gen(node.self, tracked, x, `break ${bad};`, fn, d)}${check}${add}` : collect.element(`break ${bad};`, check);
|
|
608
|
-
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};}`;
|
|
673
|
+
const body = `${loop}:for(;${bound};${n}++){${cond === void 0 ? "" : `if(${min > 0 ? `${n}>=${this.num(min)}&&` : ""}!${this.const(cond)}(${acc}))break ${loop};`}${st}=p;${bad}:{${element}continue ${loop};}${save}if($S.mode!=="Backtrack"${min > 0 ? `||${n}<${this.num(min)}` : ""}){${fail}}p=${st};break ${loop};}`;
|
|
609
674
|
if (r === void 0) return `${init}${n}=0;${body}${collect?.finish ?? ""}`;
|
|
610
|
-
return r.wrap(
|
|
675
|
+
return r.wrap(held, `${held}=cp.acc;${collect?.restore ?? ""}${n}=cp.count;p=cp.pos;`, `${init}${n}=0;`, `${body}${collect?.finish ?? ""}`);
|
|
611
676
|
}
|
|
612
677
|
/**
|
|
613
678
|
* In a resumable build, a repetition entered at `entry` may restart from a
|
|
@@ -638,7 +703,8 @@ var Emitter = class {
|
|
|
638
703
|
const loop = this.label();
|
|
639
704
|
const push = keep ? `${acc}.push(${x});` : "";
|
|
640
705
|
const r = this.resumable ? this.resumePoint(fn) : void 0;
|
|
641
|
-
const
|
|
706
|
+
const held = collect?.value ?? acc;
|
|
707
|
+
const save = r === void 0 ? "" : `if($S.mode==="Incomplete"&&$S.resume!==void 0)R.save($S,${r.key},${r.entry},{acc:${held},${collect?.saved ?? ""}count:${n},pos:${st}});`;
|
|
642
708
|
const attempt = (body, success, fatal, checkpoint) => {
|
|
643
709
|
const ok = this.label();
|
|
644
710
|
const bad = this.label();
|
|
@@ -646,11 +712,11 @@ var Emitter = class {
|
|
|
646
712
|
};
|
|
647
713
|
const self = (f) => collect === void 0 ? this.gen(node.self, keep, x, f, fn, d) : collect.element(f, "");
|
|
648
714
|
const sep = (f) => this.gen(node.separator, false, null, f, fn, d);
|
|
649
|
-
const check =
|
|
715
|
+
const check = `if(p===${st}){$S.mode="Cut";${fail}}`;
|
|
650
716
|
const first = `${collect?.init ?? (keep ? `${acc}=[];` : "")}${n}=0;${st}=p;` + attempt(self, `${push}${n}++;`, min > 0 ? "||true" : "", "");
|
|
651
|
-
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) + `}`;
|
|
717
|
+
const rest = `${loop}:while(${max === Infinity ? "true" : `${n}<${this.num(max)}`}){${st}=p;` + attempt(sep, "", `||${n}<${this.num(min)}`, save) + check + attempt(self, `${push}${n}++;continue ${loop};`, `||${n}<${this.num(min)}`, save) + `}`;
|
|
652
718
|
if (r === void 0) return `${done}:{${first}${rest}}${collect?.finish ?? ""}`;
|
|
653
|
-
return r.wrap(
|
|
719
|
+
return r.wrap(held, `${held}=cp.acc;${collect?.restore ?? ""}${n}=cp.count;p=cp.pos;`, "", `${done}:{if(!${r.resumed}){${first}}${rest}}${collect?.finish ?? ""}`);
|
|
654
720
|
}
|
|
655
721
|
/**
|
|
656
722
|
* `map(self, Object.fromEntries)`, where `buildsEntries(self)`: builds the
|
|
@@ -661,35 +727,35 @@ var Emitter = class {
|
|
|
661
727
|
*/
|
|
662
728
|
entries(p, out, fail, fn, d) {
|
|
663
729
|
const node = nodeOf(p);
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
const
|
|
677
|
-
|
|
678
|
-
const t = this.v(fn);
|
|
679
|
-
return this.gen(p, true, t, fail, fn, d) + `${out}=${this.const(fromEntries)}(${t});`;
|
|
680
|
-
}
|
|
681
|
-
const deferred = this.v(fn);
|
|
682
|
-
const key = this.v(fn);
|
|
683
|
-
const value = this.v(fn);
|
|
684
|
-
const collect = {
|
|
685
|
-
init: `${out}={};${deferred}=void 0;`,
|
|
686
|
-
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});`,
|
|
687
|
-
finish: `if(${deferred}!==void 0)R.flushEntries(${out},${deferred});`
|
|
688
|
-
};
|
|
689
|
-
return Predicate.isTagged(node, "Repeat") ? this.repeat(node, true, out, fail, fn, d, collect) : this.separated(node, true, out, fail, fn, d, collect);
|
|
730
|
+
if (Predicate.isTagged(node, "Mode")) {
|
|
731
|
+
const ok = this.label();
|
|
732
|
+
const bad = this.label();
|
|
733
|
+
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}}`;
|
|
734
|
+
}
|
|
735
|
+
if (Predicate.isTagged(node, "Seq")) {
|
|
736
|
+
const i = node.output;
|
|
737
|
+
return node.parsers.map((q, j) => j === i ? this.entries(q, out, fail, fn, d) : this.gen(q, false, null, fail, fn, d)).join("");
|
|
738
|
+
}
|
|
739
|
+
if (Predicate.isTagged(node, "Repeat") || Predicate.isTagged(node, "Separated")) {
|
|
740
|
+
const pair = pairOf(node.self);
|
|
741
|
+
if (pair === void 0) {
|
|
742
|
+
const t = this.v(fn);
|
|
743
|
+
return this.gen(p, true, t, fail, fn, d) + `${out}=${this.const(fromEntries)}(${t});`;
|
|
690
744
|
}
|
|
691
|
-
|
|
745
|
+
const deferred = this.v(fn);
|
|
746
|
+
const key = this.v(fn);
|
|
747
|
+
const value = this.v(fn);
|
|
748
|
+
const collect = {
|
|
749
|
+
init: `${out}={};${deferred}=void 0;`,
|
|
750
|
+
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});`,
|
|
751
|
+
finish: `if(${deferred}!==void 0)R.flushEntries(${out},${deferred});`,
|
|
752
|
+
value: out,
|
|
753
|
+
saved: `def:${deferred},`,
|
|
754
|
+
restore: `${deferred}=cp.def;`
|
|
755
|
+
};
|
|
756
|
+
return Predicate.isTagged(node, "Repeat") ? this.repeat(node, true, out, fail, fn, d, collect) : this.separated(node, true, out, fail, fn, d, collect);
|
|
692
757
|
}
|
|
758
|
+
return this.entries(node.self, out, fail, fn, d);
|
|
693
759
|
}
|
|
694
760
|
/** An expression: is the unit `c`, known to be below `size` (at most `TableSize`), accepted? */
|
|
695
761
|
member(accept, c, size = TableSize) {
|
|
@@ -745,9 +811,10 @@ var Emitter = class {
|
|
|
745
811
|
return this.literalUnits(Predicate.isString(encoded) ? unitsOf(encoded) : Array.from(encoded), false, fail) + set(this.lit(lit));
|
|
746
812
|
}
|
|
747
813
|
const literalKind = Predicate.isString(lit) ? 0 : lit instanceof Uint8Array ? 1 : 2;
|
|
748
|
-
|
|
749
|
-
if (
|
|
750
|
-
|
|
814
|
+
let codes;
|
|
815
|
+
if (Predicate.isString(lit)) codes = kind === 0 ? unitsOf(lit) : Array.from(new TextEncoder().encode(lit));
|
|
816
|
+
else if (kind === 1 && lit instanceof Uint8Array) codes = Array.from(lit);
|
|
817
|
+
else return void 0;
|
|
751
818
|
const len = codes.length;
|
|
752
819
|
const value = !node.caseless && literalKind === kind ? this.lit(lit) : kind === 0 ? `I.slice(p-${len},p)` : `I.subarray(p-${len},p)`;
|
|
753
820
|
return this.literalUnits(codes, node.caseless, fail) + set(value);
|
|
@@ -800,9 +867,9 @@ var Emitter = class {
|
|
|
800
867
|
const loop = this.label();
|
|
801
868
|
const counted = max !== Infinity || min > 1;
|
|
802
869
|
const count = counted ? `${n}++;` : "";
|
|
803
|
-
const bound = max !== Infinity ? `&&${n}<${max}` : "";
|
|
804
|
-
const slice = enc !== void 0 ?
|
|
805
|
-
const finish = (min > 0 ? `if(${counted ? n : `p-${st}`}<${min}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=${slice};`);
|
|
870
|
+
const bound = max !== Infinity ? `&&${n}<${this.num(max)}` : "";
|
|
871
|
+
const slice = enc !== void 0 ? this.text(enc, st) : kind === 0 ? `I.slice(${st},p)` : `I.subarray(${st},p)`;
|
|
872
|
+
const finish = (min > 0 ? `if(${counted ? n : `p-${st}`}<${this.num(min)}){${BT}${fail}}` : "") + (out === null ? "" : `${out}=${slice};`);
|
|
806
873
|
const head = `${st}=p;${counted ? `${n}=0;` : ""}${loop}:while(p<E${bound}){${c}=${this.unit("p")};`;
|
|
807
874
|
const member = this.member(accept, c);
|
|
808
875
|
if (kind === 1 && (enc === void 0 || fastLimit(enc) >= TableSize)) return `${head}if(!(${member}))break;p++;${count}}${finish}`;
|
|
@@ -811,6 +878,8 @@ var Emitter = class {
|
|
|
811
878
|
const guard = r.width === 1 ? "" : `${r.guard("p")}&&`;
|
|
812
879
|
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}`;
|
|
813
880
|
}
|
|
881
|
+
const stops = negate && !counted ? stopChars(cs) : void 0;
|
|
882
|
+
if (stops !== void 0) return this.stopSearch(stops, st, c, finish, fn);
|
|
814
883
|
const fast = 55296;
|
|
815
884
|
const small = TableSize;
|
|
816
885
|
const highTest = (v) => this.memberHigh(cs, negate, v);
|
|
@@ -820,6 +889,21 @@ var Emitter = class {
|
|
|
820
889
|
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}`;
|
|
821
890
|
}
|
|
822
891
|
/**
|
|
892
|
+
* `Token.takeTill` on a string, of one to `MaxStops` characters that are
|
|
893
|
+
* whole code points: the set accepts every other unit, surrogates
|
|
894
|
+
* included, so the run ends at the first stop character. The first
|
|
895
|
+
* `SearchHead` units are tested one at a time, which beats a native
|
|
896
|
+
* search on short runs; a longer run ends at the next occurrence that
|
|
897
|
+
* `nextStop` finds with `indexOf` (#75).
|
|
898
|
+
*/
|
|
899
|
+
stopSearch(stops, st, c, finish, fn) {
|
|
900
|
+
const h = this.v(fn);
|
|
901
|
+
const test = stops.map((u) => `${c}!==${u}`).join("&&");
|
|
902
|
+
const search = stops.length === 1 ? `{p=I.indexOf(${JSON.stringify(String.fromCharCode(stops[0]))},p);if(p<0)p=E}` : `p=R.nextStop(${this.const(new StopCache(stops.map((u) => String.fromCharCode(u))))},$S,p);`;
|
|
903
|
+
const head = stops.length === 1 ? SearchHead : 2 * SearchHead;
|
|
904
|
+
return `${st}=p;${h}=p+${head}<E?p+${head}:E;while(p<${h}&&(${c}=I.charCodeAt(p),${test}))p++;if(p===${h}&&p<E&&(${c}=I.charCodeAt(p),${test}))${search}${finish}`;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
823
907
|
* `escaped`. In a resumable build it keeps the closure compiler's
|
|
824
908
|
* checkpoints: where the next segment starts and, unless raw, the text
|
|
825
909
|
* so far, saved when a segment or an escape runs out of input.
|
|
@@ -843,37 +927,54 @@ var Emitter = class {
|
|
|
843
927
|
const normal = this.gen(node.normal, !raw, x, `break ${bad};`, fn, d);
|
|
844
928
|
const escape = this.gen(node.escape, !raw, x, `${save(b)}${fail}`, fn, d);
|
|
845
929
|
const onNormal = raw ? `if(p===${b}){$S.mode="Cut";${fail}}continue ${loop};` : `if(p!==${b}){${acc}+=${x};continue ${loop}}`;
|
|
846
|
-
const slice = enc !== void 0 ?
|
|
847
|
-
const ctrlTest = rd === void 0 ? `p<E&&${this.unit("p")}===${ctrl}` : `${rd.guard("p")}&&${rd.unit("p")}===${ctrl}`;
|
|
930
|
+
const slice = enc !== void 0 ? this.text(enc, st) : this.kind === 0 ? `I.slice(${st},p)` : `I.subarray(${st},p)`;
|
|
931
|
+
const ctrlTest = rd === void 0 ? `p<E&&${this.unit("p")}===${this.num(ctrl)}` : `${rd.guard("p")}&&${rd.unit("p")}===${this.num(ctrl)}`;
|
|
848
932
|
const stop = r === void 0 ? loop : this.label();
|
|
849
933
|
const loopCode = `${loop}:while(p<E){${b}=p;${okv}=false;${bad}:{${normal}${okv}=true;}if(${okv}){${onNormal}}else{if($S.mode!=="Backtrack"){${save(b)}${fail}}p=${b}}if(${ctrlTest}){p+=${rd?.width ?? 1};${escape}${raw ? "" : `${acc}+=${x};`}}else break ${stop};}`;
|
|
850
|
-
const body = r === void 0 ? loopCode : `${stop}:{${loopCode}if($S.partial){$S.
|
|
934
|
+
const body = r === void 0 ? loopCode : `${stop}:{${loopCode}if($S.partial){$S.incomplete(0);${save("p")}${fail}}}`;
|
|
851
935
|
if (r === void 0) return `${raw ? `${st}=p;` : `${acc}="";`}${body}${raw && out !== null ? `${out}=${slice};` : ""}`;
|
|
852
936
|
if (acc !== null) return r.wrap(acc, `${acc}=cp.out;p=cp.pos;`, `${acc}="";`, body);
|
|
853
937
|
const value = out ?? this.v(fn);
|
|
854
938
|
return r.wrap(value, "p=cp;", "", `${body}${value}=${out === null ? "void 0" : slice};`);
|
|
855
939
|
}
|
|
856
940
|
};
|
|
941
|
+
/**
|
|
942
|
+
* A parser that exists only as a description, for the rewrites of
|
|
943
|
+
* `Emitter.repeatRun`. `step` is never run on the paths they compile (the
|
|
944
|
+
* token code of a native `takeWhile`, and alternatives inline), so it is
|
|
945
|
+
* the step of the repetition's element, which describes the same language
|
|
946
|
+
* when its value is unused.
|
|
947
|
+
*/
|
|
948
|
+
const synthetic = (node, step) => {
|
|
949
|
+
return {
|
|
950
|
+
step,
|
|
951
|
+
name: void 0,
|
|
952
|
+
[NodeId]: node
|
|
953
|
+
};
|
|
954
|
+
};
|
|
857
955
|
/** The UTF-16 code units of a string. */
|
|
858
956
|
const unitsOf = (s) => Array.from({ length: s.length }, (_, i) => s.charCodeAt(i));
|
|
859
957
|
/** Generates the source of a compiled parser, without building it. */
|
|
860
958
|
const generate = (root, kind, resumable = false) => {
|
|
861
959
|
const e = new Emitter(root, kind, resumable);
|
|
862
960
|
const main = e.rule(root, true);
|
|
961
|
+
let closure;
|
|
962
|
+
const short = e.const((state) => (closure ??= createClosureCompiler(kind, resumable).compile(root, true))(state));
|
|
863
963
|
return {
|
|
864
|
-
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}}`,
|
|
964
|
+
source: `"use strict";let $I,$E,$S,P;${e.functions.join("\n")}\nreturn function run(state){if(state.end!==state.input.length)return ${short}(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}catch(e){if(!R.isStackOverflow(e))throw e;return R.tooDeep(state)}finally{$I=sI;$E=sE;$S=sS;P=sP}}`,
|
|
865
965
|
constants: e.constants,
|
|
866
966
|
fallbacks: e.fallbacks
|
|
867
967
|
};
|
|
868
968
|
};
|
|
869
|
-
/**
|
|
969
|
+
/**
|
|
970
|
+
* Compiles a root parser for one input kind with `new Function`. The step
|
|
971
|
+
* is the generated entry, which handles every state and reports call-stack
|
|
972
|
+
* overflows itself.
|
|
973
|
+
*/
|
|
870
974
|
const compileJit = (root, kind, resumable = false) => {
|
|
871
975
|
const { constants, fallbacks, source } = generate(root, kind, resumable);
|
|
872
|
-
const run = globalThis.Function("C", "F", "R", source)(constants, Fail, runtime);
|
|
873
|
-
let closure;
|
|
874
|
-
const step = (state) => state.end === state.input.length ? run(state) : (closure ??= createClosureCompiler(kind, resumable).compile(root, true))(state);
|
|
875
976
|
return {
|
|
876
|
-
step,
|
|
977
|
+
step: globalThis.Function("C", "F", "R", source)(constants, Fail, runtime),
|
|
877
978
|
fallbacks,
|
|
878
979
|
source
|
|
879
980
|
};
|
|
@@ -888,6 +989,7 @@ const backend = { build: (p, kind, resumable) => {
|
|
|
888
989
|
onSuccess: ({ fallbacks, source, step }) => ({
|
|
889
990
|
backend: "jit",
|
|
890
991
|
step,
|
|
992
|
+
guarded: true,
|
|
891
993
|
fallbacks,
|
|
892
994
|
error: void 0,
|
|
893
995
|
source
|
|
@@ -898,6 +1000,6 @@ const backend = { build: (p, kind, resumable) => {
|
|
|
898
1000
|
})
|
|
899
1001
|
});
|
|
900
1002
|
} };
|
|
901
|
-
export { backend };
|
|
1003
|
+
export { backend, jitSupported };
|
|
902
1004
|
|
|
903
1005
|
//# sourceMappingURL=jit.js.map
|