Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -110,3 +110,4 @@ In [docs/decisions.md](docs/decisions.md):
|
|||||||
- The US given names come from a mirror of the SSA file
|
- The US given names come from a mirror of the SSA file
|
||||||
- `List` advertises direct descents only
|
- `List` advertises direct descents only
|
||||||
- Each entry point to `drawCheck.hasRead` says what its caller gets
|
- Each entry point to `drawCheck.hasRead` says what its caller gets
|
||||||
|
- The four path walks are four loops
|
||||||
|
|||||||
@@ -683,3 +683,12 @@ the direct chain is the one a reader can predict from the tables' parents.
|
|||||||
2026-09-25, larv-review; approved 2026-09-25 by lilleman. Goal 2: a reader lands on
|
2026-09-25, larv-review; approved 2026-09-25 by lilleman. Goal 2: a reader lands on
|
||||||
`readsPath` or `splitsDraws` from its caller, so each doc states where that walk stops,
|
`readsPath` or `splitsDraws` from its caller, so each doc states where that walk stops,
|
||||||
though `hasRead` states the same stop rule. Valid while the two differ in where they stop.
|
though `hasRead` states the same stop rule. Valid while the two differ in where they stop.
|
||||||
|
|
||||||
|
## The four path walks are four loops
|
||||||
|
|
||||||
|
2026-09-28, larv-review on systems-architect's finding; awaiting approval. Goals 2 and
|
||||||
|
11: `pathCheck`, `pathCover`, `pathProbe` and `pathDraw` each loop over `stepInto` and
|
||||||
|
`table.route` themselves. One walk calling them through an interface or a type parameter
|
||||||
|
leaks the walker and the pins it holds, an allocation per reference read. Valid while Go's
|
||||||
|
escape analysis treats a call through an interface or a type parameter as leaking its
|
||||||
|
receiver.
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func tableReadOf(head node, a arm, leaf node) *tableRead {
|
|||||||
if !isTable {
|
if !isTable {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
probe := &probeWalk{}
|
probe := &pathProbe{drawn: map[*table]bool{}}
|
||||||
_, _ = probe.walk(t, a.tail)
|
_, _ = probe.walk(t, a.tail)
|
||||||
tr := &tableRead{headTable: t, pins: probe.pins, drawn: probe.drawn}
|
tr := &tableRead{headTable: t, pins: probe.pins, drawn: probe.drawn}
|
||||||
written := a.spelling[:len(a.spelling)-len(joinSegments(a.tail))]
|
written := a.spelling[:len(a.spelling)-len(joinSegments(a.tail))]
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ func renderEdges(n node) []renderEdge {
|
|||||||
// contributes every variant, since any of them may be the one drawn. checkPath has
|
// contributes every variant, since any of them may be the one drawn. checkPath has
|
||||||
// already proved the tail resolves in every variant.
|
// already proved the tail resolves in every variant.
|
||||||
func pathLeaves(n node, tail []string) []node {
|
func pathLeaves(n node, tail []string) []node {
|
||||||
w := &proveWalk{tail: tail}
|
w := &pathCheck{tail: tail}
|
||||||
_, _ = w.walk(n, tail)
|
_, _ = w.walk(n, tail)
|
||||||
return w.leaves
|
return w.leaves
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func readField(s *session, t *template, held *hold, sc renderScope, a arm) draw
|
|||||||
if len(a.tail) > 0 {
|
if len(a.tail) > 0 {
|
||||||
sc.pins = &d.pins
|
sc.pins = &d.pins
|
||||||
}
|
}
|
||||||
r := renderLeaf(s, drawPath(t.head(a.key), a.tail, a.key, &renderWalk{s: s, pins: &d.pins, held: d, a: &a}), sc)
|
r := renderLeaf(s, drawPath(t.head(a.key), a.tail, a.key, &pathDraw{s: s, pins: &d.pins, held: d, a: &a}), sc)
|
||||||
if d.value == nil {
|
if d.value == nil {
|
||||||
d.value = map[string]draw{}
|
d.value = map[string]draw{}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -100,7 +100,7 @@ func operandReader(t *template, head string) string {
|
|||||||
// coverPath collects what holding one path pins: every choice level the path
|
// coverPath collects what holding one path pins: every choice level the path
|
||||||
// passes through, whole, and the leaf it renders.
|
// passes through, whole, and the leaf it renders.
|
||||||
func coverPath(n node, tail []string, into map[node]bool) {
|
func coverPath(n node, tail []string, into map[node]bool) {
|
||||||
_, _ = (&coverWalk{into: into}).walk(n, tail)
|
_, _ = (&pathCover{into: into}).walk(n, tail)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cover collects a level and everything contained in it. A fixed string outside a
|
// cover collects a level and everything contained in it. A fixed string outside a
|
||||||
|
|||||||
@@ -185,18 +185,18 @@ func (t *table) route(tail []string, descended bool) (tableRoute, error) {
|
|||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// proveWalk proves a path resolves whichever way the draws go: every variant of a
|
// pathCheck proves a path resolves whichever way the draws go: every variant of a
|
||||||
// choice carries the rest of it, and is walked, a selector names a row inside the
|
// choice carries the rest of it, and is walked, a selector names a row inside the
|
||||||
// rows selected before it, and no level read carries a repeat or a drawGroup. It
|
// rows selected before it, and no level read carries a repeat or a drawGroup. It
|
||||||
// collects every leaf the path may render; level and tail name a refused level.
|
// collects every leaf the path may render; level and tail name a refused level.
|
||||||
type proveWalk struct {
|
type pathCheck struct {
|
||||||
pins pinSet
|
pins pinSet
|
||||||
level string
|
level string
|
||||||
tail []string
|
tail []string
|
||||||
leaves []node
|
leaves []node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *proveWalk) walk(n node, tail []string) (node, error) {
|
func (w *pathCheck) walk(n node, tail []string) (node, error) {
|
||||||
for descended := false; len(tail) > 0 || descended; {
|
for descended := false; len(tail) > 0 || descended; {
|
||||||
var err error
|
var err error
|
||||||
switch x := n.(type) {
|
switch x := n.(type) {
|
||||||
@@ -228,7 +228,7 @@ func (w *proveWalk) walk(n node, tail []string) (node, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *proveWalk) walkEvery(c *choice, tail []string) (node, error) {
|
func (w *pathCheck) walkEvery(c *choice, tail []string) (node, error) {
|
||||||
if err := carriedByAll(c, tail); err != nil {
|
if err := carriedByAll(c, tail); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -242,7 +242,7 @@ func (w *proveWalk) walkEvery(c *choice, tail []string) (node, error) {
|
|||||||
return last, nil
|
return last, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *proveWalk) enter(t *template, rest []string) error {
|
func (w *pathCheck) enter(t *template, rest []string) error {
|
||||||
name := join(w.level, strings.Join(w.tail[:len(w.tail)-len(rest)], "."))
|
name := join(w.level, strings.Join(w.tail[:len(w.tail)-len(rest)], "."))
|
||||||
switch {
|
switch {
|
||||||
case t.repeat > 1:
|
case t.repeat > 1:
|
||||||
@@ -253,11 +253,10 @@ func (w *proveWalk) enter(t *template, rest []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// coverWalk collects into what holding a path pins: every choice level it passes
|
// pathCover is coverPath's walk: it stops at a choice and reads no row.
|
||||||
// through, whole, and the leaf it renders. It stops at a choice and reads no row.
|
type pathCover struct{ into map[node]bool }
|
||||||
type coverWalk struct{ into map[node]bool }
|
|
||||||
|
|
||||||
func (w *coverWalk) walk(n node, tail []string) (node, error) {
|
func (w *pathCover) walk(n node, tail []string) (node, error) {
|
||||||
for descended := false; len(tail) > 0 || descended; {
|
for descended := false; len(tail) > 0 || descended; {
|
||||||
var err error
|
var err error
|
||||||
switch x := n.(type) {
|
switch x := n.(type) {
|
||||||
@@ -281,15 +280,15 @@ func (w *coverWalk) walk(n node, tail []string) (node, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// probeWalk proves a path as proveWalk does, walking one variant of a choice, so a
|
// pathProbe proves a path resolves, walking one variant of a choice, so a
|
||||||
// path that resolves resolves whichever variants and rows are drawn. It draws
|
// path that resolves resolves whichever variants and rows are drawn. It draws
|
||||||
// nothing, marking in drawn the tables a draw would pin.
|
// nothing, marking in drawn the tables a draw would pin.
|
||||||
type probeWalk struct {
|
type pathProbe struct {
|
||||||
pins pinSet
|
pins pinSet
|
||||||
drawn map[*table]bool
|
drawn map[*table]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *probeWalk) walk(n node, tail []string) (node, error) {
|
func (w *pathProbe) walk(n node, tail []string) (node, error) {
|
||||||
for descended := false; len(tail) > 0 || descended; {
|
for descended := false; len(tail) > 0 || descended; {
|
||||||
var err error
|
var err error
|
||||||
switch x := n.(type) {
|
switch x := n.(type) {
|
||||||
@@ -318,26 +317,23 @@ func (w *probeWalk) walk(n node, tail []string) (node, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *probeWalk) readRow(t *table, r tableRoute) error {
|
func (w *pathProbe) readRow(t *table, r tableRoute) error {
|
||||||
if r.sel != "" {
|
if r.sel != "" {
|
||||||
return w.pins.selectRow(t, r.sel)
|
return w.pins.selectRow(t, r.sel)
|
||||||
}
|
}
|
||||||
if !r.draw {
|
if !r.draw {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if w.drawn == nil {
|
|
||||||
w.drawn = map[*table]bool{}
|
|
||||||
}
|
|
||||||
for stop := w.pins.nearestPinned(t); t != stop; t = t.parentT {
|
for stop := w.pins.nearestPinned(t); t != stop; t = t.parentT {
|
||||||
w.drawn[t] = true
|
w.drawn[t] = true
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderWalk draws the rows and variants a proved path reads, pinning them in pins.
|
// pathDraw draws the rows and variants a proved path reads, pinning them in pins.
|
||||||
// For a held read, held keeps the variant drawn at each level of a, so paths
|
// For a held read, held keeps the variant drawn at each level of a, so paths
|
||||||
// sharing a prefix share it.
|
// sharing a prefix share it.
|
||||||
type renderWalk struct {
|
type pathDraw struct {
|
||||||
s *session
|
s *session
|
||||||
pins *pinSet
|
pins *pinSet
|
||||||
held *hold
|
held *hold
|
||||||
@@ -346,7 +342,7 @@ type renderWalk struct {
|
|||||||
|
|
||||||
// drawPath walks w over a path proved first, by a probe or by New's fences, so the
|
// drawPath walks w over a path proved first, by a probe or by New's fences, so the
|
||||||
// walk cannot fail. head is what n is reached by, for the panic.
|
// walk cannot fail. head is what n is reached by, for the panic.
|
||||||
func drawPath(n node, tail []string, head string, w *renderWalk) node {
|
func drawPath(n node, tail []string, head string, w *pathDraw) node {
|
||||||
leaf, err := w.walk(n, tail)
|
leaf, err := w.walk(n, tail)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("fejkdata: %s: %v; the path should have been proved before it was drawn", join(head, joinSegments(tail)), err))
|
panic(fmt.Sprintf("fejkdata: %s: %v; the path should have been proved before it was drawn", join(head, joinSegments(tail)), err))
|
||||||
@@ -354,7 +350,7 @@ func drawPath(n node, tail []string, head string, w *renderWalk) node {
|
|||||||
return leaf
|
return leaf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *renderWalk) walk(n node, tail []string) (node, error) {
|
func (w *pathDraw) walk(n node, tail []string) (node, error) {
|
||||||
for descended := false; len(tail) > 0 || descended; {
|
for descended := false; len(tail) > 0 || descended; {
|
||||||
var err error
|
var err error
|
||||||
switch x := n.(type) {
|
switch x := n.(type) {
|
||||||
@@ -387,7 +383,7 @@ func (w *renderWalk) walk(n node, tail []string) (node, error) {
|
|||||||
|
|
||||||
// variant is the variant of c the walk continues into: the one held for this level
|
// variant is the variant of c the walk continues into: the one held for this level
|
||||||
// of the read, drawn once, where the walk holds its draws; else one drawn afresh.
|
// of the read, drawn once, where the walk holds its draws; else one drawn afresh.
|
||||||
func (w *renderWalk) variant(c *choice, rest []string) node {
|
func (w *pathDraw) variant(c *choice, rest []string) node {
|
||||||
if w.held == nil {
|
if w.held == nil {
|
||||||
return pick(w.s, c)
|
return pick(w.s, c)
|
||||||
}
|
}
|
||||||
@@ -453,9 +449,9 @@ func unreachableInChoice(c *choice, want string) error {
|
|||||||
return fmt.Errorf("not every variant of this %d-way choice carries %q; all carry %v", len(c.items), want, offered)
|
return fmt.Errorf("not every variant of this %d-way choice carries %q; all carry %v", len(c.items), want, offered)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPath proves a dotted tail as proveWalk does, so a path that validates here
|
// checkPath proves a dotted tail as pathCheck does, so a path that validates here
|
||||||
// resolves on every render, and a typo is a New-time error.
|
// resolves on every render, and a typo is a New-time error.
|
||||||
func checkPath(n node, tail []string, level string) error {
|
func checkPath(n node, tail []string, level string) error {
|
||||||
_, err := (&proveWalk{level: level, tail: tail}).walk(n, tail)
|
_, err := (&pathCheck{level: level, tail: tail}).walk(n, tail)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ func (f *Generator) Fake(path string) (string, error) {
|
|||||||
// every call.
|
// every call.
|
||||||
func descend(s *session, root node, segments []string, sc renderScope) (node, 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.
|
// Walked once without drawing first, so a path that fails moves no seeded stream.
|
||||||
if _, err := (&probeWalk{}).walk(root, segments); err != nil {
|
if _, err := (&pathProbe{drawn: map[*table]bool{}}).walk(root, segments); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return drawPath(root, segments, "", &renderWalk{s: s, pins: &sc.hold().pins}), nil
|
return drawPath(root, segments, "", &pathDraw{s: s, pins: &sc.hold().pins}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// render evaluates a compiled node to a string. compile validates every node up
|
// render evaluates a compiled node to a string. compile validates every node up
|
||||||
|
|||||||
Reference in New Issue
Block a user