Answer stability round 2, prose round 2 and product-owner round 2: a head may be a name, scope and link come before the entries using them, a path reaches a node, and resolve ties a reference or a name
This commit is contained in:
@@ -962,7 +962,7 @@ name.go names: {x as n} bindings, the scopes they live in, and the reads
|
||||
namefence.go the load fences over names
|
||||
pick.go a render's named picks: the frames of the name scopes rendering, the memo a pick keeps, and the reads kept under it
|
||||
env.go renderEnv: what a render reads names and rows through
|
||||
path.go the dotted-path walks, and proving a path resolves
|
||||
path.go the dotted-path walks, and proving a path reaches a node
|
||||
render.go Fake, the recursive renderer (choices, format strings, expansions) and the reads its tokens make
|
||||
record.go records: Record, the JSON/CSV/SQL serializers, and their entry points
|
||||
struct.go structs: FakeStruct, fake tags as one record's columns, and a field's Go type as its column's datatype
|
||||
|
||||
@@ -66,8 +66,8 @@ func mergeChildren(dst, src map[string]node) {
|
||||
}
|
||||
}
|
||||
|
||||
// nodeSet is the set of nodes one validation pass covers: the categories one load
|
||||
// reads, or a single inline node.
|
||||
// nodeSet is the set of nodes one validation pass covers: one load's categories, or a
|
||||
// single inline node.
|
||||
type nodeSet func(fn func(label string, n node) error) error
|
||||
|
||||
// categorySite is a loaded category and where it sits: the folder holding it, that
|
||||
|
||||
@@ -23,22 +23,22 @@ package fejkdata
|
||||
// `Generator.Fake`, `FakeRecord`, `Template.Fake` and `RecordTemplate.Fake`
|
||||
// start one each, and `FakeStruct` one per record.
|
||||
// - env — what a render reads names and rows through: `renderEnv`.
|
||||
// - scope — where a name is bound: a category, or one repeat iteration: `nameScope`.
|
||||
// - named pick — the draw a token such as {/person as p} binds to a name, drawn
|
||||
// on its first read and kept while its scope renders: `nameBinding`,
|
||||
// `namedPick`, `pickFrame`.
|
||||
// - scope — where a name is bound: a category, or one repeat iteration: `nameScope`.
|
||||
// - memo — what a named pick keeps its draws in, the variant drawn at each level
|
||||
// and the value each path read: `drawMemo`.
|
||||
// - pin — fixing which row of a table one path, or one named pick, uses:
|
||||
// `pinSet`, `namedPick.pins`, `table.drawStep`.
|
||||
// - family — a table and every table reaching it through a chain of parent
|
||||
// links.
|
||||
// - link — a table's tie to its parent table, each row to its parent row:
|
||||
// `table.linkParent`.
|
||||
// - resolve — tying each template's references and names to the assembled tree:
|
||||
// `resolveTemplates`.
|
||||
// - head — the string a read starts from: a field's name, or a reference's
|
||||
// category path with its sigil, /sv_SE.address: `arm.head`. The node it names is
|
||||
// - family — a table and every table reaching it through a chain of parent
|
||||
// links.
|
||||
// - resolve — tying a reference or a name to what it names in the assembled tree:
|
||||
// `resolveTemplates`, `resolveRefs`.
|
||||
// - head — the string a read starts from: a field or a name as written, or a
|
||||
// reference's category path with its sigil, /sv_SE.address: `arm.head`. The node it names is
|
||||
// the read's start: `template.startOf`, `nameTarget.start`.
|
||||
// - fence — a load-time check, run over each category, template or struct as it
|
||||
// loads or compiles, so rendering a compiled tree cannot fail.
|
||||
|
||||
@@ -159,7 +159,7 @@ func checkArm(name string, fields map[string]node, wholeToken bool) (missing boo
|
||||
}
|
||||
return true, fmt.Errorf("no field %q", a.head)
|
||||
}
|
||||
if err := checkPathResolves(field, a.tail, a.head); err != nil {
|
||||
if err := checkPathReaches(field, a.tail, a.head); err != nil {
|
||||
return false, fmt.Errorf("field %q: %w", a.head, err)
|
||||
}
|
||||
return false, nil
|
||||
@@ -341,7 +341,7 @@ func (t *template) compileArm(name string, targets map[*nameBinding]nameTarget)
|
||||
}
|
||||
target := targets[b]
|
||||
full := append(target.tail[:len(target.tail):len(target.tail)], a.tail...)
|
||||
if err := checkPathResolves(target.start, full, a.head); err != nil {
|
||||
if err := checkPathReaches(target.start, full, a.head); err != nil {
|
||||
return a, err
|
||||
}
|
||||
w := compilePath(target.start, full)
|
||||
|
||||
@@ -111,7 +111,7 @@ const (
|
||||
stepParent // up to the table's parent, at the row its own row links to
|
||||
)
|
||||
|
||||
// pathCheck proves a path resolves whichever way the draws go: every variant of a
|
||||
// pathCheck proves a path reaches a node 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
|
||||
// rows selected before it, and no level read carries a repeat. It compiles the steps
|
||||
// a draw takes, and every leaf the path may render; level names the head in its errors.
|
||||
@@ -237,7 +237,7 @@ func (w *pathCheck) walkEvery(c *choice, tail []string) (node, error) {
|
||||
return last, nil
|
||||
}
|
||||
|
||||
// probePath proves a path resolves without drawing, appending to steps the steps a
|
||||
// probePath proves a path reaches a node without drawing, appending to steps the steps a
|
||||
// draw takes. Where pathCheck walks every variant of a choice, it walks the first,
|
||||
// which carriedByAll lets stand for all.
|
||||
func probePath(n node, tail []string, steps []pathStep) ([]pathStep, error) {
|
||||
@@ -346,7 +346,7 @@ func (t *table) step(tail []string) (column node, child *table, err error) {
|
||||
return nil, d.Owner(), nil
|
||||
}
|
||||
|
||||
// carriedByAll is the choice rule a path that must resolve on every call obeys:
|
||||
// carriedByAll is the choice rule a path that must reach a node on every call obeys:
|
||||
// the rest of the tail must be one every variant carries.
|
||||
func carriedByAll(c *choice, rest []string) error {
|
||||
if want := strings.Join(rest, "."); !c.shared[want] {
|
||||
@@ -365,7 +365,7 @@ 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)
|
||||
}
|
||||
|
||||
func checkPathResolves(n node, tail []string, level string) error {
|
||||
func checkPathReaches(n node, tail []string, level string) error {
|
||||
_, err := (&pathCheck{level: level, tail: tail}).run(n)
|
||||
return err
|
||||
}
|
||||
|
||||
+1
-1
@@ -129,7 +129,7 @@ func TestPathKeyIsUnambiguous(t *testing.T) {
|
||||
if err == nil || !strings.Contains(err.Error(), `field "a.b" contains "."`) {
|
||||
t.Fatalf("New = %v, want the dotted field name rejected", err)
|
||||
}
|
||||
// The same data without the dotted key is fine, and the path resolves.
|
||||
// The same data without the dotted key is fine, and the path reaches a node.
|
||||
f := newGenerator(t, writeData(t, map[string]string{
|
||||
"cat": `{"format":"{a.b}","a":{"format":"{b}","b":"2"}}`,
|
||||
}), WithSeed(1))
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ func (t *template) resolveRefs(folder []string, label, category string, root map
|
||||
if category != "" && head == "/"+category {
|
||||
return refs, fmt.Errorf("%s: reference {%s}: names the category it sits in; read a sibling field as a path, or move the shared value into its own category and reference that", label, name)
|
||||
}
|
||||
if err := checkPathResolves(target, tail, head); err != nil {
|
||||
if err := checkPathReaches(target, tail, head); err != nil {
|
||||
return refs, fmt.Errorf("%s: reference {%s}: %w", label, name, err)
|
||||
}
|
||||
refs.categories[head] = target
|
||||
|
||||
Reference in New Issue
Block a user