Fix at compile how readField reads an arm, deleting its two panics and its held lookup per read
This commit is contained in:
@@ -315,8 +315,18 @@ type arm struct {
|
|||||||
steps []pathStep
|
steps []pathStep
|
||||||
leaves []node // every node the path may land on, one per variant it passes
|
leaves []node // every node the path may land on, one per variant it passes
|
||||||
cover node // what holding the path pins: the first choice it passes, else its leaf
|
cover node // what holding the path pins: the first choice it passes, else its leaf
|
||||||
|
kind armKind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// armKind is how expand reads an arm, fixed at compile.
|
||||||
|
type armKind uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
freshRead armKind = iota // drawn afresh at every read
|
||||||
|
heldRead // drawn once per expansion, kept in its hold
|
||||||
|
refPathRead // drawn once per draw group, kept in its memo
|
||||||
|
)
|
||||||
|
|
||||||
func (a arm) isRefPath() bool {
|
func (a arm) isRefPath() bool {
|
||||||
return isRef(a.head) && len(a.tail) > 0
|
return isRef(a.head) && len(a.tail) > 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,12 @@ func compileArm(t *template, a *arm) {
|
|||||||
}
|
}
|
||||||
w := compilePath(head, a.tail)
|
w := compilePath(head, a.tail)
|
||||||
a.steps, a.leaves, a.cover = w.steps, w.leaves, w.cover
|
a.steps, a.leaves, a.cover = w.steps, w.leaves, w.cover
|
||||||
|
switch _, held := t.compiled.held[a.head]; {
|
||||||
|
case a.isRefPath():
|
||||||
|
a.kind = refPathRead
|
||||||
|
case held:
|
||||||
|
a.kind = heldRead
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveLink binds every reference t reads, refusing one to t's own category, and keys
|
// resolveLink binds every reference t reads, refusing one to t's own category, and keys
|
||||||
|
|||||||
@@ -158,21 +158,15 @@ func expand(s *generatorState, t *template, sc renderScope) string {
|
|||||||
// read one row, either read twice gives one value, and a shown operand is the operand
|
// 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. Every other name is drawn afresh, so {word} {word} still draws twice.
|
||||||
func readField(s *generatorState, t *template, hold *drawMemo, sc renderScope, a arm) readValue {
|
func readField(s *generatorState, t *template, hold *drawMemo, sc renderScope, a arm) readValue {
|
||||||
if a.isRefPath() {
|
if a.kind == refPathRead {
|
||||||
return readReference(s, t, sc, a)
|
return readReference(s, t, sc, a)
|
||||||
}
|
}
|
||||||
if sc.draws.trace != nil {
|
if sc.draws.trace != nil {
|
||||||
traceRead(sc.draws.trace, t, sc, a)
|
traceRead(sc.draws.trace, t, sc, a)
|
||||||
}
|
}
|
||||||
if _, expansionHolds := t.compiled.held[a.head]; !expansionHolds {
|
if a.kind == freshRead {
|
||||||
if len(a.tail) > 0 {
|
|
||||||
panic(internalError("%q reads a path into %q, which the expansion does not hold", a.spelling, a.head))
|
|
||||||
}
|
|
||||||
return readValue{text: render(s, t.head(a.head), sc)}
|
return readValue{text: render(s, t.head(a.head), sc)}
|
||||||
}
|
}
|
||||||
if hold == nil {
|
|
||||||
panic(internalError("%q reads a name the expansion holds, with no hold to keep it in", a.spelling))
|
|
||||||
}
|
|
||||||
return readMemo(s, t, hold, nil, sc, a)
|
return readMemo(s, t, hold, nil, sc, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user