@@ -408,7 +408,7 @@ function predAltBody(branches: Step[][], firsts?: FirstSig[]): string {
408408
409409function rdRule ( r : RdRule ) : string {
410410 if ( r . predictive ) {
411- const arm = ( steps : Step [ ] , i : number ) => `\t${ i === 0 ? 'if' : 'else if' } ${ firstCond ( r . altFirst [ i ] , 't' ) } { if ${ steps . map ( stepCond ) . join ( ' && ' ) } { return finish(${ J ( r . cstName ) } , sb, offAt(save)) } }` ;
411+ const arm = ( steps : Step [ ] , i : number ) => `\t${ i === 0 ? 'if' : 'else if' } ${ firstCond ( r . altFirst [ i ] , 't' ) } { if ${ steps . map ( stepCond ) . join ( ' && ' ) } { return finish(${ J ( r . cstName ) } , sb, offAt(save), save ) } }` ;
412412 return `func parse${ r . name } () int32 {
413413\tsave := pos; sb := len(scratch); nb := len(nodes); kb := len(kids)
414414\tt := peek(); if t == nil { return -1 }
@@ -418,7 +418,7 @@ ${r.alts.map(arm).join(' ')}
418418}` ;
419419 }
420420 const alt = ( steps : Step [ ] ) =>
421- `\tif ${ steps . map ( stepCond ) . join ( ' && ' ) } { return finish(${ J ( r . cstName ) } , sb, offAt(save)) }
421+ `\tif ${ steps . map ( stepCond ) . join ( ' && ' ) } { return finish(${ J ( r . cstName ) } , sb, offAt(save), save ) }
422422\tpos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb]` ;
423423 return `func parse${ r . name } () int32 {
424424\tsave := pos; sb := len(scratch); nb := len(nodes); kb := len(kids)
@@ -433,32 +433,32 @@ function prattRule(r: PrattRule, tpl: TplCfg | null): string {
433433\t\tnode := matchTemplate()
434434\t\tif node < 0 { return -1 }
435435\t\tsb := len(scratch); scratch = append(scratch, node)
436- \t\treturn finish(${ J ( r . cstName ) } , sb, nodes[node].Offset)
436+ \t\treturn finish(${ J ( r . cstName ) } , sb, nodes[node].Offset, nodes[node].TokStart )
437437\t}\n`
438438 : '' ;
439439 const bin = r . binary . map ( ( b ) => `${ J ( b . op ) } : {${ b . lbp } , ${ b . rbp } }` ) . join ( ', ' ) ;
440440 const pre = r . prefix . map ( ( p ) => `${ J ( p . op ) } : ${ p . rbp } ` ) . join ( ', ' ) ;
441441 const atoms = r . nudToks . map ( ( k ) => `${ J ( k ) } : true` ) . join ( ', ' ) ;
442442 const bracketNud = ( b : Bracket ) => `\tif t.Text == ${ J ( b . first ) } {
443443\t\tsave := pos; sb := len(scratch); nb := len(nodes); kb := len(kids)
444- \t\tif ${ b . steps . map ( stepCond ) . join ( ' && ' ) } { return finish(${ J ( r . cstName ) } , sb, t.Off) }
444+ \t\tif ${ b . steps . map ( stepCond ) . join ( ' && ' ) } { return finish(${ J ( r . cstName ) } , sb, t.Off, save ) }
445445\t\tpos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb]
446446\t}` ;
447447 const ledArm = ( b : Bracket , accessTail : boolean , lbp : number | null , sameLine : boolean , nll : string [ ] | null ) => `\t\tif ${ accessTail ? '!tailClosed && ' : '' } ${ lbp !== null ? `${ lbp } > minBp && ` : '' } ${ sameLine ? '!t.Nl && ' : '' } ${ nll ? `!_inW([]string{${ nll . map ( J ) . join ( ', ' ) } }, headLeafText(left)) && ` : '' } !_suppressCur[${ J ( b . first ) } ] && t.Text == ${ J ( b . first ) } {
448448\t\t\tledSave := pos; sb := len(scratch); nb := len(nodes); kb := len(kids)
449449\t\t\tscratch = append(scratch, left)
450- \t\t\tif ${ b . steps . map ( stepCond ) . join ( ' && ' ) } { left = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset); continue }
450+ \t\t\tif ${ b . steps . map ( stepCond ) . join ( ' && ' ) } { left = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset, nodes[left].TokStart ); continue }
451451\t\t\tpos = ledSave; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb]; break
452452\t\t}` ;
453453 const postfixArm = ( tok : string ) => {
454454 const tplPart = tpl && tok === tpl . token ? `
455455\t\tif !tailClosed && t.Kind == "$templateHead" {
456456\t\t\tnode := matchTemplate()
457- \t\t\tif node >= 0 { sb := len(scratch); scratch = append(scratch, left, node); left = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset); continue }
457+ \t\t\tif node >= 0 { sb := len(scratch); scratch = append(scratch, left, node); left = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset, nodes[left].TokStart ); continue }
458458\t\t}` : '' ;
459459 return `\t\tif !tailClosed && t.Kind == ${ J ( tok ) } {
460460\t\t\tsb := len(scratch); scratch = append(scratch, left, mkLeaf(t.Kind, t.Off, t.End)); pos++
461- \t\t\tleft = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset); continue
461+ \t\t\tleft = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset, nodes[left].TokStart ); continue
462462\t\t}${ tplPart } ` ;
463463 } ;
464464 const post = r . postfix . map ( ( p ) => `${ J ( p . op ) } : ${ p . lbp } ` ) . join ( ', ' ) ;
@@ -486,7 +486,7 @@ ${r.leds.map((b, i) => ledArm(b, r.ledAccessTail[i], r.ledLbp[i], r.ledSameLine[
486486${ r . postfixToks . map ( postfixArm ) . join ( '\n' ) }
487487\t\tif post, ok := ${ r . name } POST[t.Text]; ok && !tailClosed && post > minBp {
488488\t\t\tsb := len(scratch); scratch = append(scratch, left, mkLeaf("$operator", t.Off, t.End)); pos++; tailClosed = true
489- \t\t\tleft = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset); continue
489+ \t\t\tleft = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset, nodes[left].TokStart ); continue
490490\t\t}
491491\t\tinfo, ok := ${ r . name } BIN[t.Text]
492492\t\tif !ok || info.lbp <= minBp { break }
@@ -496,19 +496,19 @@ ${r.postfixToks.map(postfixArm).join('\n')}
496496\t\trhs := ${ r . name } bp(info.rbp)
497497\t\tif rhs < 0 { pos = ledSave; scratch = scratch[:sb]; break }
498498\t\tscratch = append(scratch, rhs)
499- \t\tleft = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset)
499+ \t\tleft = finish(${ J ( r . cstName ) } , sb, nodes[left].Offset, nodes[left].TokStart )
500500\t}
501501\treturn left
502502}
503503func ${ r . name } nud(minBp int) int32 {
504504\t_capped = false
505505\tt := peek()
506506\tif t == nil { return -1 }
507- ${ r . nudCapped . map ( ( c ) => `\tif minBp < ${ c . capBp } { save := pos; sb := len(scratch); nb := len(nodes); kb := len(kids); if ${ c . steps . length ? c . steps . map ( stepCond ) . join ( ' && ' ) : 'true' } { _capped = true; return finish(${ J ( r . cstName ) } , sb, offAt(save)) }; pos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb] }` ) . join ( '\n' ) }
507+ ${ r . nudCapped . map ( ( c ) => `\tif minBp < ${ c . capBp } { save := pos; sb := len(scratch); nb := len(nodes); kb := len(kids); if ${ c . steps . length ? c . steps . map ( stepCond ) . join ( ' && ' ) : 'true' } { _capped = true; return finish(${ J ( r . cstName ) } , sb, offAt(save), save ) }; pos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb] }` ) . join ( '\n' ) }
508508\t_r := func() int32 { // non-capped: a sub-parse may leave _capped set; force it false after
509509${ tplNud } \tif ${ r . name } ATOM[t.Kind] {
510- \t\tsb := len(scratch); scratch = append(scratch, mkLeaf(t.Kind, t.Off, t.End)); pos++
511- \t\treturn finish(${ J ( r . cstName ) } , sb, t.Off)
510+ \t\tsb := len(scratch); ts := pos; scratch = append(scratch, mkLeaf(t.Kind, t.Off, t.End)); pos++
511+ \t\treturn finish(${ J ( r . cstName ) } , sb, t.Off, ts )
512512\t}
513513${ r . nudBrackets . map ( bracketNud ) . join ( '\n' ) }
514514\tif pbp, ok := ${ r . name } PRE[t.Text]; ok {
@@ -517,9 +517,9 @@ ${r.nudBrackets.map(bracketNud).join('\n')}
517517\t\toperand := ${ r . name } bp(pbp)
518518\t\tif operand < 0 { pos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb]; return -1 }
519519\t\tscratch = append(scratch, operand)
520- \t\treturn finish(${ J ( r . cstName ) } , sb, t.Off)
520+ \t\treturn finish(${ J ( r . cstName ) } , sb, t.Off, save )
521521\t}
522- ${ r . nudSeqs . map ( ( seq ) => `\t{ save := pos; sb := len(scratch); nb := len(nodes); kb := len(kids); if ${ seq . length ? seq . map ( stepCond ) . join ( ' && ' ) : 'true' } { return finish(${ J ( r . cstName ) } , sb, offAt(save)) }; pos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb] }` ) . join ( '\n' ) }
522+ ${ r . nudSeqs . map ( ( seq ) => `\t{ save := pos; sb := len(scratch); nb := len(nodes); kb := len(kids); if ${ seq . length ? seq . map ( stepCond ) . join ( ' && ' ) : 'true' } { return finish(${ J ( r . cstName ) } , sb, offAt(save), save ) }; pos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb] }` ) . join ( '\n' ) }
523523\treturn -1
524524\t}()
525525\t_capped = false
@@ -1104,7 +1104,7 @@ func Tokenize(src string) []Tok { return lex(src) }
11041104\t\tif next.Kind == "$templateTail" { scratch = append(scratch, mkLeaf("$templateTail", next.Off, next.End)); pos++; break }
11051105\t\tpos = save; scratch = scratch[:sb]; nodes = nodes[:nb]; kids = kids[:kb]; return -1
11061106\t}
1107- \treturn finish("$template", sb, t.Off)
1107+ \treturn finish("$template", sb, t.Off, save )
11081108}
11091109` : '' ;
11101110 return `// GENERATED by emit-portable.ts (goTarget) — parser LIBRARY for grammar "${ ir . grammarName } ".
@@ -1127,7 +1127,7 @@ type Tok struct {
11271127type Node struct {
11281128\tRule, TokenType string
11291129\tIsLeaf bool
1130- \tKidStart, KidCount, Offset, End int
1130+ \tKidStart, KidCount, Offset, End, TokStart, TokEnd int
11311131}
11321132type bp struct{ lbp, rbp int }
11331133
@@ -1149,18 +1149,19 @@ func peek() *Tok {
11491149}
11501150func offAt(i int) int { if i < len(toks) { return toks[i].Off }; return 0 }
11511151func mkLeaf(ttype string, off, end int) int32 {
1152- \tnodes = append(nodes, Node{TokenType: ttype, IsLeaf: true, Offset: off, End: end})
1152+ \tnodes = append(nodes, Node{TokenType: ttype, IsLeaf: true, Offset: off, End: end, TokStart: pos, TokEnd: pos + 1 })
11531153\treturn int32(len(nodes) - 1)
11541154}
11551155// Wrap the scratch entries [sb:] as one node's children (flattened into kids); truncate scratch.
1156- func finish(rule string, sb, fallbackOff int) int32 {
1156+ // tokStart is the parse-consumption start (entry pos / leftmost operand), tokEnd is pos at finish.
1157+ func finish(rule string, sb, fallbackOff, tokStart int) int32 {
11571158\tnn := len(scratch)
11581159\tkidStart := len(kids)
11591160\toff, end := fallbackOff, fallbackOff
11601161\tif nn > sb { off = nodes[scratch[sb]].Offset; end = nodes[scratch[nn-1]].End }
11611162\tkids = append(kids, scratch[sb:nn]...)
11621163\tscratch = scratch[:sb]
1163- \tnodes = append(nodes, Node{Rule: rule, KidStart: kidStart, KidCount: nn - sb, Offset: off, End: end})
1164+ \tnodes = append(nodes, Node{Rule: rule, KidStart: kidStart, KidCount: nn - sb, Offset: off, End: end, TokStart: tokStart, TokEnd: pos })
11641165\treturn int32(len(nodes) - 1)
11651166}
11661167func matchLit(value, ttype string) bool {
@@ -1287,6 +1288,22 @@ func main() {
12871288\t\tos.Stdout.WriteString(b.String())
12881289\t\treturn
12891290\t}
1291+ \tif len(os.Args) > 1 && os.Args[1] == "tok-spans" {
1292+ \t\troot := parse(tokenize(src))
1293+ \t\tif root < 0 || pos != len(toks) {
1294+ \t\t\tfmt.Fprintf(os.Stderr, "parse error (pos %d/%d)\\n", pos, len(toks))
1295+ \t\t\tos.Exit(1)
1296+ \t\t}
1297+ \t\tnd := &nodes[root]
1298+ \t\tfor i := 0; i < nd.KidCount; i++ {
1299+ \t\t\tk := &nodes[kids[nd.KidStart+i]]
1300+ \t\t\tname := k.Rule
1301+ \t\t\tif k.IsLeaf { name = k.TokenType }
1302+ \t\t\tfmt.Printf("%s\\t%d\\t%d\\n", name, k.TokStart, k.TokEnd)
1303+ \t\t}
1304+ \t\tfmt.Printf("total\\t0\\t%d\\n", pos)
1305+ \t\treturn
1306+ \t}
12901307\troot := parse(tokenize(src))
12911308\tif root < 0 || pos != len(toks) {
12921309\t\tfmt.Fprintf(os.Stderr, "parse error (pos %d/%d)\\n", pos, len(toks))
0 commit comments