Answer architecture round 1: refuse a name read inside the field it binds, check every scope's cycles, build a column read in one pass, drop the implicit struct pick for names across tags, and state the fresh-draw rule once
This commit is contained in:
@@ -9,6 +9,34 @@ type namedPick struct {
|
||||
pins pinSet
|
||||
}
|
||||
|
||||
// drawMemo is what a named pick has drawn: the variant each level was drawn as, so every path
|
||||
// under it reads one variant; the value each read produced, by its path, so the same read written
|
||||
// twice reads one value; the frames a read opens for the name scopes around where it lands
|
||||
// (enter); and the rows drawn by each step down after a "..", by level.
|
||||
type drawMemo struct {
|
||||
variant map[string]node
|
||||
value map[string]readValue
|
||||
enteredFrames map[*nameScope]*pickFrame
|
||||
steppedDown map[string]*pinSet
|
||||
}
|
||||
|
||||
// stepDownPins is the pins a path steps down into after stepping up to t: kept in m where there
|
||||
// is one, so every path stepping down there reads one draw.
|
||||
func (m *drawMemo) stepDownPins(pins *pinSet, t *table, levels []string, at int) *pinSet {
|
||||
if m == nil {
|
||||
return pins.above(t)
|
||||
}
|
||||
p, ok := m.steppedDown[levels[at]]
|
||||
if !ok {
|
||||
p = pins.above(t)
|
||||
if m.steppedDown == nil {
|
||||
m.steppedDown = map[string]*pinSet{}
|
||||
}
|
||||
m.steppedDown[levels[at]] = p
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// pickFrame is one render of a name scope: a pick per binding, each drawn on its first read.
|
||||
type pickFrame struct {
|
||||
scope *nameScope
|
||||
@@ -117,7 +145,7 @@ func readName(s *generatorState, sc renderScope, a arm) readValue {
|
||||
return r
|
||||
}
|
||||
leaf, pins := p.draw(s, a.named.head, a.steps, a.levels, a.path)
|
||||
if a.named.field {
|
||||
if a.named.bindsField() {
|
||||
return p.renderAt(s, leaf, pins, a.path, sc)
|
||||
}
|
||||
sc, mark := sc.enter(leaf, &p.memo)
|
||||
|
||||
Reference in New Issue
Block a user