Hold a path's draw at every level it passes through
This commit is contained in:
@@ -189,17 +189,36 @@ func resolve(s *session, arms []arm, t *template, bound *draws) string {
|
|||||||
n = drawn(s, t.fields[a.key])
|
n = drawn(s, t.fields[a.key])
|
||||||
bound.variant[a.key] = n
|
bound.variant[a.key] = n
|
||||||
}
|
}
|
||||||
if len(a.tail) > 0 {
|
// Walk the tail, holding the draw at every level the path passes through, so
|
||||||
var err error
|
// two paths sharing a prefix share every choice along it, not just the head.
|
||||||
if n, err = descend(s, n, a.tail); err != nil {
|
for i, seg := range a.tail {
|
||||||
panic(fmt.Sprintf("fakes: %s: %v", a.name, err))
|
if i < len(a.steps) {
|
||||||
|
held, drew := bound.variant[a.steps[i]]
|
||||||
|
if !drew {
|
||||||
|
held = drawn(s, child(n, seg))
|
||||||
|
bound.variant[a.steps[i]] = held
|
||||||
}
|
}
|
||||||
|
n = held
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
n = child(n, seg)
|
||||||
}
|
}
|
||||||
v := render(s, n)
|
v := render(s, n)
|
||||||
bound.value[a.name] = v
|
bound.value[a.name] = v
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// child is the node one path segment names below an already-drawn node. checkPath
|
||||||
|
// proved the segment exists and that drawn leaves a template here, so this cannot
|
||||||
|
// fail.
|
||||||
|
func child(n node, seg string) node {
|
||||||
|
t, ok := n.(*template)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("fakes: %q under %T, which carries no fields", seg, n))
|
||||||
|
}
|
||||||
|
return t.fields[seg]
|
||||||
|
}
|
||||||
|
|
||||||
// drawn resolves a choice to one variant, so a bound head is a concrete node the
|
// drawn resolves a choice to one variant, so a bound head is a concrete node the
|
||||||
// rest of the expansion shares. Nested choices unwrap too: a draw is one value, not
|
// rest of the expansion shares. Nested choices unwrap too: a draw is one value, not
|
||||||
// another set to pick from.
|
// another set to pick from.
|
||||||
|
|||||||
+10
-1
@@ -180,6 +180,10 @@ type arm struct {
|
|||||||
name string // as written, and the key a bound draw's value is held under
|
name string // as written, and the key a bound draw's value is held under
|
||||||
key string
|
key string
|
||||||
tail []string
|
tail []string
|
||||||
|
// steps holds the key for each segment the walk passes *through* — the path
|
||||||
|
// prefixes below the head and above the leaf. The head is bound under key and
|
||||||
|
// the leaf's value under name, so a one-segment tail needs none of these.
|
||||||
|
steps []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitArm splits one token alternative into key and tail. A reference keeps its
|
// splitArm splits one token alternative into key and tail. A reference keeps its
|
||||||
@@ -192,7 +196,12 @@ func splitArm(name string) arm {
|
|||||||
if !dotted {
|
if !dotted {
|
||||||
return arm{name: name, key: name}
|
return arm{name: name, key: name}
|
||||||
}
|
}
|
||||||
return arm{name: name, key: head, tail: strings.Split(tail, ".")}
|
segs := strings.Split(tail, ".")
|
||||||
|
var steps []string
|
||||||
|
for i := 0; i < len(segs)-1; i++ { // every prefix except the leaf's own
|
||||||
|
steps = append(steps, head+"."+strings.Join(segs[:i+1], "."))
|
||||||
|
}
|
||||||
|
return arm{name: name, key: head, tail: segs, steps: steps}
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitArms splits a token body's '|' alternatives.
|
// splitArms splits a token body's '|' alternatives.
|
||||||
|
|||||||
Reference in New Issue
Block a user