Run New, NewTemplate and FakeStruct through one bind pipeline naming where they differ
This commit is contained in:
@@ -890,7 +890,7 @@ transform.go the builtins that rewrite an operand's value, and the ASCII fold
|
|||||||
calc.go the {calc()} arithmetic evaluator: parser, eval, validation
|
calc.go the {calc()} arithmetic evaluator: parser, eval, validation
|
||||||
datatype.go column datatypes: DataType, where datatype and null may sit, a column's datatype
|
datatype.go column datatypes: DataType, where datatype and null may sit, a column's datatype
|
||||||
value.go the value proof: what a typed column or calc operand holds, checked at load
|
value.go the value proof: what a typed column or calc operand holds, checked at load
|
||||||
data.go the load path: fs.FS folders/files -> merged namespace tree, and the fence order a scope runs
|
data.go the load path: fs.FS folders/files -> merged namespace tree, and the bind pipeline every entry point runs
|
||||||
cmd/fejkdata/ the fejkdata CLI
|
cmd/fejkdata/ the fejkdata CLI
|
||||||
data/ shipped data (JSON, and a TSV per table), embedded at build: locale folders, geo, misc
|
data/ shipped data (JSON, and a TSV per table), embedded at build: locale folders, geo, misc
|
||||||
data-import/ the scripts that rebuild each sourced table (see DATA-LICENSES.md)
|
data-import/ the scripts that rebuild each sourced table (see DATA-LICENSES.md)
|
||||||
|
|||||||
@@ -62,17 +62,7 @@ func loadData(sources []dataSource) (map[string]node, error) {
|
|||||||
if len(root) == 0 {
|
if len(root) == 0 {
|
||||||
return nil, fmt.Errorf("no .json data found")
|
return nil, fmt.Errorf("no .json data found")
|
||||||
}
|
}
|
||||||
setTablePaths(root)
|
if err := treeBinding(root).bind(); err != nil {
|
||||||
if err := linkTables(root); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := linkRefs(root); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkNoCycles(root); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := checkScope(treeScope(root)); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return root, nil
|
return root, nil
|
||||||
@@ -206,11 +196,50 @@ func inlineScope(n node, label string) nodeScope {
|
|||||||
return func(fn func(path string, m node) error) error { return eachNode(n, label, fn) }
|
return func(fn func(path string, m node) error) error { return eachNode(n, label, fn) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkScope(s nodeScope) error {
|
// binding is one entry point's nodes on their way through bind, the load pipeline New,
|
||||||
if err := checkColumns(s); err != nil {
|
// NewTemplate and FakeStruct share; its fields are where they differ.
|
||||||
|
type binding struct {
|
||||||
|
scope nodeScope
|
||||||
|
// link binds the references: a loaded tree's relative to each category's folder, an
|
||||||
|
// inline node's from the root alone.
|
||||||
|
link func() error
|
||||||
|
// noCycles refuses a reference cycle, which only a loaded tree can close: nothing
|
||||||
|
// references an inline node.
|
||||||
|
noCycles func() error
|
||||||
|
// typedByGo marks a struct's columns, whose datatypes its Go types set and checkField
|
||||||
|
// proves, so checkColumns skips them.
|
||||||
|
typedByGo bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func treeBinding(root map[string]node) binding {
|
||||||
|
return binding{
|
||||||
|
scope: treeScope(root),
|
||||||
|
link: func() error {
|
||||||
|
setTablePaths(root)
|
||||||
|
if err := linkTables(root); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return linkRefs(root)
|
||||||
|
},
|
||||||
|
noCycles: func() error { return checkNoCycles(root) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b binding) bind() error {
|
||||||
|
if err := b.link(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return checkRenders(s)
|
if b.noCycles != nil {
|
||||||
|
if err := b.noCycles(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !b.typedByGo {
|
||||||
|
if err := checkColumns(b.scope); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checkRenders(b.scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkRenders runs the per-node fences over a scope, each over the whole scope
|
// checkRenders runs the per-node fences over a scope, each over the whole scope
|
||||||
|
|||||||
+1
-1
@@ -57,7 +57,7 @@ tags and any other caller read one.
|
|||||||
|
|
||||||
`New` proves the loaded tree acyclic, an inline node is a finite tree of its own, and
|
`New` proves the loaded tree acyclic, an inline node is a finite tree of its own, and
|
||||||
nothing in the tree can reference it, so no render of it reaches itself. Every other
|
nothing in the tree can reference it, so no render of it reaches itself. Every other
|
||||||
fence runs over both, from one `checkScope`, except that struct tags leave column
|
fence runs over both, from one `binding.bind`, except that struct tags leave column
|
||||||
agreement to their Go types.
|
agreement to their Go types.
|
||||||
|
|
||||||
## An inline template that does not compile is misuse (exit 2), including a reference that resolves to nothing
|
## An inline template that does not compile is misuse (exit 2), including a reference that resolves to nothing
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func (f *Generator) NewTemplate(input string) (*Template, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("fejkdata: %w", err)
|
return nil, fmt.Errorf("fejkdata: %w", err)
|
||||||
}
|
}
|
||||||
if err := bindInline(n, "template", f.categories, checkScope); err != nil {
|
if err := inlineBinding(n, "template", f.categories).bind(); err != nil {
|
||||||
return nil, fmt.Errorf("fejkdata: %w", err)
|
return nil, fmt.Errorf("fejkdata: %w", err)
|
||||||
}
|
}
|
||||||
return &Template{g: f, n: n}, nil
|
return &Template{g: f, n: n}, nil
|
||||||
@@ -146,17 +146,17 @@ func inputValue(input string) (any, error) {
|
|||||||
return raw, nil
|
return raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindInline links an inline node's references against root and runs check over it, naming its
|
// inlineBinding binds an inline node against root, naming its nodes from label.
|
||||||
// nodes from label.
|
func inlineBinding(n node, label string, root map[string]node) binding {
|
||||||
func bindInline(n node, label string, root map[string]node, check func(nodeScope) error) error {
|
scope := inlineScope(n, label)
|
||||||
|
return binding{scope: scope, link: func() error { return linkInline(n, label, scope, root) }}
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkInline(n node, label string, scope nodeScope, root map[string]node) error {
|
||||||
if t, isTemplate := n.(*template); isTemplate && t.drawGroup != "" {
|
if t, isTemplate := n.(*template); isTemplate && t.drawGroup != "" {
|
||||||
return fmt.Errorf("%s: drawGroup %q names nothing, since nothing can reference an inline template; drop it", label, t.drawGroup)
|
return fmt.Errorf("%s: drawGroup %q names nothing, since nothing can reference an inline template; drop it", label, t.drawGroup)
|
||||||
}
|
}
|
||||||
scope := inlineScope(n, label)
|
return linkNodeRefs(scope, root)
|
||||||
if err := linkNodeRefs(scope, root); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return check(scope)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkNodeRefs binds the references in an inline node's templates against the
|
// linkNodeRefs binds the references in an inline node's templates against the
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ func TestEveryFormatCompilesAtLink(t *testing.T) {
|
|||||||
t.Errorf("%s compiled before link", format)
|
t.Errorf("%s compiled before link", format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := bindInline(n, "t", map[string]node{"w": w}, func(nodeScope) error { return nil }); err != nil {
|
if err := linkInline(n, "t", inlineScope(n, "t"), map[string]node{"w": w}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for format, has := range compiledByPath() {
|
for format, has := range compiledByPath() {
|
||||||
|
|||||||
@@ -258,7 +258,9 @@ func (s *structShape) compileRecord(categories map[string]node, t reflect.Type,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s: %w", label, err)
|
return fmt.Errorf("%s: %w", label, err)
|
||||||
}
|
}
|
||||||
if err := bindInline(n, label, categories, checkRenders); err != nil {
|
b := inlineBinding(n, label, categories)
|
||||||
|
b.typedByGo = true
|
||||||
|
if err := b.bind(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
record, columns, err := recordOf(n)
|
record, columns, err := recordOf(n)
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ Self-sufficiency 5.6), every seat capped by Locality, and all nine naming
|
|||||||
|
|
||||||
This round, in order:
|
This round, in order:
|
||||||
|
|
||||||
- Run `New`, `NewTemplate` and `FakeStruct` through one bind pipeline that names
|
|
||||||
where they differ: each picks its own fences today.
|
|
||||||
- Make `disagreement` and `bothTyped` a table of cases: each swaps its operands and
|
- Make `disagreement` and `bothTyped` a table of cases: each swaps its operands and
|
||||||
runs a proof to pick an error's wording.
|
runs a proof to pick an error's wording.
|
||||||
- Derive a column's datatype in one place: `columnItems` yields nothing for a
|
- Derive a column's datatype in one place: `columnItems` yields nothing for a
|
||||||
|
|||||||
Reference in New Issue
Block a user