parseman 0.47.0 → 0.47.1
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.cjs +133 -45
- package/dist/analysis/diagnostics.cjs.map +2 -2
- package/dist/analysis/diagnostics.js +133 -45
- package/dist/analysis/diagnostics.js.map +2 -2
- package/dist/cli/index.cjs +133 -45
- package/dist/cli/index.cjs.map +2 -2
- package/dist/cli/index.js +133 -45
- package/dist/cli/index.js.map +2 -2
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +5 -0
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/index.cjs +134 -46
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +134 -46
- package/dist/index.js.map +2 -2
- package/dist/language-service/index.cjs +3 -1
- package/dist/language-service/index.cjs.map +1 -1
- package/dist/language-service/index.js +3 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/index.cjs +134 -46
- package/dist/plugin/index.cjs.map +2 -2
- package/dist/plugin/index.js +134 -46
- package/dist/plugin/index.js.map +2 -2
- package/dist/spec/index.cjs +55 -7
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.js +55 -7
- package/dist/spec/index.js.map +1 -1
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts +2 -2
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/emit.d.ts.map +1 -1
- package/dist/table/exec.d.ts.map +1 -1
- package/dist/table/index.cjs +1566 -1478
- package/dist/table/index.cjs.map +3 -3
- package/dist/table/index.js +1566 -1478
- package/dist/table/index.js.map +3 -3
- package/dist/table/ops.d.ts +8 -1
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/table/program.d.ts +4 -1
- package/dist/table/program.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/combinators/first-set.ts +29 -3
- package/src/combinators/sequence.ts +23 -7
- package/src/combinators/trivia-skip.ts +31 -0
- package/src/table/assemble.ts +30 -18
- package/src/table/child-slots.ts +2 -2
- package/src/table/emit-assembly.ts +36 -25
- package/src/table/emit.ts +12 -1
- package/src/table/encode.ts +4 -4
- package/src/table/exec.ts +20 -12
- package/src/table/ops.ts +9 -1
- package/src/table/program.ts +22 -1
- package/src/table/site-labels.ts +2 -2
- package/src/table/stamp.ts +2 -2
- package/src/version.ts +1 -1
package/dist/table/ops.d.ts
CHANGED
|
@@ -103,12 +103,14 @@ export declare const OP_LIT_TRACK = 17;
|
|
|
103
103
|
export declare const OP_RX_TRACK = 18;
|
|
104
104
|
export declare const OP_NODE_TRACK = 19;
|
|
105
105
|
/**
|
|
106
|
-
* `SCOPE k c` — a `parser({ trivia })`
|
|
106
|
+
* `SCOPE k c policy` — a policy-bearing `parser({ trivia })` scope.
|
|
107
107
|
*
|
|
108
108
|
* `k` is the scope's trivia COMBINATOR in the const pool. The driver installs it
|
|
109
109
|
* on `ctx.trivia` for the duration and restores the outer one after, which is
|
|
110
110
|
* how the runtime's own `advanceTrivia` fast scanner gets reached — the same
|
|
111
111
|
* shared machinery the interpreter uses, not a second copy of it.
|
|
112
|
+
* Synthetic rule-entry/restoration scopes use `OP_SCOPE_PLAIN` so a zero
|
|
113
|
+
* policy stays a three-word row without changing this opcode's ABI.
|
|
112
114
|
*/
|
|
113
115
|
export declare const OP_SCOPE = 20;
|
|
114
116
|
/**
|
|
@@ -424,6 +426,11 @@ export declare const OP_LABEL = 39;
|
|
|
424
426
|
* which is the granularity the IDs are minted at.
|
|
425
427
|
*/
|
|
426
428
|
export declare const OP_COV = 40;
|
|
429
|
+
/**
|
|
430
|
+
* `SCOPE_PLAIN k c` — a synthetic ambient-trivia scope with policy fixed to zero.
|
|
431
|
+
* A distinct opcode prevents the next row's opcode from being read as policy.
|
|
432
|
+
*/
|
|
433
|
+
export declare const OP_SCOPE_PLAIN = 41;
|
|
427
434
|
/**
|
|
428
435
|
* `DISPATCH sel d other otherRouted n a1 … an` — `dispatch()`.
|
|
429
436
|
*
|
package/dist/table/ops.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/table/ops.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,wDAAwD;AACxD,eAAO,MAAM,MAAM,IAAI,CAAA;AACvB,gEAAgE;AAChE,eAAO,MAAM,KAAK,IAAI,CAAA;AACtB,6EAA6E;AAC7E,eAAO,MAAM,MAAM,IAAI,CAAA;AACvB,iFAAiF;AACjF,eAAO,MAAM,OAAO,IAAI,CAAA;AACxB;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B;;;GAGG;AACH,eAAO,MAAM,MAAM,IAAI,CAAA;AACvB,2CAA2C;AAC3C,eAAO,MAAM,OAAO,IAAI,CAAA;AACxB;;;;kDAIkD;AAClD,eAAO,MAAM,MAAM,IAAI,CAAA;AACvB,qEAAqE;AACrE,eAAO,MAAM,QAAQ,IAAI,CAAA;AACzB;;;;;;;;;;;;;;;;;;;;iCAoBiC;AACjC,eAAO,MAAM,OAAO,KAAK,CAAA;AACzB,2CAA2C;AAC3C,eAAO,MAAM,OAAO,KAAK,CAAA;AACzB,8EAA8E;AAC9E,eAAO,MAAM,OAAO,KAAK,CAAA;AACzB,+CAA+C;AAC/C,eAAO,MAAM,MAAM,KAAK,CAAA;AACxB;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,KAAK,CAAA;AACzB,oEAAoE;AACpE,eAAO,MAAM,OAAO,KAAK,CAAA;AACzB,0CAA0C;AAC1C,eAAO,MAAM,QAAQ,KAAK,CAAA;AAC1B;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,KAAK,CAAA;AAC9B,eAAO,MAAM,WAAW,KAAK,CAAA;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAA;AAC/B
|
|
1
|
+
{"version":3,"file":"ops.d.ts","sourceRoot":"","sources":["../../src/table/ops.ts"],"names":[],"mappings":"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"}
|
package/dist/table/program.d.ts
CHANGED
|
@@ -118,7 +118,8 @@ export type TableProgram = {
|
|
|
118
118
|
*/
|
|
119
119
|
readonly runtimeOnly?: readonly string[];
|
|
120
120
|
/**
|
|
121
|
-
* Trivia specs, referenced by index from `OP_SCOPE` and
|
|
121
|
+
* Trivia specs, referenced by index from `OP_SCOPE`, `OP_SCOPE_CAP` and
|
|
122
|
+
* `OP_SCOPE_PLAIN` rule/restoration entries.
|
|
122
123
|
*
|
|
123
124
|
* `classifiedTrivia()` is `trivia(oneOrMore(choice(label(name, arm)…)))` with
|
|
124
125
|
* regex arms — entirely structural, so it lowers to DATA and is rebuilt at
|
|
@@ -303,6 +304,8 @@ export type ResolvedDispatchSpec = {
|
|
|
303
304
|
readonly routed: readonly number[];
|
|
304
305
|
readonly expected: readonly string[];
|
|
305
306
|
};
|
|
307
|
+
/** Refuse malformed dispatch arm references before closure/emitted linking. */
|
|
308
|
+
export declare function validateDispatchSpec(spec: ResolvedDispatchSpec | undefined, arity: number, fallbackRouted: number): asserts spec is ResolvedDispatchSpec;
|
|
306
309
|
/** A char class expanded for execution: O(1) for ASCII, ranges above it. */
|
|
307
310
|
export type ResolvedClass = {
|
|
308
311
|
readonly ascii: Uint8Array;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/table/program.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAExE,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AAIzF,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAElE;;;;;;;;;GASG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAA;IAChC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;IAChC,sDAAsD;IACtD,QAAQ,CAAC,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,SAAS,OAAO,EAAE,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;IAC9B,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,SAAS,YAAY,EAAE,CAAA;IACrC,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAChD;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IACtB;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,CAAC,CAAA;IAC3B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,SAAS,UAAU,EAAE,CAAC,EAAE,CAAA;IACtD;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,sDAAsD;IACtD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAA;IACpC;;;;;;;;OAQG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;IACjC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACxC
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/table/program.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
* Kept in sync with `package.json` by `test/unit/version-sync.test.ts`, which fails
|
|
14
14
|
* the build if this constant drifts from the published version.
|
|
15
15
|
*/
|
|
16
|
-
export declare const PARSEMAN_VERSION = "0.47.
|
|
16
|
+
export declare const PARSEMAN_VERSION = "0.47.1";
|
|
17
17
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "parseman",
|
|
3
|
-
"version": "0.47.
|
|
3
|
+
"version": "0.47.1",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": "^20.19.0 || >=22.12.0"
|
|
@@ -97,6 +97,7 @@
|
|
|
97
97
|
"prepare": "git config core.hooksPath scripts/git-hooks || true; node scripts/build.mjs",
|
|
98
98
|
"prepublishOnly": "node scripts/check-changelog.mjs --publish",
|
|
99
99
|
"check:changelog": "node scripts/check-changelog.mjs",
|
|
100
|
+
"check:main-release-state": "node scripts/check-main-release-state.mjs",
|
|
100
101
|
"docs:verify": "node scripts/verify-doc-examples.mjs",
|
|
101
102
|
"docs:dev": "vitepress dev docs",
|
|
102
103
|
"docs:build": "vitepress build docs",
|
|
@@ -84,11 +84,23 @@ export function matchesEmpty(
|
|
|
84
84
|
seen: Set<Combinator<unknown>> = new Set(),
|
|
85
85
|
resolve?: RefResolver,
|
|
86
86
|
): boolean {
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
87
|
+
// `seen` is the current recursion stack, not a global visited set. A node
|
|
88
|
+
// reached again through a sibling in a shared DAG is not recursive; only a
|
|
89
|
+
// back-edge on the current path gets the safe nullable answer.
|
|
90
90
|
if (seen.has(p)) return true
|
|
91
91
|
seen.add(p)
|
|
92
|
+
try {
|
|
93
|
+
return matchesEmptyBody(p, seen, resolve)
|
|
94
|
+
} finally {
|
|
95
|
+
seen.delete(p)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function matchesEmptyBody(
|
|
100
|
+
p: Combinator<unknown>,
|
|
101
|
+
seen: Set<Combinator<unknown>>,
|
|
102
|
+
resolve: RefResolver | undefined,
|
|
103
|
+
): boolean {
|
|
92
104
|
const me = (c: Combinator<unknown>): boolean => matchesEmpty(c, seen, resolve)
|
|
93
105
|
const d = p._def as ParserDef
|
|
94
106
|
switch (d.tag) {
|
|
@@ -249,8 +261,22 @@ export function firstSetOf(
|
|
|
249
261
|
seen: Set<Combinator<unknown>> = new Set(),
|
|
250
262
|
resolve?: RefResolver,
|
|
251
263
|
): FirstSet {
|
|
264
|
+
// As above, only a node on the current recursion path is a cycle. Keeping a
|
|
265
|
+
// completed shared child in this set widened later siblings to `any`.
|
|
252
266
|
if (seen.has(p)) return any() // cycle → any (safe over-approximation)
|
|
253
267
|
seen.add(p)
|
|
268
|
+
try {
|
|
269
|
+
return firstSetBody(p, seen, resolve)
|
|
270
|
+
} finally {
|
|
271
|
+
seen.delete(p)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function firstSetBody(
|
|
276
|
+
p: Combinator<unknown>,
|
|
277
|
+
seen: Set<Combinator<unknown>>,
|
|
278
|
+
resolve: RefResolver | undefined,
|
|
279
|
+
): FirstSet {
|
|
254
280
|
const fs = (c: Combinator<unknown>): FirstSet => firstSetOf(c, seen, resolve)
|
|
255
281
|
const empties = (c: Combinator<unknown>): boolean => matchesEmpty(c, new Set(), resolve)
|
|
256
282
|
const d = p._def as ParserDef
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Combinator, ParseContext, ParseResult, ParserMeta, ParseFail } from '../types.ts'
|
|
2
2
|
import { sequenceFirstSet, firstSetOf, union } from './first-set.ts'
|
|
3
|
-
import { advanceTrivia, needsDeferredTriviaCommit,
|
|
3
|
+
import { advanceTrivia, needsDeferredTriviaCommit, rollbackScannedTriviaAt, scanTrivia } from './trivia-skip.ts'
|
|
4
|
+
import { cstTlLen } from '../cst/capture-buffer.ts'
|
|
4
5
|
import { firstSetSentinel } from '../recovery/scan.ts'
|
|
5
6
|
import { adjacencyFail, adjacencyOf, holdsAdjacency, type AdjacencyDef } from './adjacency.ts'
|
|
6
7
|
|
|
@@ -80,7 +81,9 @@ export function sequence<T extends [Combinator<unknown>, ...Combinator<unknown>[
|
|
|
80
81
|
continue
|
|
81
82
|
}
|
|
82
83
|
if (ctx.trivia && i > 0) {
|
|
83
|
-
const
|
|
84
|
+
const mTlog = cstTlLen(ctx)
|
|
85
|
+
const mLog = ctx._triviaLog?.length ?? 0
|
|
86
|
+
const mRootLog = ctx._rootTriviaLog?.length ?? 0
|
|
84
87
|
let scanEnd: number
|
|
85
88
|
if (needsDeferredTriviaCommit(ctx)) {
|
|
86
89
|
const scan = scanTrivia(input, cur, ctx)
|
|
@@ -89,10 +92,13 @@ export function sequence<T extends [Combinator<unknown>, ...Combinator<unknown>[
|
|
|
89
92
|
} else {
|
|
90
93
|
scanEnd = advanceTrivia(input, cur, ctx)
|
|
91
94
|
}
|
|
95
|
+
const scanTlog = cstTlLen(ctx)
|
|
96
|
+
const scanLog = ctx._triviaLog?.length ?? 0
|
|
97
|
+
const scanRootLog = ctx._rootTriviaLog?.length ?? 0
|
|
92
98
|
const result = parsers[i]!.parse(input, scanEnd, ctx)
|
|
93
99
|
if (!result.ok) return result as ParseFail
|
|
94
100
|
if (result.span.end > scanEnd) cur = result.span.end
|
|
95
|
-
else
|
|
101
|
+
else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog)
|
|
96
102
|
if (values !== undefined) values.push(result.value)
|
|
97
103
|
continue
|
|
98
104
|
}
|
|
@@ -131,7 +137,9 @@ export function sequence<T extends [Combinator<unknown>, ...Combinator<unknown>[
|
|
|
131
137
|
}
|
|
132
138
|
if (ctx.trivia && i > 0) {
|
|
133
139
|
let scanEnd: number
|
|
134
|
-
const
|
|
140
|
+
const mTlog = cstTlLen(ctx)
|
|
141
|
+
const mLog = ctx._triviaLog?.length ?? 0
|
|
142
|
+
const mRootLog = ctx._rootTriviaLog?.length ?? 0
|
|
135
143
|
if (needsDeferredTriviaCommit(ctx)) {
|
|
136
144
|
const scan = scanTrivia(input, cur, ctx)
|
|
137
145
|
scan.commit()
|
|
@@ -139,10 +147,13 @@ export function sequence<T extends [Combinator<unknown>, ...Combinator<unknown>[
|
|
|
139
147
|
} else {
|
|
140
148
|
scanEnd = advanceTrivia(input, cur, ctx)
|
|
141
149
|
}
|
|
150
|
+
const scanTlog = cstTlLen(ctx)
|
|
151
|
+
const scanLog = ctx._triviaLog?.length ?? 0
|
|
152
|
+
const scanRootLog = ctx._rootTriviaLog?.length ?? 0
|
|
142
153
|
const result = parsers[i]!.parse(input, scanEnd, ctx)
|
|
143
154
|
if (!result.ok) return result as ParseFail
|
|
144
155
|
if (result.span.end > scanEnd) cur = result.span.end
|
|
145
|
-
else
|
|
156
|
+
else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog)
|
|
146
157
|
if (values !== undefined) values.push(result.value)
|
|
147
158
|
continue
|
|
148
159
|
}
|
|
@@ -183,7 +194,9 @@ export function sequence<T extends [Combinator<unknown>, ...Combinator<unknown>[
|
|
|
183
194
|
// this term actually matches content past the trivia. A term that matches
|
|
184
195
|
// empty (optional/many/lookahead) leaves the trivia for the enclosing rule.
|
|
185
196
|
let scanEnd: number
|
|
186
|
-
|
|
197
|
+
const mTlog = cstTlLen(ctx)
|
|
198
|
+
const mLog = ctx._triviaLog?.length ?? 0
|
|
199
|
+
const mRootLog = ctx._rootTriviaLog?.length ?? 0
|
|
187
200
|
|
|
188
201
|
if (needsDeferredTriviaCommit(ctx)) {
|
|
189
202
|
const scan = scanTrivia(input, cur, ctx)
|
|
@@ -193,12 +206,15 @@ export function sequence<T extends [Combinator<unknown>, ...Combinator<unknown>[
|
|
|
193
206
|
scanEnd = advanceTrivia(input, cur, ctx)
|
|
194
207
|
}
|
|
195
208
|
|
|
209
|
+
const scanTlog = cstTlLen(ctx)
|
|
210
|
+
const scanLog = ctx._triviaLog?.length ?? 0
|
|
211
|
+
const scanRootLog = ctx._rootTriviaLog?.length ?? 0
|
|
196
212
|
const result = parsers[i]!.parse(input, scanEnd, ctx)
|
|
197
213
|
if (!result.ok) return result as ParseFail
|
|
198
214
|
if (result.span.end > scanEnd) {
|
|
199
215
|
cur = result.span.end
|
|
200
216
|
} else {
|
|
201
|
-
|
|
217
|
+
rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog)
|
|
202
218
|
}
|
|
203
219
|
if (values !== undefined) values.push(result.value)
|
|
204
220
|
continue
|
|
@@ -95,6 +95,37 @@ export function rollbackTrivia(ctx: ParseContext, mark: TriviaRollbackMark): voi
|
|
|
95
95
|
if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
function removeNumberRange(values: number[] | undefined, start: number, end: number): void {
|
|
99
|
+
if (values === undefined || end <= start) return
|
|
100
|
+
if (values.length > end) values.copyWithin(start, end)
|
|
101
|
+
values.length -= end - start
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Remove only the trivia rows appended by an ambient scan, preserving effects
|
|
106
|
+
* appended later by a successful zero-width child.
|
|
107
|
+
*/
|
|
108
|
+
export function rollbackScannedTriviaAt(
|
|
109
|
+
ctx: ParseContext,
|
|
110
|
+
tlogStart: number,
|
|
111
|
+
tlogEnd: number,
|
|
112
|
+
logStart: number,
|
|
113
|
+
logEnd: number,
|
|
114
|
+
rootLogStart: number,
|
|
115
|
+
rootLogEnd: number,
|
|
116
|
+
): void {
|
|
117
|
+
const b = ctx._cstBuf
|
|
118
|
+
if (b !== undefined) {
|
|
119
|
+
const tlog = b.tl
|
|
120
|
+
removeNumberRange(tlog, tlogStart, tlogEnd)
|
|
121
|
+
if (tlog !== undefined && tlog.length === 0) b.tl = undefined
|
|
122
|
+
} else {
|
|
123
|
+
removeNumberRange(ctx._cstTriviaLog, tlogStart, tlogEnd)
|
|
124
|
+
}
|
|
125
|
+
removeNumberRange(ctx._triviaLog, logStart, logEnd)
|
|
126
|
+
removeNumberRange(ctx._rootTriviaLog, rootLogStart, rootLogEnd)
|
|
127
|
+
}
|
|
128
|
+
|
|
98
129
|
function parseTriviaNoCapture(
|
|
99
130
|
triviaP: Combinator<unknown>,
|
|
100
131
|
input: string,
|
package/src/table/assemble.ts
CHANGED
|
@@ -71,18 +71,18 @@ import { projectChild, unwrapChild } from '../combinators/node.ts'
|
|
|
71
71
|
import { cstOutputHost } from '../compiler/build-arity.ts'
|
|
72
72
|
import { consumeTrivia } from '../combinators/trivia-skip.ts'
|
|
73
73
|
import {
|
|
74
|
-
advanceTrivia, needsDeferredTriviaCommit, rollbackTrivia, rollbackTriviaAt,
|
|
74
|
+
advanceTrivia, needsDeferredTriviaCommit, rollbackScannedTriviaAt, rollbackTrivia, rollbackTriviaAt,
|
|
75
75
|
saveTriviaMark, scanTrivia, skipTriviaScanned, type FastTriviaScanner,
|
|
76
76
|
} from '../combinators/trivia-skip.ts'
|
|
77
77
|
import {
|
|
78
|
-
cstCaptureActive, cstLeavesLen,
|
|
78
|
+
cstCaptureActive, cstLeavesLen, cstTlLen,
|
|
79
79
|
demoteCapturedToRaw, pushCstChild, pushCstLeaf,
|
|
80
80
|
type CstCaptureBuf,
|
|
81
81
|
} from '../cst/capture-buffer.ts'
|
|
82
82
|
import {
|
|
83
83
|
OP_CHOICE, OP_EMPTY, OP_GATE, OP_LEAF, OP_LIT, OP_NODE, OP_NOT, OP_OPT,
|
|
84
84
|
OP_PEEK, OP_REP, OP_REPV, OP_RULE, OP_RX, OP_SEQ, OP_SEQV, OP_XFORM,
|
|
85
|
-
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
85
|
+
OP_LIT_TRACK, OP_RX_TRACK, OP_NODE_TRACK, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_EXPECT, OP_SEQX, OP_SCAN,
|
|
86
86
|
OP_LIVE,
|
|
87
87
|
OP_FIELD, OP_DISPATCH, OP_ROUTED, OP_LIT_CI, OP_LIT_CI_TRACK, OP_TOKEN, OP_WITHCTX, OP_GUARD, OP_ATTEMPT, OP_LABEL,
|
|
88
88
|
OP_COV,
|
|
@@ -118,10 +118,11 @@ import { lead, rawEntry, spanLines } from './run-support.ts'
|
|
|
118
118
|
* property read per terminal miss — the same price codegen pays.
|
|
119
119
|
*/
|
|
120
120
|
import {
|
|
121
|
-
classHas, decodeClassSpec, expandCompact, resolveTable,
|
|
121
|
+
classHas, decodeClassSpec, expandCompact, resolveTable, validateDispatchSpec,
|
|
122
122
|
type CompactProgram, type ResolvedClass, type ResolvedTable,
|
|
123
123
|
type SubtreeRef, type TableProgram, type TableRule,
|
|
124
124
|
} from './program.ts'
|
|
125
|
+
import { reachableSites } from './site-labels.ts'
|
|
125
126
|
import { stampRuleMap } from './stamp.ts'
|
|
126
127
|
import { refuseUnclassifiedRootScope } from '../cst/root-trivia-scope.ts'
|
|
127
128
|
import { captureError, firstSetSentinel, matchesAt, orSentinel, recoverScan } from '../recovery/scan.ts'
|
|
@@ -662,22 +663,21 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
662
663
|
return EC.e > scanEnd ? EC.e : cur
|
|
663
664
|
}
|
|
664
665
|
// SCALAR MARKS — no per-term mark object, as `exec.ts` established.
|
|
665
|
-
const need =
|
|
666
|
-
const
|
|
667
|
-
const mTl = MTL
|
|
668
|
-
const mLv = MLV
|
|
669
|
-
const mFl = need ? ctx._fields?.length ?? 0 : 0
|
|
670
|
-
const mEr = need ? ctx._errors?.length ?? 0 : 0
|
|
666
|
+
const need = rollbackNeeded(ctx)
|
|
667
|
+
const mTl = need ? cstTlLen(ctx) : 0
|
|
671
668
|
const mLog = need ? ctx._triviaLog?.length ?? 0 : 0
|
|
672
669
|
const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0
|
|
673
670
|
const scanEnd = skipTrivia(input, cur, ctx)
|
|
671
|
+
const scanTl = need ? cstTlLen(ctx) : 0
|
|
672
|
+
const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0
|
|
673
|
+
const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0
|
|
674
674
|
const v = child(input, scanEnd, ctx)
|
|
675
675
|
if (v === FAIL) return -1
|
|
676
676
|
TERMV = v
|
|
677
677
|
if (EC.e > scanEnd) return EC.e
|
|
678
678
|
// The term matched nothing, so the trivia in front of it was never consumed
|
|
679
679
|
// by anything — unrecord it and leave the cursor where it was.
|
|
680
|
-
if (need)
|
|
680
|
+
if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot)
|
|
681
681
|
return cur
|
|
682
682
|
}
|
|
683
683
|
|
|
@@ -1212,7 +1212,8 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1212
1212
|
}
|
|
1213
1213
|
|
|
1214
1214
|
case OP_SCOPE:
|
|
1215
|
-
case OP_SCOPE_CAP:
|
|
1215
|
+
case OP_SCOPE_CAP:
|
|
1216
|
+
case OP_SCOPE_PLAIN: {
|
|
1216
1217
|
const ki = code[ip + 1]!
|
|
1217
1218
|
const scopeTrivia = ki < 0 ? undefined : (trivia[ki] as ParseContext['trivia'])
|
|
1218
1219
|
const scopeLabels = scopeTrivia?._meta.triviaKindLabels
|
|
@@ -1261,7 +1262,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
1261
1262
|
SCAN = savedScan
|
|
1262
1263
|
return v
|
|
1263
1264
|
}
|
|
1264
|
-
return scopeRootPolicy(scopePiece, code[ip + 3]!)
|
|
1265
|
+
return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]!)
|
|
1265
1266
|
}
|
|
1266
1267
|
|
|
1267
1268
|
case OP_ROUTED: {
|
|
@@ -2363,15 +2364,21 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2363
2364
|
usesRouted = routed[arm] === 1
|
|
2364
2365
|
}
|
|
2365
2366
|
|
|
2366
|
-
const savedRouted = ctx._routed
|
|
2367
2367
|
let mark = saveTriviaMark(ctx)
|
|
2368
|
+
let v: unknown
|
|
2368
2369
|
if (usesRouted) {
|
|
2370
|
+
const savedRouted = ctx._routed
|
|
2369
2371
|
rollbackTrivia(ctx, selectorMark)
|
|
2370
2372
|
mark = saveTriviaMark(ctx)
|
|
2371
2373
|
ctx._routed = { value: key, span: { start: pos, end: selEnd } }
|
|
2374
|
+
try {
|
|
2375
|
+
v = target(input, pos, ctx)
|
|
2376
|
+
} finally {
|
|
2377
|
+
ctx._routed = savedRouted
|
|
2378
|
+
}
|
|
2379
|
+
} else {
|
|
2380
|
+
v = target(input, selEnd, ctx)
|
|
2372
2381
|
}
|
|
2373
|
-
const v = target(input, usesRouted ? pos : selEnd, ctx)
|
|
2374
|
-
if (usesRouted) ctx._routed = savedRouted
|
|
2375
2382
|
if (v === FAIL) {
|
|
2376
2383
|
rollbackTrivia(ctx, mark)
|
|
2377
2384
|
// A failed dispatch branch is COMMITTED: the selector already matched.
|
|
@@ -2602,6 +2609,11 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2602
2609
|
if (s.sentinel !== undefined) extraIps.push(s.sentinel[0])
|
|
2603
2610
|
}
|
|
2604
2611
|
for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0])
|
|
2612
|
+
const validationRoots = [...Object.values(prog.rules), ...extraIps]
|
|
2613
|
+
for (const ip of reachableSites(code, validationRoots)) {
|
|
2614
|
+
if (code[ip] !== OP_DISPATCH) continue
|
|
2615
|
+
validateDispatchSpec(dsp[code[ip + 2]!], code[ip + 5]!, code[ip + 4]!)
|
|
2616
|
+
}
|
|
2605
2617
|
/**
|
|
2606
2618
|
* THE BUILD'S OWN ANSWER, TRIED BEFORE THE CONSTRUCTOR.
|
|
2607
2619
|
*
|
|
@@ -2630,7 +2642,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2630
2642
|
EC, FAIL, k, fx, fns, pools.masks, pools.classes, pools.armExpected, trivia,
|
|
2631
2643
|
trivia.map(tv => tv?._meta.triviaKindLabels), triviaScan,
|
|
2632
2644
|
scansArr, disp, dsp, EMPTY_FX, EMPTY_CH, EMPTY_TLOG, EMPTY_TL,
|
|
2633
|
-
cstCaptureActive, pushCstLeaf, pushCstChild, rollbackTriviaAt, failAt,
|
|
2645
|
+
cstCaptureActive, pushCstLeaf, pushCstChild, rollbackTriviaAt, rollbackScannedTriviaAt, failAt,
|
|
2634
2646
|
classHas, consumeTrivia, buildFieldMap, projectChild, unwrapChild,
|
|
2635
2647
|
demoteCapturedToRaw, cstLeavesLen, skipTriviaScanned, needsDeferredTriviaCommit,
|
|
2636
2648
|
scanTrivia, advanceTrivia, refuseUnclassifiedRootScope, spanLines, rawEntry, lead,
|
|
@@ -2705,7 +2717,7 @@ export function assemble(t: ResolvedTable, prog: TableProgram, cfg: RunCfg): Ass
|
|
|
2705
2717
|
EC, FAIL, k, fx, fns, em.masks, em.classes, em.armExpected, trivia,
|
|
2706
2718
|
trivia.map(tv => tv?._meta.triviaKindLabels), triviaScan,
|
|
2707
2719
|
scansArr, disp, dsp, EMPTY_FX, EMPTY_CH, EMPTY_TLOG, EMPTY_TL,
|
|
2708
|
-
cstCaptureActive, pushCstLeaf, pushCstChild, rollbackTriviaAt, failAt,
|
|
2720
|
+
cstCaptureActive, pushCstLeaf, pushCstChild, rollbackTriviaAt, rollbackScannedTriviaAt, failAt,
|
|
2709
2721
|
classHas, consumeTrivia, buildFieldMap, projectChild, unwrapChild,
|
|
2710
2722
|
demoteCapturedToRaw, cstLeavesLen, skipTriviaScanned, needsDeferredTriviaCommit,
|
|
2711
2723
|
scanTrivia, advanceTrivia, refuseUnclassifiedRootScope, spanLines, rawEntry, lead,
|
package/src/table/child-slots.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
OP_FIELD, OP_GATE, OP_GREEDY, OP_GUARD, OP_LABEL, OP_LEAF, OP_LIT, OP_LIT_CI,
|
|
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
|
-
OP_SCOPE, OP_SCOPE_CAP, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
|
|
6
|
+
OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_WITHCTX, OP_XFORM,
|
|
7
7
|
} from './ops.ts'
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -53,7 +53,7 @@ export function childSlots(code: ArrayLike<number>, ip: number, out: number[]):
|
|
|
53
53
|
return true
|
|
54
54
|
|
|
55
55
|
// Single child at `ip + 2`.
|
|
56
|
-
case OP_GATE: case OP_SCOPE: case OP_SCOPE_CAP: case OP_WITHCTX: case OP_XFORM:
|
|
56
|
+
case OP_GATE: case OP_SCOPE: case OP_SCOPE_CAP: case OP_SCOPE_PLAIN: case OP_WITHCTX: case OP_XFORM:
|
|
57
57
|
case OP_NODE: case OP_NODE_TRACK: case OP_FIELD: case OP_LEAF: case OP_ARMGATE:
|
|
58
58
|
out.push(code[ip + 2]!)
|
|
59
59
|
return true
|
|
@@ -54,9 +54,9 @@ import {
|
|
|
54
54
|
OP_ADJ, OP_ATTEMPT, OP_CHOICE, OP_DISPATCH, OP_EMPTY, OP_EXPECT, OP_FIELD, OP_GATE,
|
|
55
55
|
OP_LABEL, OP_LEAF, OP_LIT, OP_LIT_CI, OP_LIT_CI_TRACK, OP_LIT_TRACK, OP_NAMES,
|
|
56
56
|
OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT, OP_PEEK, OP_REP, OP_REPV, OP_ROUTED, OP_RULE, OP_RX,
|
|
57
|
-
OP_RX_TRACK, OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_XFORM,
|
|
57
|
+
OP_RX_TRACK, OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_XFORM,
|
|
58
58
|
} from './ops.ts'
|
|
59
|
-
import type
|
|
59
|
+
import { validateDispatchSpec, type ResolvedClass, type ResolvedTable, type TableProgram } from './program.ts'
|
|
60
60
|
import { emitShapeMatch, scanShapeFromRegex } from './scan-shapes.ts'
|
|
61
61
|
import {
|
|
62
62
|
CAP_OFF, CAP_ON, TRI_NONE, TRI_UNKNOWN, TOP, computeSiteLabels, reachableSites, type SiteLabel,
|
|
@@ -94,7 +94,7 @@ export class Unemittable extends Error {
|
|
|
94
94
|
export const EMITTED_PARAMS = [
|
|
95
95
|
'EC', 'FAIL', 'K', 'FX', 'FNS', 'MASK', 'CLS', 'AFX', 'TRIVIA', 'TRIVIALABELS', 'TRIVIASCAN',
|
|
96
96
|
'SCANS', 'DISP', 'DSP', 'EMPTY_FX', 'EMPTY_CH', 'EMPTY_TLOG', 'EMPTY_TL',
|
|
97
|
-
'cstCaptureActive', 'pushCstLeaf', 'pushCstChild', 'rollbackTriviaAt', 'failAt',
|
|
97
|
+
'cstCaptureActive', 'pushCstLeaf', 'pushCstChild', 'rollbackTriviaAt', 'rollbackScannedTriviaAt', 'failAt',
|
|
98
98
|
'classHas', 'consumeTrivia', 'buildFieldMap', 'projectChild', 'unwrapChild',
|
|
99
99
|
'demoteCapturedToRaw', 'cstLeavesLen', 'skipTriviaScanned', 'needsDeferredTriviaCommit',
|
|
100
100
|
'scanTrivia', 'advanceTrivia', 'refuseUnclassifiedRootScope', 'spanLines', 'rawEntry', 'lead',
|
|
@@ -311,19 +311,24 @@ function emitRollback(t: string, buf: boolean, s: Sinks = NO_SINKS): string {
|
|
|
311
311
|
* only the first branch, a known slot keeps only the second (with the scope's own
|
|
312
312
|
* scanner already bound into `skip`), and `TRI_UNKNOWN` keeps both.
|
|
313
313
|
*/
|
|
314
|
-
function emitTerm(callee: string, dst: string, t: string, l: SiteLabel, skip: string
|
|
314
|
+
function emitTerm(callee: string, dst: string, t: string, l: SiteLabel, skip: string): string {
|
|
315
315
|
const fast = `const ${t}v=${callee}(input,cur,ctx)
|
|
316
316
|
if(${t}v===FAIL)return FAIL
|
|
317
317
|
${dst}=${t}v
|
|
318
318
|
cur=EC.e`
|
|
319
319
|
if (l.tri === TRI_NONE) return fast
|
|
320
|
-
const scanned =
|
|
320
|
+
const scanned = `const ${t}tl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
|
|
321
|
+
const ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
322
|
+
const ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
|
|
321
323
|
const ${t}s=${skip}(input,cur,ctx)
|
|
324
|
+
const ${t}stl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
|
|
325
|
+
const ${t}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
|
|
326
|
+
const ${t}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
|
|
322
327
|
const ${t}v=${callee}(input,${t}s,ctx)
|
|
323
328
|
if(${t}v===FAIL)return FAIL
|
|
324
329
|
${dst}=${t}v
|
|
325
330
|
if(EC.e>${t}s)cur=EC.e
|
|
326
|
-
else{
|
|
331
|
+
else{rollbackScannedTriviaAt(ctx,${t}tl,${t}stl,${t}lg,${t}slg,${t}rt,${t}srt)}`
|
|
327
332
|
if (l.tri !== TRI_UNKNOWN) return scanned
|
|
328
333
|
return `if(ctx.trivia===undefined){
|
|
329
334
|
${fast}
|
|
@@ -744,7 +749,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
|
|
|
744
749
|
// `ki >= 0` is required rather than implied: `TRI_NONE` and `TRI_UNKNOWN` are
|
|
745
750
|
// themselves negative, so comparing a negative operand against a lattice
|
|
746
751
|
// element would read "unknown" as a match.
|
|
747
|
-
if (op === OP_SCOPE && code[ip + 3]! === 0 && code[ip + 1]! >= 0
|
|
752
|
+
if ((op === OP_SCOPE_PLAIN || (op === OP_SCOPE && code[ip + 3]! === 0)) && code[ip + 1]! >= 0
|
|
748
753
|
&& labels.at(ip).tri === code[ip + 1]!) {
|
|
749
754
|
return code[ip + 2]!
|
|
750
755
|
}
|
|
@@ -1016,10 +1021,11 @@ return r.value
|
|
|
1016
1021
|
}
|
|
1017
1022
|
|
|
1018
1023
|
case OP_SCOPE:
|
|
1019
|
-
case OP_SCOPE_CAP:
|
|
1024
|
+
case OP_SCOPE_CAP:
|
|
1025
|
+
case OP_SCOPE_PLAIN: {
|
|
1020
1026
|
const ki = code[ip + 1]!
|
|
1021
1027
|
const cap = op === OP_SCOPE_CAP
|
|
1022
|
-
const flags = code[ip + 3]!
|
|
1028
|
+
const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3]!
|
|
1023
1029
|
const child = link(code[ip + 2]!)
|
|
1024
1030
|
// THE SWAP, RESOLVED AT EMIT. `swapLegal` is `!trackLines`, an option;
|
|
1025
1031
|
// the other two are table data. All three are known here, so the body
|
|
@@ -1228,7 +1234,7 @@ return v
|
|
|
1228
1234
|
const vn = `v${i}`
|
|
1229
1235
|
parts.push(`let ${vn}`)
|
|
1230
1236
|
if (REC) parts.push(pub(i))
|
|
1231
|
-
parts.push(emitTerm(kids[i]!, vn, tmp(), L, skipFor(L)
|
|
1237
|
+
parts.push(emitTerm(kids[i]!, vn, tmp(), L, skipFor(L)))
|
|
1232
1238
|
names.push(vn)
|
|
1233
1239
|
}
|
|
1234
1240
|
parts.push('EC.e=cur')
|
|
@@ -1348,17 +1354,17 @@ return FAIL
|
|
|
1348
1354
|
|
|
1349
1355
|
case OP_DISPATCH: {
|
|
1350
1356
|
const di = code[ip + 2]!
|
|
1351
|
-
const spec = dsp[di]
|
|
1357
|
+
const spec = dsp[di]
|
|
1352
1358
|
const selector = link(code[ip + 1]!)
|
|
1353
1359
|
const otherIp = code[ip + 3]!
|
|
1354
1360
|
const other = otherIp >= 0 ? link(otherIp) : undefined
|
|
1355
1361
|
const otherRouted = code[ip + 4]! === 1
|
|
1356
1362
|
const n = code[ip + 5]!
|
|
1363
|
+
validateDispatchSpec(spec, n, code[ip + 4]!)
|
|
1357
1364
|
const armBase = ip + 6
|
|
1358
1365
|
const arms: string[] = []
|
|
1359
1366
|
for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]!))
|
|
1360
1367
|
const bk = hoist('bk', `DSP[${di}].byKey`)
|
|
1361
|
-
const rt = hoist('rt', `DSP[${di}].routed`)
|
|
1362
1368
|
const dx = hoist('dx', `DSP[${di}].expected`)
|
|
1363
1369
|
// THE MATCHER ARMS, AS SOURCE. `exec.ts`'s `linkMatcher` mints one
|
|
1364
1370
|
// closure per arm from four literals it already has in hand; the four
|
|
@@ -1385,6 +1391,19 @@ return FAIL
|
|
|
1385
1391
|
: ''
|
|
1386
1392
|
const m1 = tmp()
|
|
1387
1393
|
const m2 = tmp()
|
|
1394
|
+
const routedCall = (target: string): string => `{const savedRouted=ctx._routed
|
|
1395
|
+
${emitRollback(m1, L.buf, sinks)}
|
|
1396
|
+
${emitMark(m2, L.buf, sinks, false)}
|
|
1397
|
+
ctx._routed={value:key,span:{start:pos,end:selEnd}}
|
|
1398
|
+
try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
|
|
1399
|
+
break}`
|
|
1400
|
+
const plainCall = (target: string): string => `v=${target}(input,selEnd,ctx);break`
|
|
1401
|
+
const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1
|
|
1402
|
+
? routedCall(target)
|
|
1403
|
+
: plainCall(target)}`).join('\n')
|
|
1404
|
+
const fallbackCase = other === undefined ? '' : `default:${otherRouted
|
|
1405
|
+
? routedCall(other)
|
|
1406
|
+
: plainCall(other)}`
|
|
1388
1407
|
// THE SELECTOR RUNS ONCE and the key it returns picks the arm — that is
|
|
1389
1408
|
// what `dispatch()` buys over a choice of arms that each re-parse the
|
|
1390
1409
|
// opener. A routed arm rewinds the selector's trivia capture and gets
|
|
@@ -1396,24 +1415,16 @@ if(sv===FAIL)return FAIL
|
|
|
1396
1415
|
const selEnd=EC.e
|
|
1397
1416
|
const key=sv
|
|
1398
1417
|
let arm=${bk}.get(key)
|
|
1399
|
-
${fold}${chain}
|
|
1418
|
+
${fold}${chain}
|
|
1400
1419
|
if(arm===undefined){
|
|
1401
|
-
${other === undefined ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` :
|
|
1402
|
-
}else ur=${rt}[arm]===1
|
|
1403
|
-
const savedRouted=ctx._routed
|
|
1404
|
-
${emitMark(m2, L.buf, sinks)}
|
|
1405
|
-
if(ur){
|
|
1406
|
-
${emitRollback(m1, L.buf, sinks)}
|
|
1407
|
-
${emitMark(m2, L.buf, sinks, false)}
|
|
1408
|
-
ctx._routed={value:key,span:{start:pos,end:selEnd}}
|
|
1420
|
+
${other === undefined ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ''}
|
|
1409
1421
|
}
|
|
1410
|
-
|
|
1422
|
+
${emitMark(m2, L.buf, sinks)}
|
|
1411
1423
|
let v
|
|
1412
1424
|
switch(arm){
|
|
1413
|
-
${
|
|
1414
|
-
${
|
|
1425
|
+
${armCases}
|
|
1426
|
+
${fallbackCase}
|
|
1415
1427
|
}
|
|
1416
|
-
if(ur)ctx._routed=savedRouted
|
|
1417
1428
|
if(v===FAIL){
|
|
1418
1429
|
${emitRollback(m2, L.buf, sinks)}
|
|
1419
1430
|
ctx._fc=true
|
package/src/table/emit.ts
CHANGED
|
@@ -15,6 +15,17 @@ function jsString(s: string): string {
|
|
|
15
15
|
return JSON.stringify(s)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/** Emit a char-class pool in the shorter of the ordinary array and an
|
|
19
|
+
* equivalent delimiter-split string. Fall back when no delimiter is absent. */
|
|
20
|
+
function emitClassPool(classes: readonly string[]): string {
|
|
21
|
+
const array = `[${classes.map(jsString).join(',')}]`
|
|
22
|
+
if (classes.length < 2) return array
|
|
23
|
+
const delimiter = '|/~?^`'.split('').find(ch => classes.every(spec => !spec.includes(ch)))
|
|
24
|
+
if (delimiter === undefined) return array
|
|
25
|
+
const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`
|
|
26
|
+
return split.length < array.length ? split : array
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
/**
|
|
19
30
|
* Serialise one const-pool entry, or REFUSE it.
|
|
20
31
|
*
|
|
@@ -264,7 +275,7 @@ function programFields(prog: TableProgram, fns: readonly string[], opts: EmitOpt
|
|
|
264
275
|
...emitAssemblies(prog, opts.assemblies ?? []),
|
|
265
276
|
`c:[${prog.code.join(',')}],`,
|
|
266
277
|
`k:[${prog.k.map(emitConst).join(',')}],`,
|
|
267
|
-
`x
|
|
278
|
+
`x:${emitClassPool(prog.cc)},`,
|
|
268
279
|
`e:[${prog.fx.map(f => `[${f.map(jsString).join(',')}]`).join(',')}],`,
|
|
269
280
|
`d:[${prog.disp.map(a => `[${a.join(',')}]`).join(',')}],`,
|
|
270
281
|
`r:${JSON.stringify(prog.rules)},`,
|