Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -870,7 +870,7 @@ doc.go the package doc, and the vocabulary the package is written in
|
|||||||
fejkdata.go Generator, New, options, the embedded data set, List
|
fejkdata.go Generator, New, options, the embedded data set, List
|
||||||
node.go the node model and JSON -> node compilation
|
node.go the node model and JSON -> node compilation
|
||||||
table.go tables: the rows TSV, its options and links, row selection and draws
|
table.go tables: the rows TSV, its options and links, row selection and draws
|
||||||
path.go the dotted-path walk with its selectors, and proving a path resolves
|
path.go the dotted-path walks with their selectors, and proving a path resolves
|
||||||
render.go Fake and the recursive renderer (choices, format strings, expansions)
|
render.go Fake and the recursive renderer (choices, format strings, expansions)
|
||||||
record.go records: Record, the JSON/CSV/SQL serializers, and their entry points
|
record.go records: Record, the JSON/CSV/SQL serializers, and their entry points
|
||||||
struct.go structs: FakeStruct, fake tags, and a field's Go type as its column's datatype
|
struct.go structs: FakeStruct, fake tags, and a field's Go type as its column's datatype
|
||||||
|
|||||||
+3
-3
@@ -325,7 +325,7 @@ Go ties a package to one directory, so folders would split the API into packages
|
|||||||
|
|
||||||
## The performance gate asserts allocations, not wall-clock time
|
## The performance gate asserts allocations, not wall-clock time
|
||||||
|
|
||||||
`AllocsPerRun` is deterministic across machines, so a ±10% ceiling does not flake under
|
`AllocsPerRun` is deterministic across machines, so a 10% ceiling does not flake under
|
||||||
CI load, while time varies with the machine and its neighbours. A rendering slowdown
|
CI load, while time varies with the machine and its neighbours. A rendering slowdown
|
||||||
almost always costs an allocation too (a lost pre-size, a per-item map, an extra copy).
|
almost always costs an allocation too (a lost pre-size, a per-item map, an extra copy).
|
||||||
The benchmark suite (the README's Development) reports time for a human, not as a pass/fail gate.
|
The benchmark suite (the README's Development) reports time for a human, not as a pass/fail gate.
|
||||||
@@ -689,8 +689,8 @@ though `hasRead` states the same stop rule. Valid while the two differ in where
|
|||||||
2026-09-28, larv-review on systems-architect's finding; awaiting approval. Goals 2 and
|
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
|
11: `pathCheck`, `pathCover`, `pathProbe` and `pathDraw` each loop over `stepInto` and
|
||||||
`table.route` themselves, and `descend` builds its probe in place, so the probe's
|
`table.route` themselves, and `descend` builds its probe in place, so the probe's
|
||||||
`drawn` map stays on the stack; its caller always builds that map, since no walker
|
`drawn` map stays on the stack; its caller always builds that map, so `readRow` never
|
||||||
picks a behaviour by a nil field. One walk calling them through an interface or a type
|
tests it for nil. One walk calling them through an interface or a type
|
||||||
parameter leaks the walker and the pins it holds, an allocation per reference read.
|
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
|
Valid while Go's escape analysis treats a call through an interface or a type parameter
|
||||||
as leaking its receiver.
|
as leaking its receiver.
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ type tableSel struct {
|
|||||||
spelling string
|
spelling string
|
||||||
}
|
}
|
||||||
|
|
||||||
// tableReadOf replays a reference's selectors through the walk a render uses, so
|
// tableReadOf replays a reference path through pathProbe, so two paths pinning one
|
||||||
// two paths pinning one row by different routes compare equal. checkPath proved
|
// row by different routes compare equal. checkPath proved
|
||||||
// each selector names a row.
|
// each selector names a row.
|
||||||
func tableReadOf(head node, a arm, leaf node) *tableRead {
|
func tableReadOf(head node, a arm, leaf node) *tableRead {
|
||||||
t, isTable := head.(*table)
|
t, isTable := head.(*table)
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ type draw struct {
|
|||||||
// token addresses by dotted path, or a field an operand reads — is drawn once and
|
// token addresses by dotted path, or a field an operand reads — is drawn once and
|
||||||
// kept, so {place.postal-code} and {place.locality} read one row, either read twice
|
// kept, so {place.postal-code} and {place.locality} read one row, either read twice
|
||||||
// gives one value, and a shown operand is the operand computed. Every other name is
|
// gives one value, and a shown operand is the operand computed. Every other name is
|
||||||
// drawn afresh, so {word} {word} still draws twice. checkTokens, checkPath and
|
// drawn afresh, so {word} {word} still draws twice.
|
||||||
// linkRefs prove every step, so the walk cannot fail.
|
|
||||||
func readField(s *session, t *template, held *hold, sc renderScope, a arm) draw {
|
func readField(s *session, t *template, held *hold, sc renderScope, a arm) draw {
|
||||||
if s.trace != nil {
|
if s.trace != nil {
|
||||||
traceRead(s.trace, t, sc, a)
|
traceRead(s.trace, t, sc, a)
|
||||||
|
|||||||
+2
-2
@@ -97,8 +97,8 @@ func operandReader(t *template, head string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// coverPath collects what holding one path pins: every choice level the path
|
// coverPath collects what holding one path pins: the first choice level it passes,
|
||||||
// passes through, whole, and the leaf it renders.
|
// whole, else the leaf it renders; it reads no row.
|
||||||
func coverPath(n node, tail []string, into map[node]bool) {
|
func coverPath(n node, tail []string, into map[node]bool) {
|
||||||
_, _ = (&pathCover{into: into}).walk(n, tail)
|
_, _ = (&pathCover{into: into}).walk(n, tail)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func (*folder) isNode() {}
|
|||||||
|
|
||||||
// choice picks one of its items. cum holds cumulative weights for a weighted
|
// choice picks one of its items. cum holds cumulative weights for a weighted
|
||||||
// pick; when nil the choice is uniform and selection is O(1). shared is the set of
|
// pick; when nil the choice is uniform and selection is O(1). shared is the set of
|
||||||
// relative dot paths every item can address, so descend and List both read the one
|
// relative dot paths every item can address, so carriedByAll and List both read the one
|
||||||
// answer to what a path may reach through this choice.
|
// answer to what a path may reach through this choice.
|
||||||
type choice struct {
|
type choice struct {
|
||||||
items []node
|
items []node
|
||||||
|
|||||||
@@ -125,8 +125,7 @@ func nameSegments(segs []string) []string {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// stepInto is what seg names under n: a folder's entry or a template's field. A
|
// stepInto is what seg names under n: a folder's entry or a template's field.
|
||||||
// missing segment is an error, so no walk reaches past what the data holds.
|
|
||||||
func stepInto(n node, seg string) (node, error) {
|
func stepInto(n node, seg string) (node, error) {
|
||||||
if isSelector(seg) {
|
if isSelector(seg) {
|
||||||
return nil, fmt.Errorf("%s is not a table, so it has no row to select", selectorOf(seg))
|
return nil, fmt.Errorf("%s is not a table, so it has no row to select", selectorOf(seg))
|
||||||
@@ -148,7 +147,7 @@ func stepInto(n node, seg string) (node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tableRoute is how a path passes one table: the row it reads, by selector or
|
// tableRoute is how a path passes one table: the row it reads, by selector or
|
||||||
// drawn, and what it goes on into, a linked table it descends to among them.
|
// drawn, what it goes on into, and whether that is a linked table.
|
||||||
type tableRoute struct {
|
type tableRoute struct {
|
||||||
sel string
|
sel string
|
||||||
draw bool
|
draw bool
|
||||||
@@ -188,7 +187,7 @@ func (t *table) route(tail []string, descended bool) (tableRoute, error) {
|
|||||||
// pathCheck 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 names the head in its errors.
|
||||||
type pathCheck struct {
|
type pathCheck struct {
|
||||||
pins pinSet
|
pins pinSet
|
||||||
level string
|
level string
|
||||||
@@ -258,7 +257,6 @@ func (w *pathCheck) enter(t *template, rest []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// pathCover is coverPath's walk: it stops at a choice and reads no row.
|
|
||||||
type pathCover struct{ into map[node]bool }
|
type pathCover struct{ into map[node]bool }
|
||||||
|
|
||||||
func (w *pathCover) walk(n node, tail []string) (node, error) {
|
func (w *pathCover) walk(n node, tail []string) (node, error) {
|
||||||
@@ -285,9 +283,8 @@ func (w *pathCover) walk(n node, tail []string) (node, error) {
|
|||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// pathProbe proves a path resolves, walking one variant of a choice, so a
|
// pathProbe proves a path resolves without drawing: carriedByAll lets one variant
|
||||||
// path that resolves resolves whichever variants and rows are drawn. It draws
|
// of a choice stand for all. It marks in drawn the tables a draw would pin.
|
||||||
// nothing, marking in drawn the tables a draw would pin.
|
|
||||||
type pathProbe struct {
|
type pathProbe struct {
|
||||||
pins pinSet
|
pins pinSet
|
||||||
drawn map[*table]bool
|
drawn map[*table]bool
|
||||||
@@ -345,8 +342,8 @@ type pathDraw struct {
|
|||||||
a *arm
|
a *arm
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 at load, so the walk
|
||||||
// walk cannot fail. head is what n is reached by, for the panic.
|
// cannot fail. head names n in the panic.
|
||||||
func drawPath(n node, tail []string, head string, w *pathDraw) 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 {
|
||||||
@@ -440,8 +437,7 @@ func carriedByAll(c *choice, rest []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// unreachableInChoice reports that a path cannot step through this choice, listing
|
// unreachableInChoice reports that a path cannot step through this choice, listing
|
||||||
// what every variant does carry. It reads the precomputed set, so a failing path
|
// what every variant does carry.
|
||||||
// costs no more than a rendering one.
|
|
||||||
func unreachableInChoice(c *choice, want string) error {
|
func unreachableInChoice(c *choice, want string) error {
|
||||||
if len(c.shared) == 0 {
|
if len(c.shared) == 0 {
|
||||||
return fmt.Errorf("no variant of this %d-way choice carries %q", len(c.items), want)
|
return fmt.Errorf("no variant of this %d-way choice carries %q", len(c.items), want)
|
||||||
@@ -454,8 +450,8 @@ 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 pathCheck does, so a path that validates here
|
// checkPath runs pathCheck over a path read at load; level names the head in its
|
||||||
// resolves on every render, and a typo is a New-time error.
|
// errors.
|
||||||
func checkPath(n node, tail []string, level string) error {
|
func checkPath(n node, tail []string, level string) error {
|
||||||
_, err := (&pathCheck{level: level, tail: tail}).run(n)
|
_, err := (&pathCheck{level: level, tail: tail}).run(n)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -36,14 +36,10 @@ func (f *Generator) Fake(path string) (string, error) {
|
|||||||
return render(f.rand, n, sc), nil
|
return render(f.rand, n, sc), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// descend walks named fields to the node a path names, pinning the table rows it
|
// descend walks a caller's path to the node it names, pinning in sc the rows it
|
||||||
// selects or draws in sc. It is the one render-side step that can fail, because the
|
// selects or draws.
|
||||||
// path comes from the caller and may name a field or a row that does not exist. A
|
|
||||||
// choice consumes no segment, so the rest of the path must be one every variant
|
|
||||||
// carries before a variant is picked — a path that resolves at all resolves on
|
|
||||||
// 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.
|
// docs/decisions.md#a-path-is-walked-once-without-drawing-before-it-is-walked-for-real
|
||||||
if _, err := (&pathProbe{drawn: map[*table]bool{}}).walk(root, segments); err != nil {
|
if _, err := (&pathProbe{drawn: map[*table]bool{}}).walk(root, segments); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user