parseman 0.61.6 → 0.61.7
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/dist/analysis/diagnostics.js +109 -29
- package/dist/analysis/diagnostics.js.map +2 -2
- package/dist/cli/index.js +109 -29
- package/dist/cli/index.js.map +2 -2
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts +3 -1
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/compiler/token-capability.js +14 -10
- package/dist/compiler/token-capability.js.map +1 -1
- package/dist/index.js +109 -29
- package/dist/index.js.map +2 -2
- package/dist/plugin/index.js +109 -29
- package/dist/plugin/index.js.map +2 -2
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/hold-gap.d.ts +3 -1
- package/dist/table/hold-gap.d.ts.map +1 -1
- package/dist/table/index.js +109 -29
- package/dist/table/index.js.map +2 -2
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/combinators/expect.ts +3 -2
- package/src/combinators/first-set.ts +14 -7
- package/src/combinators/sequence.ts +1 -1
- package/src/table/assemble.ts +38 -0
- package/src/table/emit-assembly.ts +42 -5
- package/src/table/encode.ts +1 -1
- package/src/table/hold-gap.ts +22 -13
- package/src/version.ts +1 -1
|
@@ -198,8 +198,9 @@ function matchesEmptyBody(p, seen, resolve) {
|
|
|
198
198
|
case "optional":
|
|
199
199
|
case "not":
|
|
200
200
|
case "peek":
|
|
201
|
+
case "expect":
|
|
201
202
|
return true;
|
|
202
|
-
// zero repetitions / absent / lookahead
|
|
203
|
+
// zero repetitions / absent / lookahead / recovered
|
|
203
204
|
// Default `sepBy` is `(item (sep item)*)?` — it MATCHES THE EMPTY STRING.
|
|
204
205
|
// Any `min >= 1` requires that many ITEMS, so it is nullable only when the
|
|
205
206
|
// item is. (Keying this off `min === 1` reported every `{ min: 2 }` list as
|
|
@@ -220,7 +221,6 @@ function matchesEmptyBody(p, seen, resolve) {
|
|
|
220
221
|
case "trivia":
|
|
221
222
|
case "token":
|
|
222
223
|
case "leaf":
|
|
223
|
-
case "expect":
|
|
224
224
|
case "withCtx":
|
|
225
225
|
case "node":
|
|
226
226
|
case "grammar":
|
|
@@ -290,17 +290,17 @@ function sequenceSet(parsers, fs, empties, trivia2, consuming = true) {
|
|
|
290
290
|
function sequenceFirstSet(parsers) {
|
|
291
291
|
return sequenceSet(parsers, (p) => p._meta.firstSet, matchesEmpty, void 0, false);
|
|
292
292
|
}
|
|
293
|
-
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve, activeTrivia, consuming = true) {
|
|
293
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve, activeTrivia, consuming = true, follow = false) {
|
|
294
294
|
if (seen.has(p)) return any();
|
|
295
295
|
seen.add(p);
|
|
296
296
|
try {
|
|
297
|
-
return firstSetBody(p, seen, resolve, activeTrivia, consuming);
|
|
297
|
+
return firstSetBody(p, seen, resolve, activeTrivia, consuming, follow);
|
|
298
298
|
} finally {
|
|
299
299
|
seen.delete(p);
|
|
300
300
|
}
|
|
301
301
|
}
|
|
302
|
-
function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
|
|
303
|
-
const fs = (c) => firstSetOf(c, seen, resolve, activeTrivia, consuming);
|
|
302
|
+
function firstSetBody(p, seen, resolve, activeTrivia, consuming, follow) {
|
|
303
|
+
const fs = (c) => firstSetOf(c, seen, resolve, activeTrivia, consuming, follow);
|
|
304
304
|
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
|
|
305
305
|
const d = p._def;
|
|
306
306
|
switch (d.tag) {
|
|
@@ -321,7 +321,7 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
|
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
323
|
const through = activeTrivia === null && resolve !== void 0;
|
|
324
|
-
return firstSetOf(target, seen, resolve, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming);
|
|
324
|
+
return firstSetOf(target, seen, resolve, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming, follow);
|
|
325
325
|
}
|
|
326
326
|
case "choice": {
|
|
327
327
|
let out = empty();
|
|
@@ -331,6 +331,10 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
|
|
|
331
331
|
case "sequence": {
|
|
332
332
|
return sequenceSet(d.parsers, fs, empties, activeTrivia, consuming);
|
|
333
333
|
}
|
|
334
|
+
// Runs on any character: on one its child can't start, it reports the error. A
|
|
335
|
+
// resync sentinel still stops where the child could start.
|
|
336
|
+
case "expect":
|
|
337
|
+
return follow ? fs(d.parser) : any();
|
|
334
338
|
case "peek": {
|
|
335
339
|
const inner = d.parser;
|
|
336
340
|
return empties(inner) ? any() : fs(inner);
|
|
@@ -344,7 +348,6 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
|
|
|
344
348
|
case "leaf":
|
|
345
349
|
case "node":
|
|
346
350
|
case "sepBy":
|
|
347
|
-
case "expect":
|
|
348
351
|
// A transaction accepts exactly what its inner accepts. Its own `_meta` is
|
|
349
352
|
// the inner's construction-time set, which reads `any` when the inner opens
|
|
350
353
|
// with a rule reference — resolve through it like any other wrapper.
|
|
@@ -352,14 +355,15 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
|
|
|
352
355
|
return fs(d.parser);
|
|
353
356
|
// A token runs its body with trivia cleared (`token.ts`).
|
|
354
357
|
case "token":
|
|
355
|
-
return firstSetOf(d.parser, seen, resolve, activeTrivia === void 0 ? void 0 : null, consuming);
|
|
358
|
+
return firstSetOf(d.parser, seen, resolve, activeTrivia === void 0 ? void 0 : null, consuming, follow);
|
|
356
359
|
case "grammar":
|
|
357
360
|
return firstSetOf(
|
|
358
361
|
d.parser,
|
|
359
362
|
seen,
|
|
360
363
|
resolve,
|
|
361
364
|
d.clearTrivia ? null : d.triviaParser ?? activeTrivia,
|
|
362
|
-
consuming
|
|
365
|
+
consuming,
|
|
366
|
+
follow
|
|
363
367
|
);
|
|
364
368
|
// A run starts with its first line's prefix; a nullable prefix starts with anything.
|
|
365
369
|
case "lines": {
|
|
@@ -2712,7 +2716,8 @@ function derive(c, seen) {
|
|
|
2712
2716
|
function expect(combinator, label2) {
|
|
2713
2717
|
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
2714
2718
|
const meta = {
|
|
2715
|
-
|
|
2719
|
+
// It runs on any character: on one its child can't start, it reports the error.
|
|
2720
|
+
firstSet: any(),
|
|
2716
2721
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
2717
2722
|
isTrivia: false
|
|
2718
2723
|
};
|
|
@@ -4072,7 +4077,7 @@ function regex(pattern, flags = "") {
|
|
|
4072
4077
|
}
|
|
4073
4078
|
|
|
4074
4079
|
// src/version.ts
|
|
4075
|
-
var PARSEMAN_VERSION = "0.61.
|
|
4080
|
+
var PARSEMAN_VERSION = "0.61.7";
|
|
4076
4081
|
|
|
4077
4082
|
// src/table/lex-body.ts
|
|
4078
4083
|
function buildLexBodyRecognizer(spec, constants) {
|
|
@@ -5041,7 +5046,7 @@ function sequence(...parsers) {
|
|
|
5041
5046
|
if (tolerant) {
|
|
5042
5047
|
followSentinels ??= parsers.map((_, i) => firstSetSentinel(
|
|
5043
5048
|
parsers.slice(i + 1).reduce(
|
|
5044
|
-
(set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false)),
|
|
5049
|
+
(set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false, true)),
|
|
5045
5050
|
{ kind: "empty" }
|
|
5046
5051
|
)
|
|
5047
5052
|
));
|
|
@@ -8330,7 +8335,7 @@ var Encoder = class {
|
|
|
8330
8335
|
let fs = { kind: "empty" };
|
|
8331
8336
|
const rr = this.refResolver();
|
|
8332
8337
|
for (let j = i + 1; j < parsers.length; j++) {
|
|
8333
|
-
fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false));
|
|
8338
|
+
fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false, true));
|
|
8334
8339
|
}
|
|
8335
8340
|
return this.charClass(fs);
|
|
8336
8341
|
}
|
|
@@ -10825,17 +10830,17 @@ var WRAPPERS = /* @__PURE__ */ new Set([
|
|
|
10825
10830
|
OP_SCOPE_PLAIN,
|
|
10826
10831
|
OP_FIELD,
|
|
10827
10832
|
OP_LABEL,
|
|
10828
|
-
OP_EXPECT,
|
|
10829
10833
|
OP_WITHCTX,
|
|
10830
10834
|
OP_RULE,
|
|
10831
10835
|
OP_ATTEMPT,
|
|
10832
10836
|
OP_COV,
|
|
10833
10837
|
OP_GAPGATE
|
|
10834
10838
|
]);
|
|
10835
|
-
function rowNullable(code, k, ip, memo) {
|
|
10836
|
-
const
|
|
10839
|
+
function rowNullable(code, k, ip, memo, recovers = true) {
|
|
10840
|
+
const key = recovers ? ip : ~ip;
|
|
10841
|
+
const hit = memo.get(key);
|
|
10837
10842
|
if (hit !== void 0) return hit;
|
|
10838
|
-
memo.set(
|
|
10843
|
+
memo.set(key, true);
|
|
10839
10844
|
const op = code[ip];
|
|
10840
10845
|
const kids = [];
|
|
10841
10846
|
let out = true;
|
|
@@ -10846,20 +10851,20 @@ function rowNullable(code, k, ip, memo) {
|
|
|
10846
10851
|
out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
|
|
10847
10852
|
} else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
|
|
10848
10853
|
childSlots(code, ip, kids);
|
|
10849
|
-
out = kids.every((c) => rowNullable(code, k, c, memo));
|
|
10854
|
+
out = kids.every((c) => rowNullable(code, k, c, memo, recovers));
|
|
10850
10855
|
} else if (op === OP_CHOICE) {
|
|
10851
10856
|
childSlots(code, ip, kids);
|
|
10852
|
-
out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
|
|
10857
|
+
out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo, recovers));
|
|
10853
10858
|
} else if (op === OP_REP || op === OP_REPV) {
|
|
10854
|
-
out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
|
|
10859
|
+
out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo, recovers);
|
|
10855
10860
|
} else if (op === OP_SEED) {
|
|
10856
|
-
out = rowNullable(code, k, code[ip + 1], memo);
|
|
10861
|
+
out = rowNullable(code, k, code[ip + 1], memo, recovers);
|
|
10857
10862
|
} else if (op === OP_CONT) {
|
|
10858
|
-
out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
|
|
10859
|
-
} else if (WRAPPERS.has(op)) {
|
|
10860
|
-
if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
|
|
10863
|
+
out = rowNullable(code, k, code[ip + 1], memo, recovers) && rowNullable(code, k, code[ip + 3], memo, recovers);
|
|
10864
|
+
} else if (WRAPPERS.has(op) || op === OP_EXPECT && !recovers) {
|
|
10865
|
+
if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo, recovers);
|
|
10861
10866
|
}
|
|
10862
|
-
memo.set(
|
|
10867
|
+
memo.set(key, out);
|
|
10863
10868
|
return out;
|
|
10864
10869
|
}
|
|
10865
10870
|
function holdsGap(code, k, base, n, i, memo) {
|
|
@@ -10868,7 +10873,7 @@ function holdsGap(code, k, base, n, i, memo) {
|
|
|
10868
10873
|
if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
|
|
10869
10874
|
const next = code[base + i + 1];
|
|
10870
10875
|
if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
|
|
10871
|
-
return !rowNullable(code, k, next, memo);
|
|
10876
|
+
return !rowNullable(code, k, next, memo, false);
|
|
10872
10877
|
}
|
|
10873
10878
|
|
|
10874
10879
|
// src/table/gap-gate.ts
|
|
@@ -11190,11 +11195,35 @@ ${fast}
|
|
|
11190
11195
|
${scanned}
|
|
11191
11196
|
}`;
|
|
11192
11197
|
}
|
|
11193
|
-
|
|
11198
|
+
var TRIVIA_LOG_LENGTH = "ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)";
|
|
11199
|
+
function emitHoldTerm(callee, dst, t2, l, skip, recovers) {
|
|
11194
11200
|
const fast = `const ${t2}v=${callee}(input,cur,ctx)
|
|
11195
11201
|
if(${t2}v===FAIL)return FAIL
|
|
11196
11202
|
${dst}=${t2}v
|
|
11197
11203
|
cur=EC.e`;
|
|
11204
|
+
if (recovers) {
|
|
11205
|
+
const marked = `let ${t2}c=cur,${t2}s=cur,${t2}tl=0,${t2}stl=0,${t2}lg=0,${t2}slg=0,${t2}rt=0,${t2}srt=0`;
|
|
11206
|
+
if (l.tri === TRI_NONE) return `${marked}
|
|
11207
|
+
${fast}`;
|
|
11208
|
+
const held2 = `${t2}tl=${TRIVIA_LOG_LENGTH}
|
|
11209
|
+
${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
11210
|
+
${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
|
|
11211
|
+
${t2}s=${skip}(input,cur,ctx)
|
|
11212
|
+
${t2}stl=${TRIVIA_LOG_LENGTH}
|
|
11213
|
+
${t2}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
11214
|
+
${t2}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
|
|
11215
|
+
const ${t2}v=${callee}(input,${t2}s,ctx)
|
|
11216
|
+
if(${t2}v===FAIL)return FAIL
|
|
11217
|
+
${dst}=${t2}v
|
|
11218
|
+
cur=${t2}s`;
|
|
11219
|
+
return l.tri !== TRI_UNKNOWN ? `${marked}
|
|
11220
|
+
${held2}` : `${marked}
|
|
11221
|
+
if(ctx.trivia===undefined){
|
|
11222
|
+
${fast}
|
|
11223
|
+
}else{
|
|
11224
|
+
${held2}
|
|
11225
|
+
}`;
|
|
11226
|
+
}
|
|
11198
11227
|
if (l.tri === TRI_NONE) return fast;
|
|
11199
11228
|
const held = `const ${t2}s=${skip}(input,cur,ctx)
|
|
11200
11229
|
const ${t2}v=${callee}(input,${t2}s,ctx)
|
|
@@ -11208,6 +11237,9 @@ ${fast}
|
|
|
11208
11237
|
${held}
|
|
11209
11238
|
}`;
|
|
11210
11239
|
}
|
|
11240
|
+
function emitHeldGapUndo(t2) {
|
|
11241
|
+
return `if(cur===${t2}s&&${t2}s!==${t2}c){rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt);cur=${t2}c}`;
|
|
11242
|
+
}
|
|
11211
11243
|
function leadSkip(hasTrivia, leadTrivia, skip) {
|
|
11212
11244
|
if (hasTrivia === "false") return "{}";
|
|
11213
11245
|
const call = `itemStart=${skip}(input,itemStart,ctx)`;
|
|
@@ -12216,6 +12248,7 @@ return v
|
|
|
12216
12248
|
}
|
|
12217
12249
|
parts.push("let cur=EC.e");
|
|
12218
12250
|
const names = ["v0"];
|
|
12251
|
+
let heldUndo;
|
|
12219
12252
|
for (let i = 1; i < n; i++) {
|
|
12220
12253
|
const vn = `v${i}`;
|
|
12221
12254
|
parts.push(`let ${vn}`);
|
|
@@ -12232,7 +12265,16 @@ return v
|
|
|
12232
12265
|
);
|
|
12233
12266
|
} else {
|
|
12234
12267
|
const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
|
|
12235
|
-
|
|
12268
|
+
if (holdsGap(code, k, base, n, i, nullable2)) {
|
|
12269
|
+
const t3 = tmp();
|
|
12270
|
+
const recovers = rowNullable(code, k, code[base + i + 1], nullable2);
|
|
12271
|
+
parts.push(emitHoldTerm(callee, vn, t3, L, skipFor(L), recovers));
|
|
12272
|
+
heldUndo = recovers ? t3 : void 0;
|
|
12273
|
+
} else {
|
|
12274
|
+
parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
|
|
12275
|
+
if (heldUndo !== void 0) parts.push(emitHeldGapUndo(heldUndo));
|
|
12276
|
+
heldUndo = void 0;
|
|
12277
|
+
}
|
|
12236
12278
|
}
|
|
12237
12279
|
names.push(vn);
|
|
12238
12280
|
}
|
|
@@ -15889,8 +15931,46 @@ function assemble(t2, prog, cfg) {
|
|
|
15889
15931
|
}
|
|
15890
15932
|
if (hasAdj) {
|
|
15891
15933
|
const first2 = linkFirst();
|
|
15934
|
+
let heldFrom = 0, heldTl = 0, heldScanTl = 0, heldLog = 0, heldScanLog = 0, heldRoot = 0, heldScanRoot = 0;
|
|
15892
15935
|
const runnerAt = (i) => {
|
|
15893
15936
|
const kidIp = code[base + i];
|
|
15937
|
+
if (i > 1 && holdsGap(code, k, base, n, i - 1, NULLABLE) && rowNullable(code, k, kidIp, NULLABLE)) {
|
|
15938
|
+
const kid = link(kidIp);
|
|
15939
|
+
return (input, cur, ctx) => {
|
|
15940
|
+
const from = heldFrom, tl = heldTl, scanTl = heldScanTl, log = heldLog;
|
|
15941
|
+
const scanLog = heldScanLog, root = heldRoot, scanRoot = heldScanRoot;
|
|
15942
|
+
const next = step(kid, input, cur, ctx);
|
|
15943
|
+
if (next !== cur || from === cur) return next;
|
|
15944
|
+
rollbackScannedTriviaAt(ctx, tl, scanTl, log, scanLog, root, scanRoot);
|
|
15945
|
+
return from;
|
|
15946
|
+
};
|
|
15947
|
+
}
|
|
15948
|
+
if (holdsGap(code, k, base, n, i, NULLABLE) && rowNullable(code, k, code[base + i + 1], NULLABLE)) {
|
|
15949
|
+
const kid = link(kidIp);
|
|
15950
|
+
return (input, cur, ctx) => {
|
|
15951
|
+
if (ctx.trivia === void 0) {
|
|
15952
|
+
const v2 = kid(input, cur, ctx);
|
|
15953
|
+
if (v2 === FAIL) return -1;
|
|
15954
|
+
TERMV = v2;
|
|
15955
|
+
heldFrom = cur;
|
|
15956
|
+
return EC.e;
|
|
15957
|
+
}
|
|
15958
|
+
const tl = cstTlLen(ctx), log = ctx._triviaLog?.length ?? 0, root = ctx._rootTriviaLog?.length ?? 0;
|
|
15959
|
+
const scanEnd = skipTrivia(input, cur, ctx);
|
|
15960
|
+
const scanTl = cstTlLen(ctx), scanLog = ctx._triviaLog?.length ?? 0, scanRoot = ctx._rootTriviaLog?.length ?? 0;
|
|
15961
|
+
const v = kid(input, scanEnd, ctx);
|
|
15962
|
+
if (v === FAIL) return -1;
|
|
15963
|
+
TERMV = v;
|
|
15964
|
+
heldFrom = cur;
|
|
15965
|
+
heldTl = tl;
|
|
15966
|
+
heldScanTl = scanTl;
|
|
15967
|
+
heldLog = log;
|
|
15968
|
+
heldScanLog = scanLog;
|
|
15969
|
+
heldRoot = root;
|
|
15970
|
+
heldScanRoot = scanRoot;
|
|
15971
|
+
return scanEnd;
|
|
15972
|
+
};
|
|
15973
|
+
}
|
|
15894
15974
|
if (holdsGap(code, k, base, n, i, NULLABLE)) {
|
|
15895
15975
|
const kid = link(kidIp);
|
|
15896
15976
|
return (input, cur, ctx) => {
|