Name pathWalk's modes, and draw a path only through drawPath once it is proved
This commit is contained in:
@@ -33,7 +33,7 @@ func tableReadOf(head node, a arm, leaf node) *tableRead {
|
||||
return nil
|
||||
}
|
||||
tr := &tableRead{head: t, drawn: map[*table]bool{}}
|
||||
_, _ = walkPath(t, a.tail, pathWalk{pins: &tr.pins})
|
||||
_, _ = walkPath(t, a.tail, pathWalk{mode: walkProbe, pins: &tr.pins})
|
||||
written := a.name[:len(a.name)-len(joinSegments(a.tail))]
|
||||
cur := t
|
||||
tr.draws(cur)
|
||||
|
||||
@@ -165,10 +165,7 @@ func renderEdges(n node) []renderEdge {
|
||||
// already proved the tail resolves in every variant.
|
||||
func pathLeaves(n node, tail []string) []node {
|
||||
var out []node
|
||||
_, _ = walkPath(n, tail, pathWalk{
|
||||
choice: func(c *choice, _ []string) ([]node, error) { return c.items, nil },
|
||||
leaf: func(n node) error { out = append(out, n); return nil },
|
||||
})
|
||||
_, _ = walkPath(n, tail, pathWalk{mode: walkEvery, pins: &pinSet{}, leaf: func(n node) error { out = append(out, n); return nil }})
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,7 @@ func readField(s *session, t *template, held *hold, sc renderScope, a arm) draw
|
||||
if r, done := d.value[a.path]; done {
|
||||
return r
|
||||
}
|
||||
leaf, err := walkPath(t.head(a.key), a.tail, pathWalk{pins: &d.pins, draws: &pathDraws{s: s, held: d, a: &a}})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("fejkdata: %q: %v; a fence should have refused this at New", a.name, err))
|
||||
}
|
||||
r := renderLeaf(s, leaf, sc)
|
||||
r := renderLeaf(s, drawPath(t.head(a.key), a.tail, &d.pins, &pathDraws{s: s, held: d, a: &a}), sc)
|
||||
if d.value == nil {
|
||||
d.value = map[string]draw{}
|
||||
}
|
||||
|
||||
+1
-4
@@ -100,10 +100,7 @@ func operandReader(t *template, head string) string {
|
||||
// coverPath collects what holding one path pins: every choice level the path
|
||||
// passes through, whole, and the leaf it renders.
|
||||
func coverPath(n node, tail []string, into map[node]bool) {
|
||||
_, _ = walkPath(n, tail, pathWalk{
|
||||
choice: func(c *choice, _ []string) ([]node, error) { cover(c, into, false); return nil, nil },
|
||||
leaf: func(n node) error { cover(n, into, false); return nil },
|
||||
})
|
||||
_, _ = walkPath(n, tail, pathWalk{mode: walkCover, leaf: func(n node) error { cover(n, into, false); return nil }})
|
||||
}
|
||||
|
||||
// cover collects a level and everything contained in it. A fixed string outside a
|
||||
|
||||
@@ -125,21 +125,33 @@ func names(segs []string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// pathWalk is what one walk of a dotted path does at each kind of level: choice
|
||||
// returns the variants to continue into (none stops the walk), and where it is nil
|
||||
// the walk draws one with draws, takes the first where draws is nil, or stops where
|
||||
// pins is nil too; level runs at each template a segment descends
|
||||
// into; leaf runs where the tail ends; pins is where the walk pins the table rows
|
||||
// it selects and draws, nil skipping tables; draws is what draws the rows and
|
||||
// variants the path reads, nil proving instead that the path resolves whichever
|
||||
// are drawn. A nil action is skipped. A render's walk sets only pins and draws, so
|
||||
// it allocates nothing.
|
||||
// walkMode is what a walk does at a choice, and whether it reads the rows a path
|
||||
// selects and draws.
|
||||
type walkMode uint8
|
||||
|
||||
const (
|
||||
// walkCover stops at a choice, handing it whole to leaf, and reads no row.
|
||||
walkCover walkMode = iota
|
||||
// walkEvery proves every variant carries the rest of the path and walks each,
|
||||
// pinning the rows it selects in pins.
|
||||
walkEvery
|
||||
// walkProbe proves as walkEvery does, walking one variant, so a path that
|
||||
// resolves resolves whichever variants and rows are drawn.
|
||||
walkProbe
|
||||
// walkDraw draws the rows and variants a proved path reads; drawPath is its
|
||||
// one entry.
|
||||
walkDraw
|
||||
)
|
||||
|
||||
// pathWalk is one walk of a dotted path: level runs at each template a segment
|
||||
// descends into, leaf where the walk ends, and a nil action is skipped. A render's
|
||||
// walk sets only pins and draws, so it allocates nothing.
|
||||
type pathWalk struct {
|
||||
choice func(c *choice, rest []string) ([]node, error)
|
||||
level func(t *template, rest []string) error
|
||||
leaf func(n node) error
|
||||
pins *pinSet
|
||||
draws *pathDraws
|
||||
mode walkMode
|
||||
level func(t *template, rest []string) error
|
||||
leaf func(n node) error
|
||||
pins *pinSet
|
||||
draws *pathDraws
|
||||
}
|
||||
|
||||
// pathDraws is what a walk draws with: the session, and, for a held read, the hold
|
||||
@@ -151,7 +163,7 @@ type pathDraws struct {
|
||||
}
|
||||
|
||||
// walkPath descends tail from n and returns the node it ends at: a folder or
|
||||
// template by its next segment, a choice by w.choice, which consumes no segment, a
|
||||
// template by its next segment, a choice by its mode, which consumes no segment, a
|
||||
// table by walkTable. A missing segment is an error, so no walk reaches past what
|
||||
// the data holds.
|
||||
func walkPath(n node, tail []string, w pathWalk) (node, error) {
|
||||
@@ -197,27 +209,32 @@ func (w pathWalk) atLeaf(n node) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// walkChoice continues a walk into the variants w.choice returns, or into one
|
||||
// w.draws draws where the walk names no choice action.
|
||||
// drawPath draws the rows and variants a path reads, pinning them in pins. The path
|
||||
// must be proved first, by a probe or by New's fences, so the walk cannot fail.
|
||||
func drawPath(n node, tail []string, pins *pinSet, draws *pathDraws) node {
|
||||
leaf, err := walkPath(n, tail, pathWalk{mode: walkDraw, pins: pins, draws: draws})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("fejkdata: %s: %v; the path should have been proved before it was drawn", joinSegments(tail), err))
|
||||
}
|
||||
return leaf
|
||||
}
|
||||
|
||||
func walkChoice(c *choice, tail []string, w pathWalk) (node, error) {
|
||||
if w.choice == nil {
|
||||
if w.pins == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if w.draws == nil { // a probe: every variant carries the tail, so any one proves it
|
||||
if err := carriedByAll(c, tail); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return walkPath(c.items[0], tail, w)
|
||||
}
|
||||
switch w.mode {
|
||||
case walkCover:
|
||||
return c, w.atLeaf(c)
|
||||
case walkDraw:
|
||||
return walkPath(w.draws.variant(c, tail), tail, w)
|
||||
}
|
||||
next, err := w.choice(c, tail)
|
||||
if err != nil {
|
||||
if err := carriedByAll(c, tail); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if w.mode == walkProbe {
|
||||
return walkPath(c.items[0], tail, w)
|
||||
}
|
||||
var last node
|
||||
for _, item := range next {
|
||||
for _, item := range c.items {
|
||||
var err error
|
||||
if last, err = walkPath(item, tail, w); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -240,8 +257,8 @@ func walkTable(t *table, tail []string, w pathWalk, descended bool) (node, error
|
||||
}
|
||||
// A selector further down pins this table by ancestry, so the walk draws only
|
||||
// where none follows; drawing first could pick a row the selector is not inside.
|
||||
if w.pins != nil {
|
||||
if err := readRow(w.pins, w.draws, t, sel, (descended || len(tail) > 0) && !hasSelector(tail)); err != nil {
|
||||
if w.mode != walkCover {
|
||||
if err := readRow(w, t, sel, (descended || len(tail) > 0) && !hasSelector(tail)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -284,12 +301,12 @@ func (t *table) step(tail []string) (column node, child *table, err error) {
|
||||
|
||||
// readRow pins the row a path reads of t: the one its selector names, or, where the
|
||||
// walk draws, one drawn where the path reads into the table.
|
||||
func readRow(p *pinSet, draws *pathDraws, t *table, sel string, draw bool) error {
|
||||
func readRow(w pathWalk, t *table, sel string, draw bool) error {
|
||||
if sel != "" {
|
||||
return p.selectRow(t, sel)
|
||||
return w.pins.selectRow(t, sel)
|
||||
}
|
||||
if draw && draws != nil {
|
||||
t.drawIn(draws.s, p)
|
||||
if draw && w.mode == walkDraw {
|
||||
t.drawIn(w.draws.s, w.pins)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -344,12 +361,7 @@ func unreachableInChoice(c *choice, want string) error {
|
||||
func checkPath(n node, tail []string, level string) error {
|
||||
var pins pinSet
|
||||
_, err := walkPath(n, tail, pathWalk{
|
||||
choice: func(c *choice, rest []string) ([]node, error) {
|
||||
if err := carriedByAll(c, rest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.items, nil
|
||||
},
|
||||
mode: walkEvery,
|
||||
level: func(t *template, rest []string) error {
|
||||
name := join(level, strings.Join(tail[:len(tail)-len(rest)], "."))
|
||||
switch {
|
||||
|
||||
@@ -45,10 +45,10 @@ func (f *Generator) Fake(path string) (string, error) {
|
||||
func descend(s *session, root node, segments []string, sc renderScope) (node, error) {
|
||||
// Walked once without drawing first, so a path that fails moves no seeded stream.
|
||||
var probe pinSet
|
||||
if _, err := walkPath(root, segments, pathWalk{pins: &probe}); err != nil {
|
||||
if _, err := walkPath(root, segments, pathWalk{mode: walkProbe, pins: &probe}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return walkPath(root, segments, pathWalk{pins: &sc.hold().pins, draws: &pathDraws{s: s}})
|
||||
return drawPath(root, segments, &sc.hold().pins, &pathDraws{s: s}), nil
|
||||
}
|
||||
|
||||
// render evaluates a compiled node to a string. compile validates every node up
|
||||
|
||||
@@ -19,17 +19,12 @@ Self-sufficiency 5.6), every seat capped by Locality or Self-sufficiency.
|
||||
|
||||
This round, in order:
|
||||
|
||||
- Name `pathWalk`'s modes: render, probe, check and cover are chosen today by which
|
||||
callbacks are nil and whether `draws` is, and `walkChoice` returns `nil, nil` where
|
||||
none is set. Make the render mode reachable only through a proved path: a walk that
|
||||
draws no longer checks `carriedByAll`, trusting its caller's probe or `New`'s fences.
|
||||
- Have the check mode report the tables a read draws, so `tableRead.drawn` and
|
||||
`entered`'s `pinsAncestors` flag stop restating `walkTable`'s draw condition and
|
||||
`table.drawIn`'s ancestor rule: a change to how a render draws rows still leaves the
|
||||
fence proving the old rule. Hold a row rendered whole in `drawAt` beside `drawn`, so
|
||||
`pinSet` holds only what `pin` pins and `alternatives` needs no exception. Settle a
|
||||
cell of a municipality drawn whole beside a path pinning a region it is not in. Needs
|
||||
the item above.
|
||||
cell of a municipality drawn whole beside a path pinning a region it is not in.
|
||||
- Register a transform once: `transforms` restates the `lowercase`, `uppercase` and
|
||||
`ascii` entries in `builtins`, and `valueProof.template` classifies by the first while
|
||||
render calls the second. Derive the numeric builtins `valueProof.template` lists in
|
||||
|
||||
Reference in New Issue
Block a user