From 4f484cd780e8e38cb01634bc3602c7127adc48f7 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Mon, 5 Oct 2026 15:53:56 +0200 Subject: [PATCH] Answer architecture round 3, stability round 1 and product-owner round 1: CalcName and proven.OfCalc for one meaning per name, a lazy load placed where its lookup found it, DataType's constants typed under it, and cover printing the module's total --- calc.go | 2 +- compose.yaml | 2 +- data.go | 8 ++++---- datatype.go | 11 ++++++----- format.go | 2 +- internal/builtinfunc/builtinfunc.go | 8 ++++---- internal/builtinfunc/builtins.go | 6 +++--- internal/proven/proven.go | 4 ++-- internal/proven/proven_test.go | 14 +++++++------- shipped.go | 6 +++--- valueproof.go | 4 ++-- 11 files changed, 34 insertions(+), 33 deletions(-) diff --git a/calc.go b/calc.go index 818349b..c013ad5 100644 --- a/calc.go +++ b/calc.go @@ -26,7 +26,7 @@ func checkCalcFields(args []string, fields map[string]node) error { // checkCalcNames holds each calc of t reading a name to the checks checkCalcFields makes of a field. func checkCalcNames(path string, t *template) error { for _, o := range t.compiled.ops { - if o.Fn != builtinfunc.Calc || !slices.ContainsFunc(o.operands, func(a arm) bool { return a.kind == namedRead }) { + if o.Fn != builtinfunc.CalcName || !slices.ContainsFunc(o.operands, func(a arm) bool { return a.kind == namedRead }) { continue } if err := checkOperands(o.Args[0], builtinfunc.ParsedCalc(o.Args[0]), operandNodes(o)); err != nil { diff --git a/compose.yaml b/compose.yaml index 7540813..2a948af 100644 --- a/compose.yaml +++ b/compose.yaml @@ -17,7 +17,7 @@ services: cover: <<: *go - command: go test -cover -coverpkg=./... ./... + command: sh -c "go test -coverpkg=./... -coverprofile=/tmp/cover.out ./... && go tool cover -func=/tmp/cover.out | tail -1" bench: <<: *go diff --git a/data.go b/data.go index 3ec2993..6baa542 100644 --- a/data.go +++ b/data.go @@ -11,7 +11,7 @@ func loadData(sources []datafiles.Source) (map[string]node, error) { root := map[string]node{} for _, src := range sources { g := &folder{children: map[string]node{}} - if err := src.Walk(compileInto(g)); err != nil { + if err := src.Walk(compileInto(func(dir []string) *folder { return madeFolder(g, dir) })); err != nil { return nil, err } mergeChildren(root, g.children) @@ -25,14 +25,14 @@ func loadData(sources []datafiles.Source) (map[string]node, error) { return root, nil } -// compileInto compiles each category it is handed into its folder under root. -func compileInto(root *folder) func(datafiles.Category) error { +// compileInto compiles each category it is handed into the folder place finds for its dir. +func compileInto(place func(dir []string) *folder) func(datafiles.Category) error { return func(c datafiles.Category) error { n, err := compileCategory(c.JSON, c.Name, c.ReadRows) if err != nil { return err } - madeFolder(root, c.Dir).children[c.Name] = n + place(c.Dir).children[c.Name] = n return nil } } diff --git a/datatype.go b/datatype.go index ed6a782..063fc3e 100644 --- a/datatype.go +++ b/datatype.go @@ -8,15 +8,16 @@ import ( "github.com/larvit/fejkdata/internal/invariant" ) -// DataType is what a record column holds, which decides how a record writes its value. +// DataType is what a record column holds, which decides how a record writes its value. It +// prints as data spells it: string, integer, number or boolean. type DataType = datatype.DataType // The datatypes a column declares with "datatype"; a column without one is a string. const ( - DataTypeString = datatype.String - DataTypeInteger = datatype.Integer - DataTypeNumber = datatype.Number - DataTypeBoolean = datatype.Boolean + DataTypeString DataType = datatype.String + DataTypeInteger DataType = datatype.Integer + DataTypeNumber DataType = datatype.Number + DataTypeBoolean DataType = datatype.Boolean ) // position is where a JSON value sits, which decides whether it may carry a datatype or diff --git a/format.go b/format.go index 65de46e..04ae748 100644 --- a/format.go +++ b/format.go @@ -12,7 +12,7 @@ import ( // operands fields holds. func checkFunc(tok grammar.Token, fields map[string]node) error { err := builtinfunc.Check(tok.Fn, tok.Args) - if err == nil && tok.Fn == builtinfunc.Calc { + if err == nil && tok.Fn == builtinfunc.CalcName { err = checkCalcFields(tok.Args, fields) } if err != nil { diff --git a/internal/builtinfunc/builtinfunc.go b/internal/builtinfunc/builtinfunc.go index b6baf16..0a5c00f 100644 --- a/internal/builtinfunc/builtinfunc.go +++ b/internal/builtinfunc/builtinfunc.go @@ -43,9 +43,9 @@ type builtin struct { prints datatype.DataType } -// Calc is the name of the builtin whose operands the caller checks and proves, as nodes only -// it holds. -const Calc = "calc" +// CalcName is the builtin whose operands the engine checks and proves, since only the engine +// holds their nodes. +const CalcName = "calc" // rng is the randomness a builtin sample draws from, which *drawstate.State satisfies. type rng interface { @@ -115,7 +115,7 @@ func numberCalls(text bool) string { } } slices.Sort(calls) - return strings.Join(calls, ", ") + " or {calc()}" + return strings.Join(calls, ", ") + " or {" + CalcName + "()}" } func plural(n int) string { diff --git a/internal/builtinfunc/builtins.go b/internal/builtinfunc/builtins.go index 8696650..bc27abe 100644 --- a/internal/builtinfunc/builtins.go +++ b/internal/builtinfunc/builtins.go @@ -64,9 +64,9 @@ var builtins = withTransforms(map[string]builtin{ cc := a[0] return func(s *drawstate.State, _ string, _ []string) string { return iban(s, cc) } }}, - "date": {arity: -1, checkArgs: dateArgs, prep: datePrep}, - "time": {arity: -1, checkArgs: timeArg, prep: timePrep}, - Calc: {arity: -1, checkArgs: checkCalc, prep: calcPrep, operands: calcOperands, noRefOperands: true}, + "date": {arity: -1, checkArgs: dateArgs, prep: datePrep}, + "time": {arity: -1, checkArgs: timeArg, prep: timePrep}, + CalcName: {arity: -1, checkArgs: checkCalc, prep: calcPrep, operands: calcOperands, noRefOperands: true}, // seq is the one stateful builtin: a per-generator counter from 1, advancing on // each call. An optional name selects an independent counter; no name uses the // default one. Deterministic by construction, so seeded output stays stable. diff --git a/internal/proven/proven.go b/internal/proven/proven.go index d5fc48e..2f9e499 100644 --- a/internal/proven/proven.go +++ b/internal/proven/proven.go @@ -47,8 +47,8 @@ func (v Value) Or(w Value) Value { return v } -// Calc bounds a calc expression from its operands, or says why it cannot. -func Calc(expr grammar.CalcNode, operand func(name string) Value) (Value, string) { +// OfCalc bounds a calc expression from its operands, or says why it cannot. +func OfCalc(expr grammar.CalcNode, operand func(name string) Value) (Value, string) { v, doubt := bound(expr, operand) if doubt == "" && !(magnitude(v) <= limit) { doubt = grammar.CalcText(expr) + " is not proven within 1e300" diff --git a/internal/proven/proven_test.go b/internal/proven/proven_test.go index 6f5ec11..87b172a 100644 --- a/internal/proven/proven_test.go +++ b/internal/proven/proven_test.go @@ -41,7 +41,7 @@ func TestOrKeepsTheBoundsOfBothAndTheFirstReason(t *testing.T) { } } -func TestCalcBoundsAnExpressionFromItsOperands(t *testing.T) { +func TestOfCalcBoundsAnExpressionFromItsOperands(t *testing.T) { operand := func(name string) Value { return map[string]Value{"a": Bounded(1, 9, true), "b": Bounded(0, 9, true), "big": Bounded(0, 1e299, true), "word": Unproven("it is text")}[name] } @@ -57,20 +57,20 @@ func TestCalcBoundsAnExpressionFromItsOperands(t *testing.T) { if err != nil { t.Fatal(err) } - v, doubt := Calc(c.Expr, operand) + v, doubt := OfCalc(c.Expr, operand) if doubt != want { - t.Errorf("Calc(%s) doubts %q, want %q", expr, doubt, want) + t.Errorf("OfCalc(%s) doubts %q, want %q", expr, doubt, want) } if expr == "a * 2 + 1" && (v.Lo != 3 || v.Hi != 19 || !v.Integral || v.NonZero != 3) { - t.Errorf("Calc(%s) = %+v, want [3, 19], integral, nonzero by 3", expr, v) + t.Errorf("OfCalc(%s) = %+v, want [3, 19], integral, nonzero by 3", expr, v) } if expr == "-(a - 10)" && (v.Lo != 1 || v.Hi != 9) { - t.Errorf("Calc(%s) = %+v, want [1, 9]", expr, v) + t.Errorf("OfCalc(%s) = %+v, want [1, 9]", expr, v) } } lone, _ := grammar.ParseCalc("x") - if _, doubt := Calc(lone.Expr, func(string) Value { return Bounded(0, 1e301, true) }); doubt != "x is not proven within 1e300" { - t.Errorf("Calc(x) doubts %q, want a lone operand held to the limit", doubt) + if _, doubt := OfCalc(lone.Expr, func(string) Value { return Bounded(0, 1e301, true) }); doubt != "x is not proven within 1e300" { + t.Errorf("OfCalc(x) doubts %q, want a lone operand held to the limit", doubt) } } diff --git a/shipped.go b/shipped.go index 38792d0..05bd208 100644 --- a/shipped.go +++ b/shipped.go @@ -99,7 +99,7 @@ func loadShipped(root *folder, wanted []unloadedCategory) { if !unloaded { continue } - site, err := u.load(root) + site, err := u.load() if err != nil { panic(invariant.Broken("shipped %s: %v; after a change under data/, regenerate shippedindex.go", join(strings.Join(u.dir, "."), u.name), err)) } @@ -117,8 +117,8 @@ func loadShipped(root *folder, wanted []unloadedCategory) { // load parses and compiles the category, and moves it from its folder's unloaded map to // the folder's children. -func (u unloadedCategory) load(root *folder) (categorySite, error) { - if err := shippedSource.Load(u.dir, u.name, compileInto(root)); err != nil { +func (u unloadedCategory) load() (categorySite, error) { + if err := shippedSource.Load(u.dir, u.name, compileInto(func([]string) *folder { return u.in })); err != nil { return categorySite{}, err } delete(u.in.unloaded, u.name) diff --git a/valueproof.go b/valueproof.go index 40bf2b3..163b9a0 100644 --- a/valueproof.go +++ b/valueproof.go @@ -173,7 +173,7 @@ func (p *valueProof) proveTemplate(t *template) proven.Value { leaves = append(leaves, a.leaves...) } return p.proveUnion(leaves) - case name == builtinfunc.Calc: + case name == builtinfunc.CalcName: return p.proveCalc(o) case builtinfunc.IsTransform(name): return proven.Unproven(fmt.Sprintf("{%s} rewrites text rather than printing a value; write the values it would print", body)) @@ -187,7 +187,7 @@ func (p *valueProof) proveTemplate(t *template) proven.Value { func (p *valueProof) proveCalc(o op) proven.Value { body, args := o.Body, o.Args nodes := operandNodes(o) - v, doubt := proven.Calc(builtinfunc.ParsedCalc(args[0]).Expr, func(name string) proven.Value { return p.proveUnion(nodes(name)) }) + v, doubt := proven.OfCalc(builtinfunc.ParsedCalc(args[0]).Expr, func(name string) proven.Value { return p.proveUnion(nodes(name)) }) if doubt != "" { return proven.Unproven(fmt.Sprintf("{%s}: %s", body, doubt)) }