parseman 0.47.1 → 0.48.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/README.md +27 -21
- package/dist/analysis/diagnostics.js +2863 -353
- package/dist/analysis/diagnostics.js.map +3 -3
- package/dist/cli/index.js +2854 -344
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/expect.d.ts +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/expected.d.ts +8 -0
- package/dist/combinators/expected.d.ts.map +1 -0
- package/dist/combinators/first-set.d.ts +8 -0
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/keywords.d.ts +4 -0
- package/dist/combinators/keywords.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/not.d.ts.map +1 -1
- package/dist/combinators/peek.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +16 -3
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/direct-projection.d.ts +12 -0
- package/dist/compiler/direct-projection.d.ts.map +1 -0
- package/dist/compiler/token-alphabet.d.ts +845 -5
- package/dist/compiler/token-alphabet.d.ts.map +1 -1
- package/dist/compiler/token-capability.d.ts +3 -0
- package/dist/compiler/token-capability.d.ts.map +1 -0
- package/dist/compiler/token-capability.js +3192 -0
- package/dist/compiler/token-capability.js.map +6 -0
- package/dist/cst/trivia-charscan.d.ts +3 -0
- package/dist/cst/trivia-charscan.d.ts.map +1 -1
- package/dist/cst/trivia-css-scanner.d.ts +5 -0
- package/dist/cst/trivia-css-scanner.d.ts.map +1 -0
- package/dist/cst/trivia-kinds.d.ts.map +1 -1
- package/dist/index.js +2862 -339
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.js +5 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/index.js +2870 -347
- package/dist/plugin/index.js.map +3 -3
- package/dist/spec/index.js +315 -46
- package/dist/spec/index.js.map +2 -2
- 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 -1
- package/dist/table/compile-rule-map.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts +12 -13
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/emit.d.ts.map +1 -1
- package/dist/table/encode.d.ts.map +1 -1
- package/dist/table/exec-baseline.d.ts.map +1 -1
- package/dist/table/exec.d.ts.map +1 -1
- package/dist/table/index.js +2819 -300
- package/dist/table/index.js.map +3 -3
- package/dist/table/lex-body.d.ts +9 -0
- package/dist/table/lex-body.d.ts.map +1 -0
- package/dist/table/lex-program.d.ts +25 -0
- package/dist/table/lex-program.d.ts.map +1 -0
- package/dist/table/ops.d.ts +43 -7
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/table/program.d.ts +50 -2
- package/dist/table/program.d.ts.map +1 -1
- package/dist/table/scalar-terminal.d.ts +13 -0
- package/dist/table/scalar-terminal.d.ts.map +1 -0
- package/dist/table/site-labels.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +11 -11
- package/src/combinators/expect.ts +1 -0
- package/src/combinators/expected.ts +17 -0
- package/src/combinators/first-set.ts +58 -5
- package/src/combinators/grammar.ts +8 -3
- package/src/combinators/keywords.ts +22 -6
- package/src/combinators/literal.ts +2 -1
- package/src/combinators/not.ts +5 -1
- package/src/combinators/peek.ts +5 -1
- package/src/combinators/regex.ts +5 -3
- package/src/combinators/repeat.ts +4 -10
- package/src/combinators/sequence.ts +17 -14
- package/src/combinators/trivia-skip.ts +46 -13
- package/src/compiler/direct-projection.ts +43 -0
- package/src/compiler/token-alphabet.ts +4316 -12
- package/src/compiler/token-capability.ts +6 -0
- package/src/cst/trivia-charscan.ts +34 -0
- package/src/cst/trivia-css-scanner.ts +142 -0
- package/src/cst/trivia-kinds.ts +3 -1
- package/src/plugin/index.ts +4 -4
- package/src/table/assemble.ts +1211 -221
- package/src/table/child-slots.ts +2 -1
- package/src/table/compile-rule-map.ts +21 -3
- package/src/table/emit-assembly.ts +328 -85
- package/src/table/emit.ts +16 -2
- package/src/table/encode.ts +242 -50
- package/src/table/exec-baseline.ts +3 -7
- package/src/table/exec.ts +121 -7
- package/src/table/lex-body.ts +30 -0
- package/src/table/lex-program.ts +422 -0
- package/src/table/ops.ts +45 -7
- package/src/table/program.ts +46 -2
- package/src/table/scalar-terminal.ts +51 -0
- package/src/table/site-labels.ts +11 -1
- package/src/table/stamp.ts +1 -1
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/analysis/diagnostics.cjs +0 -13824
- package/dist/analysis/diagnostics.cjs.map +0 -6
- package/dist/cli/index.cjs +0 -14925
- package/dist/cli/index.cjs.map +0 -6
- package/dist/index.cjs +0 -16391
- package/dist/index.cjs.map +0 -6
- package/dist/language-service/index.cjs +0 -1304
- package/dist/language-service/index.cjs.map +0 -6
- package/dist/oracle/index.cjs +0 -254
- package/dist/oracle/index.cjs.map +0 -6
- package/dist/plugin/index.cjs +0 -16097
- package/dist/plugin/index.cjs.map +0 -6
- package/dist/run/index.cjs +0 -577
- package/dist/run/index.cjs.map +0 -6
- package/dist/spec/index.cjs +0 -6236
- package/dist/spec/index.cjs.map +0 -6
- package/dist/table/index.cjs +0 -11463
- package/dist/table/index.cjs.map +0 -6
|
@@ -9,16 +9,11 @@
|
|
|
9
9
|
*
|
|
10
10
|
* ## Why text, and not a rearrangement of `assemble.ts`
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* megamorphic — a hash lookup in the megamorphic stub cache, no inlining, no
|
|
18
|
-
* type feedback for the callee body. No rearrangement of a file that MINTS
|
|
19
|
-
* closures can produce a distinct literal per site. Emitting one
|
|
20
|
-
* `function _pf<N>` per site can: inside `_pf12` the call `_pf7(…)` names ONE
|
|
21
|
-
* binding and stays monomorphic.
|
|
12
|
+
* Emission makes each fixed grammar edge a direct generated identifier and is
|
|
13
|
+
* also the form a build can serialise as an ordinary function literal for CSP.
|
|
14
|
+
* The closure assembler can bind the same topology directly through scalar
|
|
15
|
+
* captures; emission's distinct job is to print that binding, not to assert a
|
|
16
|
+
* V8 property that the semantic design depends on.
|
|
22
17
|
*
|
|
23
18
|
* ## What may be shared, and what must be emitted
|
|
24
19
|
*
|
|
@@ -55,12 +50,14 @@ import {
|
|
|
55
50
|
OP_LABEL, OP_LEAF, OP_LIT, OP_LIT_CI, OP_LIT_CI_TRACK, OP_LIT_TRACK, OP_NAMES,
|
|
56
51
|
OP_NODE, OP_NODE_TRACK, OP_NOT, OP_OPT, OP_PEEK, OP_REP, OP_REPV, OP_ROUTED, OP_RULE, OP_RX,
|
|
57
52
|
OP_RX_TRACK, OP_SCAN, OP_SCOPE, OP_SCOPE_CAP, OP_SCOPE_PLAIN, OP_SEQ, OP_SEQV, OP_SEQX, OP_TOKEN, OP_XFORM,
|
|
53
|
+
OP_LEX_BODY, OP_LEX_PROGRAM,
|
|
58
54
|
} from './ops.ts'
|
|
59
55
|
import { validateDispatchSpec, type ResolvedClass, type ResolvedTable, type TableProgram } from './program.ts'
|
|
60
56
|
import { emitShapeMatch, scanShapeFromRegex } from './scan-shapes.ts'
|
|
61
57
|
import {
|
|
62
|
-
CAP_OFF, CAP_ON, TRI_NONE, TRI_UNKNOWN,
|
|
58
|
+
CAP_OFF, CAP_ON, TRI_NONE, TRI_UNKNOWN, computeSiteLabels, reachableSites, type SiteLabel,
|
|
63
59
|
} from './site-labels.ts'
|
|
60
|
+
import { scalarTerminalNodeChild, scalarTerminalNotChild } from './scalar-terminal.ts'
|
|
64
61
|
|
|
65
62
|
/** What the compiled factory hands back — the emitted twin of `Assembly`. */
|
|
66
63
|
export type EmittedPiece = (input: string, pos: number, ctx: ParseContext) => unknown
|
|
@@ -106,6 +103,16 @@ export const EMITTED_PARAMS = [
|
|
|
106
103
|
// span, expected set and CST embedding are produced by the SAME code in every
|
|
107
104
|
// engine and cannot drift.
|
|
108
105
|
'SENTS', 'matchesAt', 'recoverScan', 'orSentinel', 'captureError',
|
|
106
|
+
// Pure scalar terminal recognizers, indexed by the terminal's existing const
|
|
107
|
+
// operand. Appended for compatibility with older precompiled factories.
|
|
108
|
+
'RECOG',
|
|
109
|
+
// Appended so precompiled factories produced by earlier runtimes keep every
|
|
110
|
+
// positional helper binding. Older factories ignore this trailing argument.
|
|
111
|
+
'commitTriviaScan', 'scanTriviaCompact', 'LEX',
|
|
112
|
+
// Appended for old precompiled-factory ABI: old factories ignore it.
|
|
113
|
+
'adjacencyHolds',
|
|
114
|
+
// Appended for selected composite lexical programs; old factories ignore it.
|
|
115
|
+
'LEXPROG',
|
|
109
116
|
] as const
|
|
110
117
|
|
|
111
118
|
/**
|
|
@@ -131,7 +138,7 @@ function _skipTrivia(input,cur,ctx){
|
|
|
131
138
|
const s=_pfScan
|
|
132
139
|
if(s!==null&&ctx._triviaLog===undefined&&!(ctx.captureTrivia===true&&(ctx._cstBuf!==undefined||ctx._cstTriviaLog!==undefined)))return s(input,cur)
|
|
133
140
|
if(s!==null)return skipTriviaScanned(s,input,cur,ctx)
|
|
134
|
-
if(needsDeferredTriviaCommit(ctx))
|
|
141
|
+
if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
|
|
135
142
|
return advanceTrivia(input,cur,ctx)
|
|
136
143
|
}
|
|
137
144
|
function _pushLeaf(ctx,value,s,e){pushCstLeaf(ctx,{_tag:'leaf',value,span:{start:s,end:e}})}
|
|
@@ -145,6 +152,13 @@ if(b.raw!==undefined)b.raw.push(l)
|
|
|
145
152
|
else if(b.rawSingle!==undefined){b.raw=[b.rawSingle,l];b.rawSingle=undefined}
|
|
146
153
|
else b.rawSingle=l
|
|
147
154
|
}
|
|
155
|
+
function _capturedFlatChildren(children){
|
|
156
|
+
if(children.length===0)return EMPTY_CH
|
|
157
|
+
if(children[0]!==undefined)return children
|
|
158
|
+
let first=1
|
|
159
|
+
while(first<children.length&&children[first]===undefined)first++
|
|
160
|
+
return first===children.length?EMPTY_CH:children.slice(first)
|
|
161
|
+
}
|
|
148
162
|
function _accSet(ax,acc){
|
|
149
163
|
if(ax===undefined||ax.length===0)return acc
|
|
150
164
|
if(acc===undefined)return ax.slice()
|
|
@@ -370,7 +384,11 @@ export type PoolPlan = {
|
|
|
370
384
|
readonly classes: readonly (readonly number[])[]
|
|
371
385
|
/** Per `AFX` row: the `fx` index of each arm's expected set. */
|
|
372
386
|
readonly armExpected: readonly (readonly number[])[]
|
|
373
|
-
/**
|
|
387
|
+
/**
|
|
388
|
+
* Per `MASK` row: a non-negative legacy `CLS` row index, or `~dispIndex` for
|
|
389
|
+
* a directly bound choice. The negative form names the EXISTING resolved
|
|
390
|
+
* dispatch row rather than serialising a second copy of its arm classes.
|
|
391
|
+
*/
|
|
374
392
|
readonly masks: readonly number[]
|
|
375
393
|
}
|
|
376
394
|
|
|
@@ -408,13 +426,18 @@ function maskForClassRow(gates: readonly (ResolvedClass | null)[]): Uint32Array
|
|
|
408
426
|
export function rebuildPools(
|
|
409
427
|
cc: readonly ResolvedClass[],
|
|
410
428
|
fx: readonly (readonly string[])[],
|
|
429
|
+
disp: ResolvedTable['disp'],
|
|
411
430
|
plan: PoolPlan,
|
|
412
431
|
): { masks: Uint32Array[]; classes: (ResolvedClass | null)[][]; armExpected: (readonly string[])[][] } {
|
|
413
432
|
const classes = plan.classes.map(row => row.map(i => (i < 0 ? null : cc[i] ?? null)))
|
|
414
433
|
return {
|
|
415
434
|
classes,
|
|
416
435
|
armExpected: plan.armExpected.map(row => row.map(i => fx[i] ?? [])),
|
|
417
|
-
masks: plan.masks.map(
|
|
436
|
+
masks: plan.masks.map(source => {
|
|
437
|
+
const row = source >= 0 ? classes[source] : disp[~source]?.armCls
|
|
438
|
+
if (row === undefined) throw new TypeError(`table emitter: invalid MASK plan source ${source}`)
|
|
439
|
+
return maskForClassRow(row)
|
|
440
|
+
}),
|
|
418
441
|
}
|
|
419
442
|
}
|
|
420
443
|
|
|
@@ -476,6 +499,17 @@ export function emitAssemblySource(
|
|
|
476
499
|
// emitted scope supplies a context this pass cannot see.
|
|
477
500
|
const roots = [...Object.values(prog.rules), ...extraIps]
|
|
478
501
|
const labels = computeSiteLabels(code, roots, hostCst)
|
|
502
|
+
// Eligibility is pooled by the terminal's existing constant operand, matching
|
|
503
|
+
// the closure recognizer pool: distinct terminal rows sharing one spec share
|
|
504
|
+
// both the recognizer and the ordinary-terminal lowering.
|
|
505
|
+
const scalarSpecs = new Set<number>()
|
|
506
|
+
if (!hostCst && !cfg.tolerant && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
|
|
507
|
+
for (const ip of reachableSites(code, roots)) {
|
|
508
|
+
if (code[ip] !== OP_NODE) continue
|
|
509
|
+
const child = scalarTerminalNodeChild(code, ip)
|
|
510
|
+
if (child >= 0) scalarSpecs.add(code[child + 1]!)
|
|
511
|
+
}
|
|
512
|
+
}
|
|
479
513
|
|
|
480
514
|
// THE SIDE-SINK CENSUS, over the same reachable set the labels are computed
|
|
481
515
|
// from. `OP_FIELD` is the only ROW that writes `_fields` and `OP_EXPECT` the
|
|
@@ -520,6 +554,7 @@ export function emitAssemblySource(
|
|
|
520
554
|
const reached = new Set<number>()
|
|
521
555
|
const prelude: string[] = []
|
|
522
556
|
const skipDefs: string[] = []
|
|
557
|
+
const choiceDefs: string[] = []
|
|
523
558
|
const skipPool = new Map<string, string>()
|
|
524
559
|
const pool = new Map<string, string>()
|
|
525
560
|
const masks: Uint32Array[] = []
|
|
@@ -548,6 +583,7 @@ export function emitAssemblySource(
|
|
|
548
583
|
const kRef = (i: number): string => hoist('k', `K[${i}]`)
|
|
549
584
|
const fxRef = (i: number): string => hoist('fx', `FX[${i}]`)
|
|
550
585
|
const fnRef = (i: number): string => hoist('fn', `FNS[${i}]`)
|
|
586
|
+
const recognizerRef = (i: number): string => hoist('rec', `RECOG[${i}]`)
|
|
551
587
|
/**
|
|
552
588
|
* The sync sentinel for a char-class index, hoisted once per class.
|
|
553
589
|
*
|
|
@@ -598,9 +634,9 @@ export function emitAssemblySource(
|
|
|
598
634
|
// through `scanTrivia`. `needsDeferredTriviaCommit` is implied by an open
|
|
599
635
|
// buffer, so an in-node site skips the call that asks.
|
|
600
636
|
skipDefs.push(l.buf
|
|
601
|
-
? `function ${nm}(input,cur,ctx){
|
|
637
|
+
? `function ${nm}(input,cur,ctx){return commitTriviaScan(scanTriviaCompact(input,cur,ctx))}`
|
|
602
638
|
: `function ${nm}(input,cur,ctx){
|
|
603
|
-
if(needsDeferredTriviaCommit(ctx))
|
|
639
|
+
if(needsDeferredTriviaCommit(ctx))return commitTriviaScan(scanTriviaCompact(input,cur,ctx))
|
|
604
640
|
return advanceTrivia(input,cur,ctx)}`)
|
|
605
641
|
return nm
|
|
606
642
|
}
|
|
@@ -734,17 +770,17 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
|
|
|
734
770
|
if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2]!
|
|
735
771
|
if (op === OP_RULE) return code[ip + 1]!
|
|
736
772
|
// A SCOPE THAT INSTALLS WHAT IS ALREADY INSTALLED. `encode.ts:520` wraps
|
|
737
|
-
// EVERY rule of a `rules({ trivia }, …)` map in its own `
|
|
773
|
+
// EVERY rule of a `rules({ trivia }, …)` map in its own `OP_SCOPE_PLAIN`, so a
|
|
738
774
|
// grammar with one ambient trivia re-installs the same slot at every rule
|
|
739
775
|
// entry — six context stores, a scanner swap and their six restores, per
|
|
740
776
|
// call, to arrive at the values already there.
|
|
741
777
|
//
|
|
742
778
|
// The label is what makes this decidable: `tri >= 0` can ONLY have come from
|
|
743
|
-
// an enclosing
|
|
779
|
+
// an enclosing scope carrying that slot, and that scope set
|
|
744
780
|
// `ctx.triviaKindLabels` and `_pfScan` from the same slot, so all three are
|
|
745
|
-
// already the values this row would write.
|
|
746
|
-
//
|
|
747
|
-
//
|
|
781
|
+
// already the values this row would write. `OP_SCOPE_PLAIN` has no root
|
|
782
|
+
// policy by construction; a policy-bearing `OP_SCOPE` aliases only when its
|
|
783
|
+
// literal policy is zero. `OP_SCOPE_CAP` also raises `captureTrivia`.
|
|
748
784
|
//
|
|
749
785
|
// `ki >= 0` is required rather than implied: `TRI_NONE` and `TRI_UNKNOWN` are
|
|
750
786
|
// themselves negative, so comparing a negative operand against a lattice
|
|
@@ -788,6 +824,19 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
|
|
|
788
824
|
const s = k[code[ip + 1]!] as string
|
|
789
825
|
const xf = fxRef(code[ip + 2]!)
|
|
790
826
|
const track = op === OP_LIT_TRACK
|
|
827
|
+
if (!track && scalarSpecs.has(code[ip + 1]!)) {
|
|
828
|
+
const recognize = recognizerRef(code[ip + 1]!)
|
|
829
|
+
return `${head}
|
|
830
|
+
const e=${recognize}(input,pos)
|
|
831
|
+
if(e>=0){
|
|
832
|
+
${captureLeaf(q(s))}
|
|
833
|
+
EC.e=e
|
|
834
|
+
return ${q(s)}
|
|
835
|
+
}
|
|
836
|
+
ctx._fe=pos;ctx._fx=${xf}
|
|
837
|
+
return FAIL
|
|
838
|
+
}`
|
|
839
|
+
}
|
|
791
840
|
// LENGTH IS TABLE DATA, so the compare is chosen here — the emitted twin
|
|
792
841
|
// of the closure engine's length-keyed literal bodies.
|
|
793
842
|
const test = s.length === 1
|
|
@@ -862,6 +911,20 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)\n` : ''}return FAIL
|
|
|
862
911
|
case OP_RX_TRACK: {
|
|
863
912
|
const xf = fxRef(code[ip + 2]!)
|
|
864
913
|
const track = op === OP_RX_TRACK
|
|
914
|
+
if (!track && scalarSpecs.has(code[ip + 1]!)) {
|
|
915
|
+
const recognize = recognizerRef(code[ip + 1]!)
|
|
916
|
+
return `${head}
|
|
917
|
+
const e=${recognize}(input,pos)
|
|
918
|
+
if(e>=0){
|
|
919
|
+
const v=input.slice(pos,e)
|
|
920
|
+
${captureLeaf('v')}
|
|
921
|
+
EC.e=e
|
|
922
|
+
return v
|
|
923
|
+
}
|
|
924
|
+
ctx._fe=pos;ctx._fx=${xf}
|
|
925
|
+
return FAIL
|
|
926
|
+
}`
|
|
927
|
+
}
|
|
865
928
|
// THE MATCH ARRAY IS THE COST, not the matching. `re.exec` allocates one
|
|
866
929
|
// per row — 6,005 rows per `json/document` parse, 12.9% of everything
|
|
867
930
|
// executed — and every field of it but `[0]` is discarded here. A shape
|
|
@@ -1109,6 +1172,75 @@ return out
|
|
|
1109
1172
|
}`
|
|
1110
1173
|
}
|
|
1111
1174
|
|
|
1175
|
+
case OP_LEX_BODY: {
|
|
1176
|
+
const recognize = hoist('lex', `LEX[${code[ip + 1]!}]`)
|
|
1177
|
+
const expected = fxRef(code[ip + 2]!)
|
|
1178
|
+
const suffixExpected = fxRef(code[ip + 3]!)
|
|
1179
|
+
const lineFlags = code[ip + 4]!
|
|
1180
|
+
const hasSuffix = (lineFlags & 4) !== 0
|
|
1181
|
+
return `${head}
|
|
1182
|
+
const r=${recognize}(input,pos)
|
|
1183
|
+
if(r<0){ctx._fe=pos;ctx._fx=${expected};if(ctx._probe!==undefined)failAt(ctx,${expected},pos);return FAIL}
|
|
1184
|
+
const sm=${hasSuffix ? 'r%2===1' : 'false'},e=(r-(sm?1:0))/2
|
|
1185
|
+
${(lineFlags & 1) !== 0 ? '_trackLines(ctx,input,sm?e-1:e)' : ''}
|
|
1186
|
+
${hasSuffix ? 'ctx._fc=false' : ''}
|
|
1187
|
+
${hasSuffix && (lineFlags & 2) !== 0 ? 'if(sm)_trackLines(ctx,input,e)' : ''}
|
|
1188
|
+
${hasSuffix ? `if(!sm){ctx._fe=e;ctx._fx=${suffixExpected};if(ctx._probe!==undefined)failAt(ctx,${suffixExpected},e)}` : ''}
|
|
1189
|
+
const v=input.slice(pos,e)
|
|
1190
|
+
if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
|
|
1191
|
+
EC.e=e
|
|
1192
|
+
return v
|
|
1193
|
+
}`
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
case OP_LEX_PROGRAM: {
|
|
1197
|
+
const programId = code[ip + 1]!
|
|
1198
|
+
const run = hoist('lexProgram', `LEXPROG[${programId}]`)
|
|
1199
|
+
const scanId = t.lexPrograms[programId]!.scan
|
|
1200
|
+
if (scanId !== undefined) return `${head}
|
|
1201
|
+
const sTri=ctx.trivia,sKinds=ctx.triviaKindLabels,sScan=_pfScan
|
|
1202
|
+
const sBuf=ctx._cstBuf,sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
|
|
1203
|
+
const sOtl=ctx._triviaLog,sRtl=ctx._rootTriviaLog
|
|
1204
|
+
const wasCap=ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined
|
|
1205
|
+
_pfScan=null
|
|
1206
|
+
ctx.trivia=undefined
|
|
1207
|
+
ctx.triviaKindLabels=undefined
|
|
1208
|
+
ctx._cstBuf=undefined
|
|
1209
|
+
ctx._cstChildren=undefined
|
|
1210
|
+
ctx._cstLeaves=undefined
|
|
1211
|
+
ctx._cstRawChildren=undefined
|
|
1212
|
+
ctx._cstTriviaLog=undefined
|
|
1213
|
+
ctx._triviaLog=undefined
|
|
1214
|
+
ctx._rootTriviaLog=undefined
|
|
1215
|
+
let e
|
|
1216
|
+
try{e=${run}(input,pos,ctx,SCANS[${scanId}])}finally{
|
|
1217
|
+
_pfScan=sScan
|
|
1218
|
+
ctx.trivia=sTri
|
|
1219
|
+
ctx.triviaKindLabels=sKinds
|
|
1220
|
+
ctx._cstBuf=sBuf
|
|
1221
|
+
ctx._cstChildren=sCh
|
|
1222
|
+
ctx._cstLeaves=sLv
|
|
1223
|
+
ctx._cstRawChildren=sRaw
|
|
1224
|
+
ctx._cstTriviaLog=sTl
|
|
1225
|
+
ctx._triviaLog=sOtl
|
|
1226
|
+
ctx._rootTriviaLog=sRtl
|
|
1227
|
+
}
|
|
1228
|
+
if(e<0)return FAIL
|
|
1229
|
+
const v=input.slice(pos,e)
|
|
1230
|
+
if(wasCap)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
|
|
1231
|
+
EC.e=e
|
|
1232
|
+
return v
|
|
1233
|
+
}`
|
|
1234
|
+
return `${head}
|
|
1235
|
+
const e=${run}(input,pos,ctx)
|
|
1236
|
+
if(e<0)return FAIL
|
|
1237
|
+
const v=input.slice(pos,e)
|
|
1238
|
+
if(ctx._cstBuf!==undefined||ctx._cstLeaves!==undefined)pushCstLeaf(ctx,{_tag:'leaf',value:v,span:{start:pos,end:e}})
|
|
1239
|
+
EC.e=e
|
|
1240
|
+
return v
|
|
1241
|
+
}`
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1112
1244
|
/* ── transaction ─────────────────────────────────────────────────────── */
|
|
1113
1245
|
|
|
1114
1246
|
case OP_ATTEMPT: {
|
|
@@ -1126,6 +1258,18 @@ return FAIL
|
|
|
1126
1258
|
}
|
|
1127
1259
|
|
|
1128
1260
|
case OP_NOT: {
|
|
1261
|
+
const scalarChild = scalarTerminalNotChild(code, ip)
|
|
1262
|
+
if (scalarChild >= 0) {
|
|
1263
|
+
const recognize = recognizerRef(code[scalarChild + 1]!)
|
|
1264
|
+
const xf = fxRef(code[ip + 2]!)
|
|
1265
|
+
return `${head}
|
|
1266
|
+
if(${recognize}(input,pos)<0){EC.e=pos;return null}
|
|
1267
|
+
ctx._fe=pos
|
|
1268
|
+
ctx._fx=${xf}
|
|
1269
|
+
EC.e=pos
|
|
1270
|
+
return FAIL
|
|
1271
|
+
}`
|
|
1272
|
+
}
|
|
1129
1273
|
const child = link(code[ip + 1]!)
|
|
1130
1274
|
const xf = fxRef(code[ip + 2]!)
|
|
1131
1275
|
const p = tmp()
|
|
@@ -1178,19 +1322,14 @@ return v
|
|
|
1178
1322
|
const base = fused ? ip + 3 : ip + 2
|
|
1179
1323
|
const n = code[fused ? ip + 2 : ip + 1]!
|
|
1180
1324
|
const wantValues = op !== OP_SEQV
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
// position finds the gap already consumed and answers "adjacent" every
|
|
1185
|
-
// time, SILENTLY (`ops.ts:226-251`).
|
|
1186
|
-
for (let i = 1; i < n; i++) {
|
|
1187
|
-
if (code[code[base + i]!] === OP_ADJ) {
|
|
1188
|
-
throw new Unemittable('a sequence carrying an adjacency assertion (OP_ADJ)')
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
const fn = fused ? fnRef(code[ip + 1]!) : undefined
|
|
1325
|
+
const reducer = fused ? code[ip + 1]! : -1
|
|
1326
|
+
const projection = reducer < 0 ? ~reducer : -1
|
|
1327
|
+
const fn = fused && projection < 0 ? fnRef(reducer) : undefined
|
|
1192
1328
|
const kids: string[] = []
|
|
1193
|
-
for (let i = 0; i < n; i++)
|
|
1329
|
+
for (let i = 0; i < n; i++) {
|
|
1330
|
+
const childIp = code[base + i]!
|
|
1331
|
+
kids.push(code[childIp] === OP_ADJ ? '' : link(childIp))
|
|
1332
|
+
}
|
|
1194
1333
|
/**
|
|
1195
1334
|
* A RECOVERY SEQUENCE PUBLISHES `ctx._sync`, and that is the WHOLE of
|
|
1196
1335
|
* "recovery config" — no grammar carries any (`assemble.ts:1446`).
|
|
@@ -1225,7 +1364,9 @@ return v
|
|
|
1225
1364
|
parts.push(`const v0=${kids[0]}(input,pos,ctx)`, 'if(v0===FAIL)return FAIL')
|
|
1226
1365
|
const close = (): string => REC ? `${parts.join('\n')}\n}finally{ctx._sync=${sy}}\n}` : `${parts.join('\n')}\n}`
|
|
1227
1366
|
if (n === 1) {
|
|
1228
|
-
parts.push(fused
|
|
1367
|
+
parts.push(fused
|
|
1368
|
+
? projection === 0 ? 'return v0' : `return ${fn}([v0],{start:pos,end:EC.e})`
|
|
1369
|
+
: wantValues ? 'return [v0]' : 'return undefined')
|
|
1229
1370
|
return close()
|
|
1230
1371
|
}
|
|
1231
1372
|
parts.push('let cur=EC.e')
|
|
@@ -1234,12 +1375,22 @@ return v
|
|
|
1234
1375
|
const vn = `v${i}`
|
|
1235
1376
|
parts.push(`let ${vn}`)
|
|
1236
1377
|
if (REC) parts.push(pub(i))
|
|
1237
|
-
|
|
1378
|
+
const childIp = code[base + i]!
|
|
1379
|
+
if (code[childIp] === OP_ADJ) {
|
|
1380
|
+
const negated = code[childIp + 1] === 1
|
|
1381
|
+
const ki = code[childIp + 2]!
|
|
1382
|
+
const kinds = ki < 0 ? 'undefined' : `K[${ki}]`
|
|
1383
|
+
const expected = fxRef(code[childIp + 3]!)
|
|
1384
|
+
parts.push(
|
|
1385
|
+
`if(!adjacencyHolds(input,cur,ctx,${negated ? 'true' : 'false'},${kinds})){ctx._fe=cur;ctx._fx=${expected};return FAIL}`,
|
|
1386
|
+
`${vn}=null`,
|
|
1387
|
+
)
|
|
1388
|
+
} else parts.push(emitTerm(kids[i]!, vn, tmp(), L, skipFor(L)))
|
|
1238
1389
|
names.push(vn)
|
|
1239
1390
|
}
|
|
1240
1391
|
parts.push('EC.e=cur')
|
|
1241
1392
|
parts.push(fused
|
|
1242
|
-
? `return ${fn}([${names.join(',')}],{start:pos,end:cur})`
|
|
1393
|
+
? projection >= 0 ? `return ${names[projection]}` : `return ${fn}([${names.join(',')}],{start:pos,end:cur})`
|
|
1243
1394
|
: wantValues ? `return [${names.join(',')}]` : 'return undefined')
|
|
1244
1395
|
return close()
|
|
1245
1396
|
}
|
|
@@ -1251,11 +1402,6 @@ return v
|
|
|
1251
1402
|
const base = ip + 4
|
|
1252
1403
|
const arms: string[] = []
|
|
1253
1404
|
for (let i = 0; i < n; i++) arms.push(link(code[base + i]!))
|
|
1254
|
-
const axi = armExpected.push(
|
|
1255
|
-
Array.from({ length: n }, (_, i) => t.fx[code[base + n + i]!] as readonly string[]),
|
|
1256
|
-
) - 1
|
|
1257
|
-
armExpectedPlan.push(Array.from({ length: n }, (_, i) => code[base + n + i]!))
|
|
1258
|
-
const afx = hoist('afx', `AFX[${axi}]`)
|
|
1259
1405
|
|
|
1260
1406
|
if (table.exclusive) {
|
|
1261
1407
|
// NO OPEN ARMS EXIST under `exclusive` — `resolveDispatch` clears the
|
|
@@ -1289,52 +1435,51 @@ return FAIL
|
|
|
1289
1435
|
}`
|
|
1290
1436
|
}
|
|
1291
1437
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
//
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
if((bits&${1 << i})!==0){
|
|
1438
|
+
{
|
|
1439
|
+
// Direct topology for every fixed arity. The emitted body names every
|
|
1440
|
+
// child, gate and expected set; no AFX/CLS row survives merely to feed
|
|
1441
|
+
// an indexed winner back into one call site.
|
|
1442
|
+
const di = code[ip + 1]!
|
|
1443
|
+
const expected = Array.from({ length: n }, (_, i) => fxRef(code[base + n + i]!))
|
|
1444
|
+
const gates = Array.from({ length: n }, (_, i) => table.armCls[i] ?? null)
|
|
1445
|
+
const gateRefs = Array.from({ length: n }, (_, i) => hoist('g', `DISP[${di}].armCls[${i}]`))
|
|
1446
|
+
const maskable = n <= 32
|
|
1447
|
+
const maskName = maskable
|
|
1448
|
+
? hoist('mk', `MASK[${masks.push(maskForClassRow(gates)) - 1}]`)
|
|
1449
|
+
: ''
|
|
1450
|
+
// `~di` points back to the authoritative dispatch row. A precompiled
|
|
1451
|
+
// module reconstructs only the input-indexed mask from that row; it
|
|
1452
|
+
// cannot carry a second mutable answer for the arms' classes.
|
|
1453
|
+
if (maskable) maskPlan.push(~di)
|
|
1454
|
+
const p = tmp()
|
|
1455
|
+
const catchName = maskable ? `_cx${uid++}_` : ''
|
|
1456
|
+
if (maskable) {
|
|
1457
|
+
const catchCases = expected.map((e, i) =>
|
|
1458
|
+
`case ${i}:if(target<=${i})return acc;acc=_accSet(${e},acc)`).join('\n')
|
|
1459
|
+
choiceDefs.push(`function ${catchName}(target,prev,acc){switch(prev){\n${catchCases}\n}return acc}`)
|
|
1460
|
+
}
|
|
1461
|
+
const maskArms = maskable ? arms.map((arm, i) => {
|
|
1462
|
+
return `if((bits&${1 << i})!==0){
|
|
1317
1463
|
ctx._fc=false
|
|
1318
|
-
{const v=${
|
|
1464
|
+
{const v=${arm}(input,pos,ctx)
|
|
1319
1465
|
if(v!==FAIL)return v}
|
|
1320
|
-
|
|
1466
|
+
acc=${catchName}(${i},prev,acc)
|
|
1321
1467
|
prev=${i + 1}
|
|
1322
1468
|
acc=_accSet(ctx._fx,acc)
|
|
1323
1469
|
if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
|
|
1324
1470
|
${emitRollback(p, L.buf, sinks)}
|
|
1325
|
-
}`
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
if(${gRef}[${i}]===null||classHas(${gRef}[${i}],c)){
|
|
1471
|
+
}`
|
|
1472
|
+
}).join('\n') : ''
|
|
1473
|
+
const generalArms = arms.map((arm, i) => `if(${gateRefs[i]}===null||classHas(${gateRefs[i]},c)){
|
|
1329
1474
|
ctx._fc=false
|
|
1330
|
-
{const v=${
|
|
1475
|
+
{const v=${arm}(input,pos,ctx)
|
|
1331
1476
|
if(v!==FAIL)return v}
|
|
1332
1477
|
acc=_accSet(ctx._fx,acc)
|
|
1333
1478
|
if(ctx._fc===true){if(acc!==undefined)ctx._fx=acc;return FAIL}
|
|
1334
1479
|
${emitRollback(p, L.buf, sinks)}
|
|
1335
|
-
}else acc=_accSet(${
|
|
1480
|
+
}else acc=_accSet(${expected[i]},acc)`).join('\n')
|
|
1336
1481
|
|
|
1337
|
-
|
|
1482
|
+
return `${head}
|
|
1338
1483
|
const c=lead(input,pos)
|
|
1339
1484
|
${emitMark(p, L.buf, sinks)}
|
|
1340
1485
|
let acc
|
|
@@ -1342,14 +1487,17 @@ ${maskable ? `if(c<128){
|
|
|
1342
1487
|
const bits=${maskName}[c<0?128:c]
|
|
1343
1488
|
let prev=0
|
|
1344
1489
|
${maskArms}
|
|
1345
|
-
|
|
1490
|
+
acc=${catchName}(${n},prev,acc)
|
|
1346
1491
|
ctx._fe=pos;ctx._fx=acc??${choiceFx}
|
|
1347
1492
|
return FAIL
|
|
1348
1493
|
}
|
|
1349
|
-
` : ''}
|
|
1494
|
+
` : ''}
|
|
1495
|
+
${generalArms}
|
|
1350
1496
|
ctx._fe=pos;ctx._fx=acc??${choiceFx}
|
|
1351
1497
|
return FAIL
|
|
1352
1498
|
}`
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1353
1501
|
}
|
|
1354
1502
|
|
|
1355
1503
|
case OP_DISPATCH: {
|
|
@@ -1371,16 +1519,26 @@ return FAIL
|
|
|
1371
1519
|
// are TABLE DATA, so here they are the test itself and no closure, no
|
|
1372
1520
|
// pool and no indexed call exist. Kinds are `matcherClaims`'s exactly
|
|
1373
1521
|
// — 0/1 raw prefix/suffix, 3/4 the pre-folded pair, anything else a
|
|
1374
|
-
// regex.
|
|
1375
|
-
//
|
|
1376
|
-
//
|
|
1522
|
+
// regex. Public `matches()` refuses global/sticky patterns, so its
|
|
1523
|
+
// RegExp can be compiled once into the assembly prelude. Hand-built
|
|
1524
|
+
// low-level rows with g/y or invalid flags retain the old per-test
|
|
1525
|
+
// construction and therefore the old `lastIndex`/throw behavior.
|
|
1377
1526
|
const claims = (m: readonly [number, string, string, number]): string => {
|
|
1378
1527
|
switch (m[0]) {
|
|
1379
1528
|
case 0: return `key.startsWith(${q(m[1])})`
|
|
1380
1529
|
case 1: return `key.endsWith(${q(m[1])})`
|
|
1381
1530
|
case 3: return `asciiFoldKey(key).startsWith(${q(m[1])})`
|
|
1382
1531
|
case 4: return `asciiFoldKey(key).endsWith(${q(m[1])})`
|
|
1383
|
-
default:
|
|
1532
|
+
default: {
|
|
1533
|
+
if (!m[2].includes('g') && !m[2].includes('y')) {
|
|
1534
|
+
try {
|
|
1535
|
+
// Validate without changing malformed-row error timing.
|
|
1536
|
+
new RegExp(m[1], m[2])
|
|
1537
|
+
return `${hoist('dm', `new RegExp(${q(m[1])},${q(m[2])})`)}.test(key)`
|
|
1538
|
+
} catch {}
|
|
1539
|
+
}
|
|
1540
|
+
return `new RegExp(${q(m[1])},${q(m[2])}).test(key)`
|
|
1541
|
+
}
|
|
1384
1542
|
}
|
|
1385
1543
|
}
|
|
1386
1544
|
const chain = spec.match.length === 0
|
|
@@ -1447,6 +1605,15 @@ return [key,v]
|
|
|
1447
1605
|
const reportItem = (flags & 4) !== 0
|
|
1448
1606
|
const itemFx = reportItem ? fxRef(code[ip + 6]!) : 'EMPTY_FX'
|
|
1449
1607
|
const collect = op === OP_REP
|
|
1608
|
+
let itemCls: string | undefined
|
|
1609
|
+
if (!REC) {
|
|
1610
|
+
const itemClassIndex = sepIp < 0 ? code[ip + 7]! : -1
|
|
1611
|
+
if (itemClassIndex >= 0) {
|
|
1612
|
+
const ci = classes.push([t.cc[itemClassIndex]!]) - 1
|
|
1613
|
+
classPlan.push([itemClassIndex])
|
|
1614
|
+
itemCls = hoist('ri', `CLS[${ci}][0]`)
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1450
1617
|
const skipBeforeFirst = sepIp < 0 && min === 0
|
|
1451
1618
|
const p = tmp()
|
|
1452
1619
|
// `viaRepItem` is `sep === undefined && count >= min && (count > 0 ||
|
|
@@ -1466,7 +1633,6 @@ return [key,v]
|
|
|
1466
1633
|
const skip = skipFor(L)
|
|
1467
1634
|
const knownTrivia = L.tri === TRI_NONE ? false : L.tri !== TRI_UNKNOWN ? true : undefined
|
|
1468
1635
|
const hasTrivia = knownTrivia === undefined ? 'hasTrivia' : String(knownTrivia)
|
|
1469
|
-
const needMark = L.buf ? 'true' : 'needMark'
|
|
1470
1636
|
// THE `_fields` AND `_errors` MARKS ARE TAKEN ONLY WHERE THE TABLE HAS A
|
|
1471
1637
|
// WRITER, which is the same emit-time census `emitMark` applies to the
|
|
1472
1638
|
// non-loop marks. Before `OP_FIELD` and `OP_EXPECT` were emittable the
|
|
@@ -1552,10 +1718,10 @@ continue
|
|
|
1552
1718
|
`
|
|
1553
1719
|
return `${head}
|
|
1554
1720
|
const out=${collect ? '[]' : 'undefined'}
|
|
1555
|
-
${knownTrivia === undefined ? 'const hasTrivia=ctx.trivia!==undefined\n' : ''}${L.buf ? '' : 'const needMark=_rollbackNeeded(ctx)\n'}${REC ? `const ${my}=ctx._sync\n` : ''}let cur=pos
|
|
1721
|
+
${knownTrivia === undefined ? 'const hasTrivia=ctx.trivia!==undefined\n' : ''}${L.buf ? '' : 'const needMark=_rollbackNeeded(ctx)\n'}${REC ? `const ${my}=ctx._sync\n` : ''}${itemCls === undefined ? '' : `const ${p}gate=ctx._probe===undefined\n`}let cur=pos
|
|
1556
1722
|
let count=0
|
|
1557
1723
|
for(;;){
|
|
1558
|
-
${max >= 0 ? `if(count>=${max})break\n` : ''}${sep !== undefined ? `if(count>0&&count>=${min}&&cur>=input.length)break\n` : ''}let ${p}raw=0,${p}tl=0,${p}lv=0,${p}lg=0,${p}rt=0${sinks.fd ? `,${p}fd=0` : ''}${sinks.er ? `,${p}er=0` : ''}
|
|
1724
|
+
${max >= 0 ? `if(count>=${max})break\n` : ''}${sep !== undefined ? `if(count>0&&count>=${min}&&cur>=input.length)break\n` : ''}${itemCls !== undefined && sep === undefined ? `if(count>=${min}&&${p}gate&&${hasTrivia === 'false' ? 'true' : hasTrivia === 'true' ? 'false' : '!hasTrivia'}&&!classHas(${itemCls},lead(input,cur)))break\n` : ''}let ${p}raw=0,${p}tl=0,${p}lv=0,${p}lg=0,${p}rt=0${sinks.fd ? `,${p}fd=0` : ''}${sinks.er ? `,${p}er=0` : ''}
|
|
1559
1725
|
${markBody}
|
|
1560
1726
|
let itemStart=cur
|
|
1561
1727
|
let sepEnd=-1
|
|
@@ -1577,7 +1743,11 @@ itemStart=${hasTrivia === 'false' ? 'EC.e' : hasTrivia === 'true' ? `${skip}(inp
|
|
|
1577
1743
|
${rb}
|
|
1578
1744
|
${trailingAllowed ? 'if(sepEnd>=0)cur=sepEnd\n' : ''}break
|
|
1579
1745
|
}
|
|
1580
|
-
|
|
1746
|
+
${itemCls === undefined ? '' : `if(count>=${min}&&${p}gate&&!classHas(${itemCls},lead(input,itemStart))){
|
|
1747
|
+
${rb}
|
|
1748
|
+
${trailingAllowed ? 'if(sepEnd>=0)cur=sepEnd\n' : ''}break
|
|
1749
|
+
}
|
|
1750
|
+
`}ctx._fc=false
|
|
1581
1751
|
const v=${child}(input,itemStart,ctx)
|
|
1582
1752
|
if(v===FAIL){
|
|
1583
1753
|
${REC
|
|
@@ -1614,6 +1784,26 @@ return out
|
|
|
1614
1784
|
case OP_NODE:
|
|
1615
1785
|
case OP_NODE_TRACK: {
|
|
1616
1786
|
const flags = code[ip + 3]!
|
|
1787
|
+
const scalarChild = scalarTerminalNodeChild(code, ip)
|
|
1788
|
+
if (scalarChild >= 0 && scalarSpecs.has(code[scalarChild + 1]!)) {
|
|
1789
|
+
const recognize = recognizerRef(code[scalarChild + 1]!)
|
|
1790
|
+
const spec = code[scalarChild] === OP_RX ? null : k[code[scalarChild + 1]!] as string
|
|
1791
|
+
const value = spec === null ? 'input.slice(pos,end)' : q(spec)
|
|
1792
|
+
const xf = fxRef(code[scalarChild + 2]!)
|
|
1793
|
+
const build = fnRef(code[ip + 1]!)
|
|
1794
|
+
return `${head}
|
|
1795
|
+
const end=${recognize}(input,pos)
|
|
1796
|
+
if(end<0){ctx._fe=pos;ctx._fx=${xf};return FAIL}
|
|
1797
|
+
const value=${value}
|
|
1798
|
+
const leaf={_tag:'leaf',value,span:{start:pos,end}}
|
|
1799
|
+
const kids=[leaf],rawKids=[leaf],span={start:pos,end}
|
|
1800
|
+
EC.e=end
|
|
1801
|
+
const nd=${build}(kids,undefined,span,rawKids,EMPTY_TL,undefined)
|
|
1802
|
+
${L.buf ? 'pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))' : 'if(ctx._cstBuf!==undefined||ctx._cstChildren!==undefined)pushCstChild(ctx,nd,rawEntry(nd,input,pos,end))'}
|
|
1803
|
+
EC.e=end
|
|
1804
|
+
return nd
|
|
1805
|
+
}`
|
|
1806
|
+
}
|
|
1617
1807
|
const child = link(code[ip + 2]!)
|
|
1618
1808
|
const proj = code[ip + 4]!
|
|
1619
1809
|
const buildIdx = code[ip + 1]!
|
|
@@ -1631,6 +1821,58 @@ return out
|
|
|
1631
1821
|
// interpreter's node case — the most-executed non-terminal in any of
|
|
1632
1822
|
// these grammars. It selects the emitted shape instead.
|
|
1633
1823
|
const build = buildIdx >= 0 ? fnRef(buildIdx) : undefined
|
|
1824
|
+
// The closure assembler's direct-builder capture tiers are table facts,
|
|
1825
|
+
// not closure-only semantics. Print the same body for a precompiled
|
|
1826
|
+
// assembly so a large composeLeaf artifact does not fall back to opening
|
|
1827
|
+
// the generic raw/trivia buffer that its reducer arity proved unread.
|
|
1828
|
+
if (!hostCst && !tracked && build !== undefined && proj < 0
|
|
1829
|
+
&& (flags === 2 || flags === 18 || flags === 34)) {
|
|
1830
|
+
const fields = flags === 18
|
|
1831
|
+
const collapseChildren = flags === 34
|
|
1832
|
+
const publish = `if(sBuf!==undefined){
|
|
1833
|
+
if(sBuf.rawOnly!==true){
|
|
1834
|
+
if(sBuf.ch!==undefined)sBuf.ch.push(nd)
|
|
1835
|
+
else if(sBuf.single!==undefined){sBuf.ch=[sBuf.single,nd];sBuf.single=undefined}
|
|
1836
|
+
else sBuf.single=nd
|
|
1837
|
+
}
|
|
1838
|
+
const rawNd=rawEntry(nd,input,pos,end)
|
|
1839
|
+
if(sBuf.raw!==undefined)sBuf.raw.push(rawNd)
|
|
1840
|
+
else if(sBuf.rawSingle!==undefined){sBuf.raw=[sBuf.rawSingle,rawNd];sBuf.rawSingle=undefined}
|
|
1841
|
+
else sBuf.rawSingle=rawNd
|
|
1842
|
+
}else if(sCh!==undefined){
|
|
1843
|
+
sCh.push(nd)
|
|
1844
|
+
if(sRaw!==undefined)sRaw.push(rawEntry(nd,input,pos,end))
|
|
1845
|
+
}`
|
|
1846
|
+
return `${head}
|
|
1847
|
+
const sCh=ctx._cstChildren,sLv=ctx._cstLeaves,sRaw=ctx._cstRawChildren,sTl=ctx._cstTriviaLog
|
|
1848
|
+
const sCap=ctx.captureTrivia,sBuf=ctx._cstBuf,sFields=ctx._fields
|
|
1849
|
+
const flat=[]
|
|
1850
|
+
ctx._cstBuf=undefined
|
|
1851
|
+
ctx._cstChildren=flat
|
|
1852
|
+
ctx._cstLeaves=flat
|
|
1853
|
+
ctx._cstRawChildren=undefined
|
|
1854
|
+
ctx._cstTriviaLog=undefined
|
|
1855
|
+
ctx.captureTrivia=false
|
|
1856
|
+
ctx._fields=${fields ? '[]' : 'undefined'}
|
|
1857
|
+
const v=${child}(input,pos,ctx)
|
|
1858
|
+
const captured=_capturedFlatChildren(flat)
|
|
1859
|
+
${fields ? 'const fieldMap=buildFieldMap(ctx._fields)\n' : ''}ctx._fields=sFields
|
|
1860
|
+
ctx._cstBuf=sBuf
|
|
1861
|
+
ctx._cstChildren=sCh
|
|
1862
|
+
ctx._cstLeaves=sLv
|
|
1863
|
+
ctx._cstRawChildren=sRaw
|
|
1864
|
+
ctx._cstTriviaLog=sTl
|
|
1865
|
+
ctx.captureTrivia=sCap
|
|
1866
|
+
if(v===FAIL)return FAIL
|
|
1867
|
+
const end=EC.e
|
|
1868
|
+
${collapseChildren
|
|
1869
|
+
? `const nd=captured.length===1?captured[0]:${build}(captured,undefined,{start:pos,end},EMPTY_CH,EMPTY_TL,undefined)`
|
|
1870
|
+
: `const nd=${build}(captured,${fields ? 'fieldMap' : 'undefined'},{start:pos,end},EMPTY_CH,EMPTY_TL,undefined)`}
|
|
1871
|
+
${publish}
|
|
1872
|
+
EC.e=end
|
|
1873
|
+
return nd
|
|
1874
|
+
}`
|
|
1875
|
+
}
|
|
1634
1876
|
const structural = build === undefined && proj < 0
|
|
1635
1877
|
const grammarCapture = (flags & 1) !== 0 || trailingTrivia
|
|
1636
1878
|
const hostCapturesThisType = structural && cfg.hostCaptureTrivia !== undefined
|
|
@@ -1745,6 +1987,7 @@ return nd
|
|
|
1745
1987
|
const source = `${RUNTIME_PRELUDE}
|
|
1746
1988
|
${prelude.join('\n')}
|
|
1747
1989
|
${skipDefs.join('\n')}
|
|
1990
|
+
${choiceDefs.join('\n')}
|
|
1748
1991
|
${bodies.join('\n')}
|
|
1749
1992
|
function _begin(ctx){
|
|
1750
1993
|
const host=ctx.build
|