Bind a pick to a name with {ref as n}, and read it with {n} and {n.path}

This commit is contained in:
2026-10-03 01:51:14 +02:00
committed by Lillem4n
parent ba9477f2e5
commit 23e426016d
16 changed files with 609 additions and 63 deletions
+31 -8
View File
@@ -61,11 +61,15 @@ func renderOnce(s *generatorState, n node) string {
func render(s *generatorState, n node, sc renderScope) string {
switch n := n.(type) {
case *choice:
if n.ownScope != nil {
mark := sc.draws.pushFrame(n.ownScope)
defer sc.draws.popFrame(mark)
}
return render(s, pick(s, n), sc)
case *nullItem:
return ""
case *table:
sc.row = renderedRow{n, n.drawRow(s)}
sc.row = renderedRow{n, sc.drawRowOf(s, n)}
return expand(s, n.formatTemplate, sc)
case *tableRow:
return expand(s, n.t.formatTemplate, sc)
@@ -78,6 +82,10 @@ func render(s *generatorState, n node, sc renderScope) string {
case *template:
sc = sc.in(n)
if n.repeat == 1 {
if n.ownScope != nil {
mark := sc.draws.pushFrame(n.ownScope)
defer sc.draws.popFrame(mark)
}
if lit, fixed := n.fixedText(); fixed {
return lit
}
@@ -89,7 +97,7 @@ func render(s *generatorState, n node, sc renderScope) string {
if i > 0 {
b.WriteString(n.separator)
}
b.WriteString(expandAnew(s, n))
b.WriteString(expandAnew(s, n, sc.draws.frames))
}
return b.String()
default:
@@ -97,12 +105,15 @@ func render(s *generatorState, n node, sc renderScope) string {
}
}
// expandAnew expands one repeat iteration of t as a render of its own, in no group. Inlined into
// render's loop, its draws would move to the heap.
// expandAnew expands one repeat iteration of t as a render of its own, in no group, inside the
// name scopes of frames. Inlined into render's loop, its draws would move to the heap.
//
//go:noinline
func expandAnew(s *generatorState, t *template) string {
var draws renderDraws
func expandAnew(s *generatorState, t *template, frames *frameStack) string {
draws := renderDraws{frames: frames}
if t.ownScope != nil {
defer draws.popFrame(draws.pushFrame(t.ownScope))
}
return expand(s, t, renderScope{draws: &draws})
}
@@ -155,7 +166,8 @@ func expand(s *generatorState, t *template, sc renderScope) string {
// token addresses by a dotted path that is not a reference, or a field an operand
// reads — is drawn once and kept in hold, so {place.postal-code} and {place.locality}
// read one row, either read twice gives one value, and a shown operand is the operand
// computed. Every other name is drawn afresh, so {word} {word} still draws twice.
// computed. A field of a template rendering as part of a named pick is kept in the pick.
// Every other field is drawn afresh, so {word} {word} still draws twice.
func readField(s *generatorState, t *template, hold *drawMemo, sc renderScope, a arm) readValue {
if a.kind == refPathRead {
return readReference(s, t, sc, a)
@@ -163,7 +175,13 @@ func readField(s *generatorState, t *template, hold *drawMemo, sc renderScope, a
if sc.draws.trace != nil {
traceRead(sc.draws.trace, t, sc, a)
}
if a.kind == freshRead {
switch {
case a.kind == namedRead:
return readName(s, sc, a)
case sc.pick != nil && !isRef(a.head):
return readUnder(s, t, sc, a)
case a.kind == freshRead:
sc.pick = nil
return readValue{text: render(s, t.head(a.head), sc)}
}
return readMemo(s, t, hold, nil, sc, a)
@@ -187,6 +205,7 @@ func readMemo(s *generatorState, t *template, memo *drawMemo, pins *pinSet, sc r
if pins != nil {
sc = sc.at(leaf, pins)
}
sc.pick, sc.entry = nil, memo
r := renderLeaf(s, leaf, sc)
if memo.value == nil {
memo.value = map[string]readValue{}
@@ -209,6 +228,10 @@ func traceRead(trace renderTrace, t *template, sc renderScope, a arm) {
// renderLeaf draws and renders what a read lands on: null on a null item, or on a column of one
// reference alone whose read drew null.
func renderLeaf(s *generatorState, n node, sc renderScope) readValue {
if c, isChoice := n.(*choice); isChoice && c.ownScope != nil {
mark := sc.draws.pushFrame(c.ownScope)
defer sc.draws.popFrame(mark)
}
n = resolveChoice(s, n)
switch leaf := n.(type) {
case *nullItem: