parseman 0.59.2 → 0.60.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/dist/analysis/commitment.d.ts +1 -1
- package/dist/analysis/diagnostics.js +877 -191
- package/dist/analysis/diagnostics.js.map +3 -3
- package/dist/cli/index.js +877 -191
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/completions.d.ts +3 -3
- package/dist/combinators/completions.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +13 -1
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts +35 -2
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/gate.d.ts +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/trivia-boundary.d.ts +11 -0
- package/dist/combinators/trivia-boundary.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +1 -1
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/compile-linkable-table.d.ts +2 -3
- package/dist/compiler/compile-linkable-table.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/token-alphabet.d.ts +2 -0
- package/dist/compiler/token-alphabet.d.ts.map +1 -1
- package/dist/compiler/token-capability.js +65 -53
- package/dist/compiler/token-capability.js.map +2 -2
- package/dist/cst/host-mode.d.ts +1 -1
- package/dist/cst/root-trivia-scope.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +897 -200
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.d.ts +1 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/entry-supercompiler.d.ts.map +1 -1
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +3 -7
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +904 -202
- package/dist/plugin/index.js.map +3 -3
- package/dist/regex/first-set.d.ts +19 -0
- package/dist/regex/first-set.d.ts.map +1 -1
- package/dist/spec/index.js.map +1 -1
- package/dist/table/assemble.d.ts +16 -3
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/child-slots.d.ts.map +1 -1
- package/dist/table/compile-rule-map.d.ts +3 -2
- package/dist/table/compile-rule-map.d.ts.map +1 -1
- package/dist/table/compile.d.ts +2 -2
- package/dist/table/emit-assembly.d.ts +8 -2
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/emit.d.ts +8 -8
- package/dist/table/emit.d.ts.map +1 -1
- package/dist/table/encode.d.ts +6 -7
- package/dist/table/encode.d.ts.map +1 -1
- package/dist/table/exec.d.ts.map +1 -1
- package/dist/table/factor-choice.d.ts +27 -0
- package/dist/table/factor-choice.d.ts.map +1 -1
- package/dist/table/gap-gate.d.ts +11 -0
- package/dist/table/gap-gate.d.ts.map +1 -0
- package/dist/table/index.js +927 -202
- package/dist/table/index.js.map +3 -3
- package/dist/table/lex-program.d.ts.map +1 -1
- package/dist/table/ops.d.ts +48 -20
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/table/program.d.ts +13 -8
- package/dist/table/program.d.ts.map +1 -1
- package/dist/types.d.ts +17 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +6 -6
- package/package.json +1 -1
- package/src/analysis/commitment.ts +1 -1
- package/src/analysis/duplication.ts +1 -1
- package/src/analysis/terminal.ts +1 -1
- package/src/combinators/attempt.ts +1 -1
- package/src/combinators/choice.ts +1 -1
- package/src/combinators/completions.ts +3 -3
- package/src/combinators/dispatch.ts +30 -6
- package/src/combinators/first-set.ts +55 -12
- package/src/combinators/gate.ts +1 -1
- package/src/combinators/node.ts +1 -1
- package/src/combinators/regex.ts +9 -4
- package/src/combinators/repeat.ts +6 -6
- package/src/combinators/sequence.ts +1 -1
- package/src/combinators/trivia-boundary.ts +18 -0
- package/src/combinators/trivia-skip.ts +1 -1
- package/src/compiler/compile-linkable-table.ts +2 -3
- package/src/compiler/degradation.ts +2 -2
- package/src/compiler/ir-serialize.ts +1 -1
- package/src/compiler/linker.ts +5 -3
- package/src/compiler/token-alphabet.ts +3 -1
- package/src/coverage.ts +1 -1
- package/src/cst/capture-buffer.ts +2 -2
- package/src/cst/host-mode.ts +1 -1
- package/src/cst/root-trivia-scope.ts +1 -1
- package/src/index.ts +1 -1
- package/src/language-service/index.ts +1 -1
- package/src/plugin/entry-supercompiler.ts +2 -1
- package/src/plugin/evaluator.ts +8 -3
- package/src/plugin/index.ts +11 -16
- package/src/regex/first-set.ts +37 -3
- package/src/table/assemble.ts +180 -35
- package/src/table/child-slots.ts +8 -3
- package/src/table/compile-rule-map.ts +10 -6
- package/src/table/compile.ts +3 -3
- package/src/table/emit-assembly.ts +186 -35
- package/src/table/emit.ts +19 -18
- package/src/table/encode.ts +482 -88
- package/src/table/exec.ts +42 -18
- package/src/table/factor-choice.ts +62 -0
- package/src/table/fail-clean.ts +2 -2
- package/src/table/gap-gate.ts +55 -0
- package/src/table/hold-gap.ts +2 -2
- package/src/table/lex-program.ts +15 -6
- package/src/table/ops.ts +51 -20
- package/src/table/program.ts +14 -9
- package/src/table/select-hot.ts +7 -2
- package/src/table/stamp.ts +1 -1
- package/src/types.ts +13 -6
- package/src/version.ts +6 -6
package/src/table/assemble.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This is ledger row G5 as stated: *"build the grammar reference at run start,
|
|
5
5
|
* making the swaps on rules / sub-rules (leaves) at that point, then run with NO
|
|
6
6
|
* logic branching for that option input"*. `exec.ts` builds the same table and
|
|
7
|
-
* then interprets it: one `switch (code[ip])` over 29
|
|
7
|
+
* then interprets it: one `switch (code[ip])` over every opcode (29 then), executed ONCE PER
|
|
8
8
|
* ROW — 497,360 rows for `benchmark.less` (`bench/jess/g5-rows.ts`) — each
|
|
9
9
|
* re-reading its opcode and re-decoding its operands from the `Int32Array`, and
|
|
10
10
|
* re-testing the same per-parse options. That is the per-node branching the
|
|
@@ -73,10 +73,11 @@ import { skipDeferredTrivia, triviaLeadTable } from './trivia-gap.ts'
|
|
|
73
73
|
import { asciiFoldKey } from '../combinators/dispatch.ts'
|
|
74
74
|
import { projectChild, unwrapChild } from '../combinators/node.ts'
|
|
75
75
|
import { cstOutputHost } from '../compiler/build-arity.ts'
|
|
76
|
+
import { PARSEMAN_VERSION } from '../version.ts'
|
|
76
77
|
import { consumeTrivia } from '../combinators/trivia-skip.ts'
|
|
77
78
|
import {
|
|
78
|
-
advanceTrivia,
|
|
79
|
-
|
|
79
|
+
advanceTrivia, needsDeferredTriviaCommit, rollbackScannedTriviaAt, rollbackTriviaAt,
|
|
80
|
+
skipTriviaScanned, type FastTriviaScanner,
|
|
80
81
|
} from '../combinators/trivia-skip.ts'
|
|
81
82
|
import {
|
|
82
83
|
cstCaptureActive, cstLeavesLen, cstTlLen,
|
|
@@ -90,8 +91,8 @@ import {
|
|
|
90
91
|
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
91
92
|
OP_LIVE,
|
|
92
93
|
OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD, OP_ATTEMPT, OP_LABEL,
|
|
93
|
-
OP_COV,
|
|
94
|
-
OP_ADJ, OP_GREEDY, OP_REJECT, OP_ARMGATE, OP_RGATE,
|
|
94
|
+
OP_COV, OP_GAPGATE, OP_STRICT,
|
|
95
|
+
OP_ADJ, OP_GREEDY, OP_REJECT, OP_ARMGATE, OP_RGATE, OP_RGATE2,
|
|
95
96
|
OP_LEX_BODY, OP_LEX_PROGRAM,
|
|
96
97
|
} from './ops.ts'
|
|
97
98
|
import { adjacencyHolds, adjacencyMisuse } from '../combinators/adjacency.ts'
|
|
@@ -110,13 +111,13 @@ import {
|
|
|
110
111
|
} from './emit-assembly.ts'
|
|
111
112
|
import { collapseEmpty, lead, rawEntry, spanLines } from './run-support.ts'
|
|
112
113
|
import { holdsGap, rowNullable } from './hold-gap.ts'
|
|
114
|
+
import { gapRows, newGapSlot } from './gap-gate.ts'
|
|
113
115
|
import { failCleanAnalysis } from './fail-clean.ts'
|
|
114
116
|
/**
|
|
115
117
|
* THE COMPLETIONS PROBE, at the terminal fail sites and nowhere else.
|
|
116
118
|
*
|
|
117
|
-
* `failAt` (combinators/probe.ts) is called
|
|
118
|
-
*
|
|
119
|
-
* mirror (`probeUpdate`) at the same leaf-fail sites. The table recorded
|
|
119
|
+
* `failAt` (combinators/probe.ts) is called at the interpreter's terminal fail
|
|
120
|
+
* sites — `literal.ts`, `regex.ts`, `keywords.ts`, `lines.ts`. The table recorded
|
|
120
121
|
* NOTHING, so `completionsAt` on a table artifact saw only the top-level
|
|
121
122
|
* failure: a swallowed item failure inside a `sepBy` (`'{'` at offset 1 in a
|
|
122
123
|
* `{ decl; }` grammar) never reached the probe and the item's opener vanished
|
|
@@ -413,6 +414,28 @@ export type Assembly = {
|
|
|
413
414
|
* ONE walk. Each site is lowered at most once and memoised by its code offset,
|
|
414
415
|
* so a subtree shared by two parents is one piece with two references to it.
|
|
415
416
|
*/
|
|
417
|
+
/**
|
|
418
|
+
* A printed factory takes its helpers BY POSITION (`EMITTED_PARAMS`), so one printed
|
|
419
|
+
* against a different helper list would bind the wrong function to a name and run
|
|
420
|
+
* wrong rather than fail. A factory printed by 0.59.x guards only against FEWER
|
|
421
|
+
* helpers, and one printed before 0.59.0 has no guard at all. So the runtime checks
|
|
422
|
+
* too, before calling it: the assembly's printed `arity` must be exactly the list it
|
|
423
|
+
* passes. It reads that printed number, never `factory.length`, which a minifier that
|
|
424
|
+
* drops unused trailing parameters lowers on a valid artifact. An assembly printed
|
|
425
|
+
* before 0.60.0 carries no `arity` and is refused. A factory this version prints also
|
|
426
|
+
* checks the count it is called with (`FACTORY_ARITY_GUARD`, `emit.ts`).
|
|
427
|
+
*/
|
|
428
|
+
export function assertFactoryArity(pre: { readonly arity?: number }): void {
|
|
429
|
+
if (pre.arity === EMITTED_PARAMS.length) return
|
|
430
|
+
const printed = pre.arity === undefined
|
|
431
|
+
? 'carries no helper count, so it was printed before parseman 0.60.0'
|
|
432
|
+
: `takes ${pre.arity} helpers, but parseman ${PARSEMAN_VERSION} passes ${EMITTED_PARAMS.length}: it was printed by an older or newer parseman`
|
|
433
|
+
throw new Error(
|
|
434
|
+
`parseman: this parser's printed assembly ${printed}. Reprint the parser with `
|
|
435
|
+
+ `parseman ${PARSEMAN_VERSION}, or run it on the parseman version that printed it.`,
|
|
436
|
+
)
|
|
437
|
+
}
|
|
438
|
+
|
|
416
439
|
export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Assembly {
|
|
417
440
|
const { code, k, fns, cc, fx, disp, dsp, trivia, triviaLabelled } = t
|
|
418
441
|
// The leaf swap is only legal when line tracking is off, and that is a property
|
|
@@ -438,7 +461,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
438
461
|
* graph with no recovery in it anywhere.
|
|
439
462
|
*
|
|
440
463
|
* Dormancy is unchanged for the OTHER two engines: the source lowering
|
|
441
|
-
* (
|
|
464
|
+
* (removed in 0.47.0) and the interpreter (`repeat.ts:163`) still gate on
|
|
442
465
|
* `ctx._tolerant` at runtime, and the recovery pieces below keep their own
|
|
443
466
|
* `_tolerant === true` failure-path gates so `exec.ts` stays the identity
|
|
444
467
|
* reference.
|
|
@@ -503,6 +526,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
503
526
|
}
|
|
504
527
|
|
|
505
528
|
const labelExtraIps = assemblyExtraIps(prog)
|
|
529
|
+
// The regex rows an optional repeat hands a scanned gap to (`gap-gate.ts`),
|
|
530
|
+
// and the one slot it hands it through, shared with the emitted pieces.
|
|
531
|
+
const GAP_ROWS = gapRows(code, [...Object.values(prog.rules), ...labelExtraIps])
|
|
532
|
+
const GAP = newGapSlot()
|
|
506
533
|
const closureLabels = computeSiteLabels(
|
|
507
534
|
code, [...Object.values(prog.rules), ...labelExtraIps], hostCst,
|
|
508
535
|
)
|
|
@@ -773,6 +800,32 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
773
800
|
}
|
|
774
801
|
}
|
|
775
802
|
|
|
803
|
+
/**
|
|
804
|
+
* A regex row a repeat may hand a scanned gap to (`gap-gate.ts`): the end comes
|
|
805
|
+
* from the slot when the slot is this row's, at this position, in this input,
|
|
806
|
+
* and from the regex otherwise. Everything after the end is the row's own.
|
|
807
|
+
*/
|
|
808
|
+
function gapRegexPiece(row: number, re: RegExp, xf: string[], track: boolean): Piece {
|
|
809
|
+
return (input, pos, ctx) => {
|
|
810
|
+
let e: number
|
|
811
|
+
if (GAP.row === row && GAP.at === pos && GAP.input === input) e = GAP.end
|
|
812
|
+
else {
|
|
813
|
+
re.lastIndex = pos
|
|
814
|
+
e = re.test(input) ? re.lastIndex : -1
|
|
815
|
+
}
|
|
816
|
+
if (e >= 0) {
|
|
817
|
+
const v = input.slice(pos, e)
|
|
818
|
+
if (cstCaptureActive(ctx)) pushLeaf(ctx, v, pos, e)
|
|
819
|
+
if (track) trackLinesInto(ctx, input, e)
|
|
820
|
+
EC.e = e
|
|
821
|
+
return v
|
|
822
|
+
}
|
|
823
|
+
ctx._fe = pos; ctx._fx = xf
|
|
824
|
+
if (ctx._probe !== undefined) failAt(ctx, xf, pos)
|
|
825
|
+
return FAIL
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
776
829
|
/**
|
|
777
830
|
* A collapse over one node is that node — `run-support.ts` `collapseEmpty` has
|
|
778
831
|
* the contract, and the one case the node's value cannot stand for itself.
|
|
@@ -1354,7 +1407,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1354
1407
|
}
|
|
1355
1408
|
}
|
|
1356
1409
|
|
|
1357
|
-
function dispatchBranch(child: Piece, usesRouted: boolean): DispatchBranch {
|
|
1410
|
+
function dispatchBranch(child: Piece, usesRouted: boolean, commits = true): DispatchBranch {
|
|
1358
1411
|
if (!usesRouted) {
|
|
1359
1412
|
// The arm runs after the selector's match, so it marks where it starts.
|
|
1360
1413
|
return (input, _pos, selEnd, key, ctx) => {
|
|
@@ -1369,7 +1422,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1369
1422
|
const v = child(input, selEnd, ctx)
|
|
1370
1423
|
if (v === FAIL) {
|
|
1371
1424
|
if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
1372
|
-
ctx._fc = true
|
|
1425
|
+
if (commits) ctx._fc = true
|
|
1373
1426
|
return FAIL
|
|
1374
1427
|
}
|
|
1375
1428
|
return [key, v]
|
|
@@ -1389,7 +1442,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1389
1442
|
}
|
|
1390
1443
|
if (v === FAIL) {
|
|
1391
1444
|
if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
1392
|
-
ctx._fc = true
|
|
1445
|
+
if (commits) ctx._fc = true
|
|
1393
1446
|
return FAIL
|
|
1394
1447
|
}
|
|
1395
1448
|
return [key, v]
|
|
@@ -1663,6 +1716,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1663
1716
|
case OP_RX: {
|
|
1664
1717
|
const re = k[code[ip + 1]!] as RegExp
|
|
1665
1718
|
const xf = fx[code[ip + 2]!] as string[]
|
|
1719
|
+
if (GAP_ROWS.has(ip)) return gapRegexPiece(ip, re, xf, false)
|
|
1666
1720
|
const shared = rawScalarSpecs.has(code[ip + 1]!) ? scalarFor(ip) : undefined
|
|
1667
1721
|
if (shared !== undefined) {
|
|
1668
1722
|
return (input, pos, ctx) => {
|
|
@@ -1701,6 +1755,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1701
1755
|
case OP_RX_TRACK: {
|
|
1702
1756
|
const re = k[code[ip + 1]!] as RegExp
|
|
1703
1757
|
const xf = fx[code[ip + 2]!] as string[]
|
|
1758
|
+
if (GAP_ROWS.has(ip)) return gapRegexPiece(ip, re, xf, true)
|
|
1704
1759
|
return (input, pos, ctx) => {
|
|
1705
1760
|
re.lastIndex = pos
|
|
1706
1761
|
if (re.test(input)) {
|
|
@@ -1878,6 +1933,14 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1878
1933
|
}
|
|
1879
1934
|
}
|
|
1880
1935
|
|
|
1936
|
+
// Transparent: only the repeat holding it reads its operands.
|
|
1937
|
+
case OP_GAPGATE:
|
|
1938
|
+
return link(code[ip + 1]!)
|
|
1939
|
+
|
|
1940
|
+
// One encoding per assembly: strict, or the construct as written.
|
|
1941
|
+
case OP_STRICT:
|
|
1942
|
+
return link(code[cfg.tolerant || cfg.probe ? ip + 2 : ip + 1]!)
|
|
1943
|
+
|
|
1881
1944
|
case OP_RULE:
|
|
1882
1945
|
// Pure indirection in the tape; in the assembled graph the parent simply
|
|
1883
1946
|
// holds the target's piece. The trampoline row disappears entirely — this
|
|
@@ -1914,8 +1977,8 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1914
1977
|
const expectSpan = (ctx: ParseContext, pos: number) =>
|
|
1915
1978
|
prog.lines === 1 ? spanLines(ctx, pos, pos) : new PlainSpan(pos, pos)
|
|
1916
1979
|
// TOLERANT `expect()` EMBEDS ITS ERROR IN THE TREE, not only in the flat
|
|
1917
|
-
// `_errors` side-channel (`combinators/expect.ts:150`, and
|
|
1918
|
-
// `_ctx._rec.capture`
|
|
1980
|
+
// `_errors` side-channel (`combinators/expect.ts:150`, and the source
|
|
1981
|
+
// lowering's `_ctx._rec.capture`) — so a tree walk finds every
|
|
1919
1982
|
// diagnostic and the node survives incremental subtree reuse. The table
|
|
1920
1983
|
// pushed to `_errors` and stopped, so a tolerant CST parse was missing the
|
|
1921
1984
|
// `parseError` child the other two engines both produce.
|
|
@@ -2536,7 +2599,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2536
2599
|
*
|
|
2537
2600
|
* The restore is `sequence()`'s `finally` (combinators/sequence.ts:105).
|
|
2538
2601
|
* Codegen does not restore and compensates by having every list capture
|
|
2539
|
-
* `_sync` at ENTRY
|
|
2602
|
+
* `_sync` at ENTRY; the table captures at entry too, so
|
|
2540
2603
|
* this is unobservable either way — it is here because leaving a stale
|
|
2541
2604
|
* sentinel published is the kind of state a later reader will trust.
|
|
2542
2605
|
*/
|
|
@@ -2950,7 +3013,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2950
3013
|
// `arms[]` merely to rediscover the same two or three children at
|
|
2951
3014
|
// every dispatch. The classifier remains table data; only its result
|
|
2952
3015
|
// is turned into a direct captured call.
|
|
2953
|
-
if (n === 2) {
|
|
3016
|
+
if (n === 2 && !cfg.probe) {
|
|
2954
3017
|
const a0 = link(code[base]!), a1 = link(code[base + 1]!)
|
|
2955
3018
|
return (input, pos, ctx) => {
|
|
2956
3019
|
const c = lead(input, pos)
|
|
@@ -2975,7 +3038,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2975
3038
|
return FAIL
|
|
2976
3039
|
}
|
|
2977
3040
|
}
|
|
2978
|
-
if (n === 3) {
|
|
3041
|
+
if (n === 3 && !cfg.probe) {
|
|
2979
3042
|
const a0 = link(code[base]!), a1 = link(code[base + 1]!), a2 = link(code[base + 2]!)
|
|
2980
3043
|
return (input, pos, ctx) => {
|
|
2981
3044
|
const c = lead(input, pos)
|
|
@@ -3008,6 +3071,9 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3008
3071
|
)
|
|
3009
3072
|
}
|
|
3010
3073
|
const selected = bindExclusive(0)
|
|
3074
|
+
// Under a completions probe the interpreter runs every arm on a miss
|
|
3075
|
+
// (`choice.ts`), so each opener reaches the probe.
|
|
3076
|
+
const probeArms = cfg.probe ? Array.from({ length: n }, (_, i) => link(code[base + i]!)) : undefined
|
|
3011
3077
|
// THERE ARE NO OPEN ARMS HERE, and the piece is written to say so. An
|
|
3012
3078
|
// ungated arm is one whose class is −1, and `resolveDispatch` clears
|
|
3013
3079
|
// `exclusive` for exactly those arms (program.ts) — so `table.open` is
|
|
@@ -3039,6 +3105,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3039
3105
|
// THE UNION IS REPORTED ONLY ON A DISPATCH MISS, where the interpreter's
|
|
3040
3106
|
// `parsers.flatMap` over non-nullable, char-excluded arms yields exactly
|
|
3041
3107
|
// each arm's own opener — this set, without running the arms.
|
|
3108
|
+
if (arm < 0 && probeArms !== undefined) for (const a of probeArms) a(input, pos, ctx)
|
|
3042
3109
|
ctx._fe = pos; ctx._fx = choiceFx
|
|
3043
3110
|
return FAIL
|
|
3044
3111
|
}
|
|
@@ -3046,8 +3113,9 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3046
3113
|
|
|
3047
3114
|
// THE PER-ARM GATE. Arms in source order, each skipped when its own class
|
|
3048
3115
|
// excludes the char at `pos`. `null` means nullable or unmappable, and
|
|
3049
|
-
// those arms are always entered.
|
|
3050
|
-
|
|
3116
|
+
// those arms are always entered. A probe assembly enters every arm, as
|
|
3117
|
+
// the interpreter's `firstMatch` does, so each opener reaches `failAt`.
|
|
3118
|
+
const armCls = cfg.probe ? table.armCls.map(() => null) : table.armCls
|
|
3051
3119
|
if (n === 2 || n === 3) {
|
|
3052
3120
|
const a0 = link(code[base]!), a1 = link(code[base + 1]!)
|
|
3053
3121
|
const a2 = n === 3 ? link(code[base + 2]!) : undefined
|
|
@@ -3355,6 +3423,43 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3355
3423
|
}
|
|
3356
3424
|
}
|
|
3357
3425
|
|
|
3426
|
+
case OP_RGATE2: {
|
|
3427
|
+
const cls = cc[code[ip + 1]!]!
|
|
3428
|
+
const xf = fx[code[ip + 3]!] as string[]
|
|
3429
|
+
const first = cc[code[ip + 4]!]!
|
|
3430
|
+
const second = cc[code[ip + 5]!]!
|
|
3431
|
+
const child = link(code[ip + 2]!)
|
|
3432
|
+
if (cfg.tolerant || cfg.probe) return child
|
|
3433
|
+
// ASCII-only classes are read as code units against their tables.
|
|
3434
|
+
if (cls.hi.length === 0 && first.hi.length === 0 && second.hi.length === 0) {
|
|
3435
|
+
const a0 = cls.ascii, a1 = first.ascii, a2 = second.ascii
|
|
3436
|
+
return (input, pos, ctx) => {
|
|
3437
|
+
const item = ctx._routed
|
|
3438
|
+
if (item !== undefined && item.span.start === pos) {
|
|
3439
|
+
const e = item.span.end
|
|
3440
|
+
const c = input.charCodeAt(e)
|
|
3441
|
+
if (a0[c] !== 1 || (a1[c] === 1 && a2[input.charCodeAt(e + 1)] !== 1)) {
|
|
3442
|
+
ctx._fe = e; ctx._fx = xf
|
|
3443
|
+
return FAIL
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
return child(input, pos, ctx)
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
return (input, pos, ctx) => {
|
|
3450
|
+
const item = ctx._routed
|
|
3451
|
+
if (item !== undefined && item.span.start === pos) {
|
|
3452
|
+
const e = item.span.end
|
|
3453
|
+
const c = lead(input, e)
|
|
3454
|
+
if (!classHas(cls, c) || (classHas(first, c) && !classHas(second, lead(input, e + 1)))) {
|
|
3455
|
+
ctx._fe = e; ctx._fx = xf
|
|
3456
|
+
return FAIL
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
return child(input, pos, ctx)
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3358
3463
|
case OP_ARMGATE: {
|
|
3359
3464
|
// Predicate, arm and expected set all bound HERE — the body reads no
|
|
3360
3465
|
// opcode, decodes no operand and tests no setting.
|
|
@@ -3451,6 +3556,19 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3451
3556
|
// `many()` — the min-0, separator-less repeat — is the only shape that runs
|
|
3452
3557
|
// its FIRST item through `repItem` and so skips leading trivia. The shape
|
|
3453
3558
|
// identifies itself, and it is table data, so it is decided here.
|
|
3559
|
+
// A separated list's ip+8 (flag bit 8) is its separator's first set where the encoder
|
|
3560
|
+
// found the test cheaper than entering it (`Encoder.sepGate`). Where the
|
|
3561
|
+
// separator cannot match empty and reads no pre-scan cursor, a lead
|
|
3562
|
+
// outside it stops the list at the separator, exactly as the strict
|
|
3563
|
+
// optional item stops at its own class above.
|
|
3564
|
+
const sepClassIndex = sepIp >= 0 && !sepLeads && (flags & 8) !== 0 ? code[ip + 8]! : -1
|
|
3565
|
+
const sepClass = !REC && sepClassIndex >= 0 && !rowNullable(code, k, sepIp, NULLABLE) ? cc[sepClassIndex]! : undefined
|
|
3566
|
+
// THE GAP GATE (`gap-gate.ts`): read the item's leading gap once, here.
|
|
3567
|
+
const gapIp = sepIp < 0 && min === 0 && !REC && code[code[ip + 1]!] === OP_GAPGATE ? code[ip + 1]! : -1
|
|
3568
|
+
const gapRow = gapIp >= 0 ? code[gapIp + 2]! : -1
|
|
3569
|
+
const gapRe = gapIp >= 0 ? k[code[gapRow + 1]!] as RegExp : undefined
|
|
3570
|
+
const gapFollow = gapIp >= 0 ? cc[code[gapIp + 3]!]! : undefined
|
|
3571
|
+
const gapOther = gapIp >= 0 && code[gapIp + 4]! >= 0 ? cc[code[gapIp + 4]!]! : undefined
|
|
3454
3572
|
const skipBeforeFirst = sepIp < 0 && min === 0
|
|
3455
3573
|
const itemClean = sepIp < 0 && CLEAN(code[ip + 1]!) && !rowNullable(code, k, code[ip + 1]!, NULLABLE)
|
|
3456
3574
|
|
|
@@ -3479,7 +3597,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3479
3597
|
* delimiter (`orSentinel`, repeat.ts:454).
|
|
3480
3598
|
* - `mySync` is captured at ENTRY. An element's own sequence publishes
|
|
3481
3599
|
* over `_sync` while it runs; the interpreter restores in a `finally`
|
|
3482
|
-
* and
|
|
3600
|
+
* and the source lowering saved at entry — same value, both ways.
|
|
3483
3601
|
* - the separator-less path rolls the leading trivia back BEFORE
|
|
3484
3602
|
* recovering (repeat.ts's `repItem`), and the separated path does NOT:
|
|
3485
3603
|
* a consumed separator and the error after it both belong to the list
|
|
@@ -3487,6 +3605,8 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3487
3605
|
*/
|
|
3488
3606
|
if (REC) {
|
|
3489
3607
|
const itemFx = fx[code[ip + 6]!] as string[]
|
|
3608
|
+
// A resync error carries the item's set as derived (bit 16: empty).
|
|
3609
|
+
const recFx = (flags & 16) !== 0 ? EMPTY_FX : itemFx
|
|
3490
3610
|
const sepSent = sentinelFor(code[ip + 7]!)
|
|
3491
3611
|
return (input, pos, ctx) => {
|
|
3492
3612
|
const out: unknown[] | undefined = collect ? [] : undefined
|
|
@@ -3547,7 +3667,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3547
3667
|
const rr = recoverScan(
|
|
3548
3668
|
input, itemStart, ctx,
|
|
3549
3669
|
sep === undefined ? mySync : orSentinel(sepSent ?? mySync, sepSent === undefined ? undefined : mySync),
|
|
3550
|
-
|
|
3670
|
+
recFx,
|
|
3551
3671
|
)
|
|
3552
3672
|
if (out !== undefined) out.push(rr.error)
|
|
3553
3673
|
captureError(ctx, rr.error)
|
|
@@ -3587,6 +3707,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3587
3707
|
// Keep the ordinary child path while one is active so this structural
|
|
3588
3708
|
// fast stop cannot erase an item completion at the cursor.
|
|
3589
3709
|
const gateItems = itemMayStart !== undefined && ctx._probe === undefined
|
|
3710
|
+
const gateSep = sepClass !== undefined && ctx._probe === undefined
|
|
3590
3711
|
let cur = pos
|
|
3591
3712
|
let count = 0
|
|
3592
3713
|
for (;;) {
|
|
@@ -3618,6 +3739,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3618
3739
|
const leavesBefore = cstLeavesLen(ctx)
|
|
3619
3740
|
let sp = cur
|
|
3620
3741
|
if (hasTrivia) sp = skipTrivia(input, sp, ctx)
|
|
3742
|
+
if (count >= min && gateSep && !classHas(sepClass!, lead(input, sp))) {
|
|
3743
|
+
if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
3744
|
+
break
|
|
3745
|
+
}
|
|
3621
3746
|
ctx._fc = false
|
|
3622
3747
|
if (sepLeads) LEAD.at = cur
|
|
3623
3748
|
const sv = sep(input, sp, ctx)
|
|
@@ -3637,13 +3762,33 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3637
3762
|
if (trailingAllowed && sepEnd >= 0) cur = sepEnd
|
|
3638
3763
|
break
|
|
3639
3764
|
}
|
|
3640
|
-
|
|
3765
|
+
// Without a separator or trivia in front, the loop head already
|
|
3766
|
+
// tested this same position.
|
|
3767
|
+
if (count >= min && gateItems && (sep !== undefined || hasTrivia) && !itemMayStart!(input, itemStart)) {
|
|
3641
3768
|
if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
3642
3769
|
if (trailingAllowed && sepEnd >= 0) cur = sepEnd
|
|
3643
3770
|
break
|
|
3644
3771
|
}
|
|
3772
|
+
let gapped = false
|
|
3773
|
+
if (gapRe !== undefined && ctx._probe === undefined) {
|
|
3774
|
+
gapRe.lastIndex = itemStart
|
|
3775
|
+
const q = gapRe.test(input) ? gapRe.lastIndex : -1
|
|
3776
|
+
// No arm with the gap can match where the gap fails, or where the
|
|
3777
|
+
// character after it opens nothing; an arm without it needs its
|
|
3778
|
+
// own lead at the item's start.
|
|
3779
|
+
if ((q < 0 || !classHas(gapFollow!, lead(input, q)))
|
|
3780
|
+
&& (gapOther === undefined || !classHas(gapOther, lead(input, itemStart)))) {
|
|
3781
|
+
if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
3782
|
+
break
|
|
3783
|
+
}
|
|
3784
|
+
if (q >= 0) {
|
|
3785
|
+
GAP.row = gapRow; GAP.at = itemStart; GAP.end = q; GAP.input = input
|
|
3786
|
+
gapped = true
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3645
3789
|
ctx._fc = false
|
|
3646
3790
|
const v = child(input, itemStart, ctx)
|
|
3791
|
+
if (gapped) GAP.at = -1
|
|
3647
3792
|
if (v === FAIL) {
|
|
3648
3793
|
if (markIt) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot)
|
|
3649
3794
|
if (committed(ctx)) return FAIL
|
|
@@ -3676,7 +3821,8 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3676
3821
|
const selector = link(code[ip + 1]!)
|
|
3677
3822
|
const otherIp = code[ip + 3]!
|
|
3678
3823
|
const other = otherIp >= 0 ? link(otherIp) : undefined
|
|
3679
|
-
const otherRouted = code[ip + 4]! === 1
|
|
3824
|
+
const otherRouted = (code[ip + 4]! & 1) === 1
|
|
3825
|
+
const otherCommits = (code[ip + 4]! & 2) === 0
|
|
3680
3826
|
const n = code[ip + 5]!
|
|
3681
3827
|
const armBase = ip + 6
|
|
3682
3828
|
const byKey = spec.byKey
|
|
@@ -3723,7 +3869,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3723
3869
|
)
|
|
3724
3870
|
}
|
|
3725
3871
|
const runArm = n === 0 ? undefined : bindArms(0)
|
|
3726
|
-
const runOther = other === undefined ? undefined : dispatchBranch(other, otherRouted)
|
|
3872
|
+
const runOther = other === undefined ? undefined : dispatchBranch(other, otherRouted, otherCommits)
|
|
3727
3873
|
|
|
3728
3874
|
return (input, pos, ctx) => {
|
|
3729
3875
|
const need = markCst(ctx)
|
|
@@ -3903,7 +4049,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
3903
4049
|
ctx._fields = wantFields ? [] : undefined
|
|
3904
4050
|
// PER-NODE-TYPE TRIVIA-KIND MASK, scoped to the body and restored —
|
|
3905
4051
|
// `node.ts:259-273`, and codegen's `_triviaCaptureMask` save/install/
|
|
3906
|
-
// restore around the same scope
|
|
4052
|
+
// restore around the same scope. The table
|
|
3907
4053
|
// installed nothing, so a host that asked `Outer` for comments only got
|
|
3908
4054
|
// every kind the scanner saw.
|
|
3909
4055
|
const savedMask = structural ? ctx._triviaCaptureMask : undefined
|
|
@@ -4100,22 +4246,22 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
4100
4246
|
? prog.asm?.find(a => a.key === cfgKey(cfg))
|
|
4101
4247
|
: undefined
|
|
4102
4248
|
if (pre !== undefined) {
|
|
4249
|
+
assertFactoryArity(pre)
|
|
4103
4250
|
const pools = rebuildPools(t.cc, t.fx, t.disp, pre.plan)
|
|
4104
4251
|
emitted = pre.factory(
|
|
4105
|
-
EC, FAIL, k, fx, fns, pools.masks, pools.classes, pools.armExpected, trivia,
|
|
4106
|
-
trivia.map(tv => tv?._meta.triviaKindLabels), triviaScan,
|
|
4252
|
+
EC, FAIL, k, fx, fns, pools.masks, pools.classes, pools.armExpected, trivia, triviaScan,
|
|
4107
4253
|
scansArr, disp, dsp, EMPTY_FX, EMPTY_CH, EMPTY_TLOG, EMPTY_TL,
|
|
4108
4254
|
cstCaptureActive, pushCstLeaf, pushCstChild, rollbackTriviaAt, rollbackScannedTriviaAt, failAt,
|
|
4109
4255
|
classHas, consumeTrivia, buildFieldMap, projectChild, unwrapChild,
|
|
4110
4256
|
demoteCapturedToRaw, cstLeavesLen, skipTriviaScanned, needsDeferredTriviaCommit,
|
|
4111
|
-
|
|
4257
|
+
advanceTrivia, refuseUnclassifiedRootScope, spanLines, rawEntry, lead,
|
|
4112
4258
|
asciiFoldKey, ROUTED_FX,
|
|
4113
4259
|
REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
|
|
4114
4260
|
matchesAt, recoverScan, orSentinel, captureError,
|
|
4115
|
-
scalarRecognizers,
|
|
4261
|
+
scalarRecognizers, t.lex, adjacencyHolds, t.lexPrograms,
|
|
4116
4262
|
LEAD, triviaFieldCapture, skipDeferredTrivia,
|
|
4117
4263
|
collapseEmpty,
|
|
4118
|
-
PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf,
|
|
4264
|
+
PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf, GAP,
|
|
4119
4265
|
)
|
|
4120
4266
|
emitReached = new Set(pre.reached)
|
|
4121
4267
|
if (emitted.ext !== undefined) HYBRID = emitted
|
|
@@ -4182,13 +4328,12 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
4182
4328
|
throw new Unemittable(`the Function constructor (${String(e)})`)
|
|
4183
4329
|
}
|
|
4184
4330
|
emitted = factory(
|
|
4185
|
-
EC, FAIL, k, fx, fns, em.masks, em.classes, em.armExpected, trivia,
|
|
4186
|
-
trivia.map(tv => tv?._meta.triviaKindLabels), triviaScan,
|
|
4331
|
+
EC, FAIL, k, fx, fns, em.masks, em.classes, em.armExpected, trivia, triviaScan,
|
|
4187
4332
|
scansArr, disp, dsp, EMPTY_FX, EMPTY_CH, EMPTY_TLOG, EMPTY_TL,
|
|
4188
4333
|
cstCaptureActive, pushCstLeaf, pushCstChild, rollbackTriviaAt, rollbackScannedTriviaAt, failAt,
|
|
4189
4334
|
classHas, consumeTrivia, buildFieldMap, projectChild, unwrapChild,
|
|
4190
4335
|
demoteCapturedToRaw, cstLeavesLen, skipTriviaScanned, needsDeferredTriviaCommit,
|
|
4191
|
-
|
|
4336
|
+
advanceTrivia, refuseUnclassifiedRootScope, spanLines, rawEntry, lead,
|
|
4192
4337
|
asciiFoldKey, ROUTED_FX,
|
|
4193
4338
|
// THE SENTINEL POOL, dense over char-class indices so the emitted text can
|
|
4194
4339
|
// index it the way it indexes `SCANS`. Built only for a recovery assembly
|
|
@@ -4197,10 +4342,10 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
4197
4342
|
// object rather than to two separately constructed ones.
|
|
4198
4343
|
REC ? prog.cc.map((_, i) => sentinelFor(i)) : EMPTY_SENTS,
|
|
4199
4344
|
matchesAt, recoverScan, orSentinel, captureError,
|
|
4200
|
-
scalarRecognizers,
|
|
4345
|
+
scalarRecognizers, t.lex, adjacencyHolds, t.lexPrograms,
|
|
4201
4346
|
LEAD, triviaFieldCapture, skipDeferredTrivia,
|
|
4202
4347
|
collapseEmpty,
|
|
4203
|
-
PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf,
|
|
4348
|
+
PlainSpan, PlainLeaf, PlainNode, PlainField, PlainBuf, GAP,
|
|
4204
4349
|
)
|
|
4205
4350
|
emitReached = em.reached
|
|
4206
4351
|
} catch (e) {
|
package/src/table/child-slots.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
OP_LIT_CI_TRACK, OP_LIT_TRACK, OP_LIVE, OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT,
|
|
5
5
|
OP_PEEK, OP_REJECT, OP_REP, OP_REPV, OP_ROUTED, OP_RULE, OP_RX, OP_RX_TRACK, OP_SCAN,
|
|
6
6
|
OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
|
|
7
|
-
OP_LEX_BODY, OP_LEX_PROGRAM,
|
|
7
|
+
OP_LEX_BODY, OP_LEX_PROGRAM, OP_GAPGATE, OP_RGATE2, OP_STRICT,
|
|
8
8
|
} from './ops.ts'
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -47,16 +47,21 @@ export function childSlots(code: ArrayLike<number>, ip: number, out: number[]):
|
|
|
47
47
|
// rest — a coverage-encoded program is a program, and omitting it made
|
|
48
48
|
// `opHistogram` throw on every table the coverage build produces.
|
|
49
49
|
case OP_RULE: case OP_OPT: case OP_NOT: case OP_PEEK: case OP_EXPECT:
|
|
50
|
-
case OP_TOKEN: case OP_ATTEMPT: case OP_LABEL: case OP_COV: case OP_REJECT:
|
|
50
|
+
case OP_TOKEN: case OP_ATTEMPT: case OP_LABEL: case OP_COV: case OP_REJECT: case OP_GAPGATE:
|
|
51
51
|
out.push(code[ip + 1]!)
|
|
52
52
|
return true
|
|
53
53
|
|
|
54
54
|
// Single child at `ip + 2`.
|
|
55
55
|
case OP_GATE: case OP_SCOPE: case OP_SCOPE_CAP: case OP_SCOPE_PLAIN: case OP_WITHCTX: case OP_XFORM:
|
|
56
|
-
case OP_NODE: case OP_NODE_TRACK: case OP_FIELD: case OP_LEAF: case OP_SOURCE_LEAF: case OP_ARMGATE: case OP_RGATE:
|
|
56
|
+
case OP_NODE: case OP_NODE_TRACK: case OP_FIELD: case OP_LEAF: case OP_SOURCE_LEAF: case OP_ARMGATE: case OP_RGATE: case OP_RGATE2:
|
|
57
57
|
out.push(code[ip + 2]!)
|
|
58
58
|
return true
|
|
59
59
|
|
|
60
|
+
// `STRICT strict tolerant` — both encodings are reachable; an assembly keeps one.
|
|
61
|
+
case OP_STRICT:
|
|
62
|
+
out.push(code[ip + 1]!, code[ip + 2]!)
|
|
63
|
+
return true
|
|
64
|
+
|
|
60
65
|
// `ROUTED fallback` — the operand is an offset or −1. The routed token itself is
|
|
61
66
|
// data the enclosing `dispatch()` already consumed, so the only edge is the
|
|
62
67
|
// fallback.
|
|
@@ -19,7 +19,7 @@ import { runDuplicationDiagnosticRules, type DuplicationOption } from './duplica
|
|
|
19
19
|
* `compileRuleMap()` FOR THE TABLE LOWERING — the counterpart that did not exist.
|
|
20
20
|
*
|
|
21
21
|
* `compile` covered `compile()`, the SINGLE-ROOT entry point, which the
|
|
22
|
-
* plugin uses only for standalone combinators
|
|
22
|
+
* plugin uses only for standalone combinators.
|
|
23
23
|
* The main path — every `rules()` grammar — goes through `compileRuleMap`, and
|
|
24
24
|
* with no table counterpart there was nothing for the macro build to point at.
|
|
25
25
|
* This is that function, and it is the EASY direction: `encodeTable` takes a
|
|
@@ -29,7 +29,7 @@ import { runDuplicationDiagnosticRules, type DuplicationOption } from './duplica
|
|
|
29
29
|
* ── THE CONTRACT IT MATCHES ──────────────────────────────────────────────────
|
|
30
30
|
* `compileRuleMap` returns ONE `replacement` string: a self-contained expression
|
|
31
31
|
* that the plugin splices over the whole `rules(factory)` call-expression
|
|
32
|
-
* (`plugin/index.ts
|
|
32
|
+
* (`evaluateRulesFactory` in `plugin/index.ts`), evaluating ONCE to
|
|
33
33
|
* the `{ name: fn, … }` map. `keys` is the entry list, for the caller to check
|
|
34
34
|
* against the source's own keys. `hostMode` / `hostBranchElided` are what the
|
|
35
35
|
* macro stamps the emitted map with. `reflection` is per-grammar CST node
|
|
@@ -59,6 +59,7 @@ export type TableRuleMapOptions = {
|
|
|
59
59
|
readonly specialise?: boolean
|
|
60
60
|
/** Grammar-level ambient scan-skip, as `rules({ scanSkip }, …)` declares it. */
|
|
61
61
|
readonly scanSkip?: Combinator<unknown>[]
|
|
62
|
+
/** @deprecated Has no effect (see `TableSettings.recovery`). Removed in the next minor release. */
|
|
62
63
|
readonly recovery?: boolean
|
|
63
64
|
readonly hostMode?: HostMode
|
|
64
65
|
readonly trackLines?: boolean
|
|
@@ -264,7 +265,7 @@ function encodeForRun(
|
|
|
264
265
|
): { prog: TableProgram; fnSrcs: (string | null)[]; hostMode: HostMode; plan: ReturnType<typeof buildGrammarPlan> | undefined } | null {
|
|
265
266
|
runDuplicationDiagnosticRules(ruleMap, opts.duplication)
|
|
266
267
|
const encodeMap = withAmbient(ruleMap, opts)
|
|
267
|
-
// WINNERS ARE THE NON-`lazy` ENTRIES, exactly as
|
|
268
|
+
// WINNERS ARE THE NON-`lazy` ENTRIES, exactly as the source lowering picked them.
|
|
268
269
|
// A `rules()` map stores named lazy proxies beside resolved bodies, and the plan
|
|
269
270
|
// uses the winner map to give a shared subtree ONE owner; filtering differently
|
|
270
271
|
// here would mint `rule:` ids the source lowering does not, so a consumer
|
|
@@ -355,9 +356,12 @@ export function compileRuleMap(
|
|
|
355
356
|
const roots = assemblyExtraIps(artifact)
|
|
356
357
|
let siteBytes, fixed
|
|
357
358
|
try {
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
|
|
359
|
+
// RANKED with every gap gate lowered as its item (`gapNeutral`), so the
|
|
360
|
+
// gates move no site's place in the order; the fit below is judged by the
|
|
361
|
+
// source that ships, gates included. Priced throughout without the
|
|
362
|
+
// `_errors` marks a lexical program over a scan adds (`scanSinkNeutral`),
|
|
363
|
+
// so they move no site in or out of the budget.
|
|
364
|
+
siteBytes = emitAssemblySource(table, artifact, cfg, roots, true, undefined, true, true).siteBytes
|
|
361
365
|
// What any selective assembly costs before its first site body: the shared
|
|
362
366
|
// prelude and the factory's tail. A budget that cannot cover it buys nothing.
|
|
363
367
|
fixed = emitAssemblySource(table, artifact, cfg, roots, true, new Set(), true).source.length
|
package/src/table/compile.ts
CHANGED
|
@@ -79,8 +79,8 @@ export type TableCompileOptions = {
|
|
|
79
79
|
readonly hostMode?: HostMode
|
|
80
80
|
readonly trackLines?: boolean
|
|
81
81
|
/**
|
|
82
|
-
* ACCEPTED AND IGNORED — recovery is ALWAYS lowered (see
|
|
83
|
-
*
|
|
82
|
+
* @deprecated ACCEPTED AND IGNORED — recovery is ALWAYS lowered (see
|
|
83
|
+
* `TableSettings.recovery`). Removed in the next minor release.
|
|
84
84
|
*/
|
|
85
85
|
readonly recovery?: boolean
|
|
86
86
|
/**
|
|
@@ -178,7 +178,7 @@ function compileRoot<T>(
|
|
|
178
178
|
): CompiledParser<T> {
|
|
179
179
|
// Argument order mirrors `compile(combinator, mapFnSources?, opts?)` so this is
|
|
180
180
|
// a drop-in, not a second API with a different shape.
|
|
181
|
-
// THE SAME WALK
|
|
181
|
+
// THE SAME WALK THE SOURCE LOWERING USED FOR A SINGLE ROOT: no winner
|
|
182
182
|
// map, so the paths are rooted at `entry` and the ids are the ones a caller
|
|
183
183
|
// switching lowerings already has. Building it differently here would produce a
|
|
184
184
|
// set that is internally consistent and lines up with nothing.
|