@@ -540,7 +540,11 @@ function stepCond(s: Step, ids: LexIdPlan, ar: ArenaIdPlan): string {
540540}
541541
542542function predAltBody ( branches : Step [ ] [ ] , ids : LexIdPlan , firsts : FirstSig [ ] | undefined , ar : ArenaIdPlan ) : string {
543- const arms = branches . map ( ( br , i ) => `if ${ firstCond ( firsts ! [ i ] , 't' , ids ) } { if ${ br . length ? br . map ( ( x ) => stepCond ( x , ids , ar ) ) . join ( ' && ' ) : 'true' } { return true } }` ) . join ( ' else ' ) ;
543+ // FIRST dispatch still only tries the matching arm; on half-failure restore like non-pred alt.
544+ const arms = branches . map ( ( br , i ) => {
545+ const steps = br . length ? br . map ( ( x ) => stepCond ( x , ids , ar ) ) . join ( ' && ' ) : 'true' ;
546+ return `if ${ firstCond ( firsts ! [ i ] , 't' , ids ) } { save := pos; sb := len(scratch); nb := len(nodes); kb := len(kids); if ${ steps } { return true }; pos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb] }` ;
547+ } ) . join ( ' else ' ) ;
544548 return `t := peek(); if t == nil { return false }; ${ arms } ; return false` ;
545549}
546550
@@ -1895,7 +1899,11 @@ function notBodyW(steps: Step[], ids: LexIdPlan, ar: ArenaIdPlan, recv: string):
18951899}
18961900function predAltBodyW ( branches : Step [ ] [ ] , ids : LexIdPlan , ar : ArenaIdPlan , firsts : FirstSig [ ] | undefined , recv : string ) : string {
18971901 // Same-line ` } else if` (native predAltBody joins with ' else '); newlines break Go ASI.
1898- const arms = branches . map ( ( br , i ) => `if ${ firstCond ( firsts ! [ i ] , 't' , ids ) } { if ${ br . length ? br . map ( ( x ) => stepCondW ( x , ids , ar , recv ) ) . join ( ' && ' ) : 'true' } { return true } }` ) . join ( ' else ' ) ;
1902+ // FIRST dispatch; restore pos/scratch/arena on arm half-failure (like altBodyW).
1903+ const arms = branches . map ( ( br , i ) => {
1904+ const steps = br . length ? br . map ( ( x ) => stepCondW ( x , ids , ar , recv ) ) . join ( ' && ' ) : 'true' ;
1905+ return `if ${ firstCond ( firsts ! [ i ] , 't' , ids ) } { sp := p.pos; sb := len(p.scratch); ${ arenaCkpt ( recv ) } ; if ${ steps } { return true }; p.pos = sp; p.scratch = p.scratch[:sb]; ${ arenaRestore ( recv ) } }` ;
1906+ } ) . join ( ' else ' ) ;
18991907 return `t := p.peekW(); if t == nil { return false }; ${ arms } ; return false` ;
19001908}
19011909
@@ -2322,11 +2330,13 @@ func (p *${recv}) optW(body func() bool) bool {
23222330\treturn true
23232331}
23242332func (p *${ recv } ) sepByW(elem func() bool, delim uint16) bool {
2325- \tif !elem() { return true }
2333+ \tsp0 := p.pos; sb0 := len(p.scratch); ${ arenaCkpt ( recv ) . replace ( 'nb, kb' , 'nb0, kb0' ) }
2334+ \tif !elem() { p.pos = sp0; p.scratch = p.scratch[:sb0]; ${ arenaRestore ( recv ) . replace ( 'nb' , 'nb0' ) . replace ( 'kb' , 'kb0' ) } ; return true }
23262335\tfor {
23272336\t\tsp := p.pos; sb := len(p.scratch); ${ arenaCkpt ( recv ) }
23282337\t\tif !p.matchLitW(delim, TT_SKIP_PUNCT) { p.pos = sp; p.scratch = p.scratch[:sb]; ${ arenaRestore ( recv ) } ; break }
2329- \t\tif !elem() { break }
2338+ \t\tsp2 := p.pos; sb2 := len(p.scratch); ${ arenaCkpt ( recv ) . replace ( 'nb, kb' , 'nb2, kb2' ) }
2339+ \t\tif !elem() { p.pos = sp2; p.scratch = p.scratch[:sb2]; ${ arenaRestore ( recv ) . replace ( 'nb' , 'nb2' ) . replace ( 'kb' , 'kb2' ) } ; break }
23302340\t}
23312341\treturn true
23322342}
@@ -2398,8 +2408,13 @@ func (b *CstBuilder) Shift(h int32, byteDelta, tokDelta int) int32 {
23982408}
23992409` ;
24002410
2411+ // EntryMeta is part of parseWithMetaW's signature always; reuse paths define it via
2412+ // rdEntryWithReuse{A,B}. Non-reuse grammars (e.g. toy) still emit DocWith and need the type.
2413+ const entryMetaType = topReuse ? '' : `type EntryMeta struct { TokStart, TokEnd, Ext, Off, End, KidStart, KidCount int }
2414+ ` ;
2415+
24012416 const parseWithMetaW = `
2402- func parseWithMetaW(text string, meta []alignMeta, b Builder) (h int32, entries []EntryMeta, entryHs []int32, ok bool) {
2417+ ${ entryMetaType } func parseWithMetaW(text string, meta []alignMeta, b Builder) (h int32, entries []EntryMeta, entryHs []int32, ok bool) {
24032418 toks := toksFromMeta(text, meta)
24042419 n := len(toks)
24052420 p := &parserW{toks: toks, src: text, b: b, scratch: nil}
@@ -2905,7 +2920,7 @@ func NewDocWith(src string, b Builder) Document {
29052920func newDocWith(src string, b Builder) *DocWith {
29062921 d := &DocWith{text: src, b: b}
29072922 d.toks = ${ initToks }
2908- h, entries, entryHs, ok := parseWithMetaW(src, d.toks, b)
2923+ ${ topReuse ? ' h, entries, entryHs, ok' : 'h, _, _, ok' } := parseWithMetaW(src, d.toks, b)
29092924 if ok {
29102925${ initAssign }
29112926 } else {
@@ -2937,7 +2952,7 @@ ${recoverClear}
29372952 }
29382953 }()
29392954 d.toks = ${ freshMeta }
2940- h, ne, nhs, ok := parseWithMetaW(d.text, d.toks, d.b)
2955+ ${ topReuse ? ' h, ne, nhs, ok' : 'h, _, _, ok' } := parseWithMetaW(d.text, d.toks, d.b)
29412956 if ok {
29422957${ recoverAssign }
29432958 } else {
@@ -3444,11 +3459,13 @@ func opt(body func() bool) bool {
34443459\tsp := pos; sb := len(scratch); nb := len(nodes); kb := len(kids); if !body() { pos = sp; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb] }; return true
34453460}
34463461func sepBy(elem func() bool, delimLid uint16) bool {
3447- \tif !elem() { return true } // the whole separated list is optional — zero elements is valid
3462+ \tsp0 := pos; sb0 := len(scratch); nb0 := len(nodes); kb0 := len(kids)
3463+ \tif !elem() { pos = sp0; scratch = scratch[:sb0]; nodes = nodes[:nb0]; kids = kids[:kb0]; return true }
34483464\tfor {
34493465\t\tsp := pos; sb := len(scratch); nb := len(nodes); kb := len(kids)
34503466\t\tif !matchLit(delimLid, TT_SKIP_PUNCT) { pos = sp; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb]; break }
3451- \t\tif !elem() { break } // a trailing delimiter is allowed — keep the pushed delim and stop
3467+ \t\tsp2 := pos; sb2 := len(scratch); nb2 := len(nodes); kb2 := len(kids)
3468+ \t\tif !elem() { pos = sp2; scratch = scratch[:sb2]; nodes = nodes[:nb2]; kids = kids[:kb2]; break } // trailing delim OK — keep delim
34523469\t}
34533470\treturn true
34543471}
0 commit comments