Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
11 changed files with 34 additions and 33 deletions
Showing only changes of commit 4f484cd780 - Show all commits
+1 -1
View File
@@ -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. // checkCalcNames holds each calc of t reading a name to the checks checkCalcFields makes of a field.
func checkCalcNames(path string, t *template) error { func checkCalcNames(path string, t *template) error {
for _, o := range t.compiled.ops { 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 continue
} }
if err := checkOperands(o.Args[0], builtinfunc.ParsedCalc(o.Args[0]), operandNodes(o)); err != nil { if err := checkOperands(o.Args[0], builtinfunc.ParsedCalc(o.Args[0]), operandNodes(o)); err != nil {
+1 -1
View File
@@ -17,7 +17,7 @@ services:
cover: cover:
<<: *go <<: *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: bench:
<<: *go <<: *go
+4 -4
View File
@@ -11,7 +11,7 @@ func loadData(sources []datafiles.Source) (map[string]node, error) {
root := map[string]node{} root := map[string]node{}
for _, src := range sources { for _, src := range sources {
g := &folder{children: map[string]node{}} 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 return nil, err
} }
mergeChildren(root, g.children) mergeChildren(root, g.children)
@@ -25,14 +25,14 @@ func loadData(sources []datafiles.Source) (map[string]node, error) {
return root, nil return root, nil
} }
// compileInto compiles each category it is handed into its folder under root. // compileInto compiles each category it is handed into the folder place finds for its dir.
func compileInto(root *folder) func(datafiles.Category) error { func compileInto(place func(dir []string) *folder) func(datafiles.Category) error {
return func(c datafiles.Category) error { return func(c datafiles.Category) error {
n, err := compileCategory(c.JSON, c.Name, c.ReadRows) n, err := compileCategory(c.JSON, c.Name, c.ReadRows)
if err != nil { if err != nil {
return err return err
} }
madeFolder(root, c.Dir).children[c.Name] = n place(c.Dir).children[c.Name] = n
return nil return nil
} }
} }
+6 -5
View File
@@ -8,15 +8,16 @@ import (
"github.com/larvit/fejkdata/internal/invariant" "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 type DataType = datatype.DataType
// The datatypes a column declares with "datatype"; a column without one is a string. // The datatypes a column declares with "datatype"; a column without one is a string.
const ( const (
DataTypeString = datatype.String DataTypeString DataType = datatype.String
DataTypeInteger = datatype.Integer DataTypeInteger DataType = datatype.Integer
DataTypeNumber = datatype.Number DataTypeNumber DataType = datatype.Number
DataTypeBoolean = datatype.Boolean DataTypeBoolean DataType = datatype.Boolean
) )
// position is where a JSON value sits, which decides whether it may carry a datatype or // position is where a JSON value sits, which decides whether it may carry a datatype or
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// operands fields holds. // operands fields holds.
func checkFunc(tok grammar.Token, fields map[string]node) error { func checkFunc(tok grammar.Token, fields map[string]node) error {
err := builtinfunc.Check(tok.Fn, tok.Args) 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) err = checkCalcFields(tok.Args, fields)
} }
if err != nil { if err != nil {
+4 -4
View File
@@ -43,9 +43,9 @@ type builtin struct {
prints datatype.DataType prints datatype.DataType
} }
// Calc is the name of the builtin whose operands the caller checks and proves, as nodes only // CalcName is the builtin whose operands the engine checks and proves, since only the engine
// it holds. // holds their nodes.
const Calc = "calc" const CalcName = "calc"
// rng is the randomness a builtin sample draws from, which *drawstate.State satisfies. // rng is the randomness a builtin sample draws from, which *drawstate.State satisfies.
type rng interface { type rng interface {
@@ -115,7 +115,7 @@ func numberCalls(text bool) string {
} }
} }
slices.Sort(calls) slices.Sort(calls)
return strings.Join(calls, ", ") + " or {calc()}" return strings.Join(calls, ", ") + " or {" + CalcName + "()}"
} }
func plural(n int) string { func plural(n int) string {
+3 -3
View File
@@ -64,9 +64,9 @@ var builtins = withTransforms(map[string]builtin{
cc := a[0] cc := a[0]
return func(s *drawstate.State, _ string, _ []string) string { return iban(s, cc) } return func(s *drawstate.State, _ string, _ []string) string { return iban(s, cc) }
}}, }},
"date": {arity: -1, checkArgs: dateArgs, prep: datePrep}, "date": {arity: -1, checkArgs: dateArgs, prep: datePrep},
"time": {arity: -1, checkArgs: timeArg, prep: timePrep}, "time": {arity: -1, checkArgs: timeArg, prep: timePrep},
Calc: {arity: -1, checkArgs: checkCalc, prep: calcPrep, operands: calcOperands, noRefOperands: true}, 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 // 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 // each call. An optional name selects an independent counter; no name uses the
// default one. Deterministic by construction, so seeded output stays stable. // default one. Deterministic by construction, so seeded output stays stable.
+2 -2
View File
@@ -47,8 +47,8 @@ func (v Value) Or(w Value) Value {
return v return v
} }
// Calc bounds a calc expression from its operands, or says why it cannot. // OfCalc bounds a calc expression from its operands, or says why it cannot.
func Calc(expr grammar.CalcNode, operand func(name string) Value) (Value, string) { func OfCalc(expr grammar.CalcNode, operand func(name string) Value) (Value, string) {
v, doubt := bound(expr, operand) v, doubt := bound(expr, operand)
if doubt == "" && !(magnitude(v) <= limit) { if doubt == "" && !(magnitude(v) <= limit) {
doubt = grammar.CalcText(expr) + " is not proven within 1e300" doubt = grammar.CalcText(expr) + " is not proven within 1e300"
+7 -7
View File
@@ -41,7 +41,7 @@ func TestOrKeepsTheBoundsOfBothAndTheFirstReason(t *testing.T) {
} }
} }
func TestCalcBoundsAnExpressionFromItsOperands(t *testing.T) { func TestOfCalcBoundsAnExpressionFromItsOperands(t *testing.T) {
operand := func(name string) Value { 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] 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 { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
v, doubt := Calc(c.Expr, operand) v, doubt := OfCalc(c.Expr, operand)
if doubt != want { 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) { 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) { 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") lone, _ := grammar.ParseCalc("x")
if _, doubt := Calc(lone.Expr, func(string) Value { return Bounded(0, 1e301, true) }); doubt != "x is not proven within 1e300" { if _, doubt := OfCalc(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) t.Errorf("OfCalc(x) doubts %q, want a lone operand held to the limit", doubt)
} }
} }
+3 -3
View File
@@ -99,7 +99,7 @@ func loadShipped(root *folder, wanted []unloadedCategory) {
if !unloaded { if !unloaded {
continue continue
} }
site, err := u.load(root) site, err := u.load()
if err != nil { 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)) 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 // load parses and compiles the category, and moves it from its folder's unloaded map to
// the folder's children. // the folder's children.
func (u unloadedCategory) load(root *folder) (categorySite, error) { func (u unloadedCategory) load() (categorySite, error) {
if err := shippedSource.Load(u.dir, u.name, compileInto(root)); err != nil { if err := shippedSource.Load(u.dir, u.name, compileInto(func([]string) *folder { return u.in })); err != nil {
return categorySite{}, err return categorySite{}, err
} }
delete(u.in.unloaded, u.name) delete(u.in.unloaded, u.name)
+2 -2
View File
@@ -173,7 +173,7 @@ func (p *valueProof) proveTemplate(t *template) proven.Value {
leaves = append(leaves, a.leaves...) leaves = append(leaves, a.leaves...)
} }
return p.proveUnion(leaves) return p.proveUnion(leaves)
case name == builtinfunc.Calc: case name == builtinfunc.CalcName:
return p.proveCalc(o) return p.proveCalc(o)
case builtinfunc.IsTransform(name): case builtinfunc.IsTransform(name):
return proven.Unproven(fmt.Sprintf("{%s} rewrites text rather than printing a value; write the values it would print", body)) 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 { func (p *valueProof) proveCalc(o op) proven.Value {
body, args := o.Body, o.Args body, args := o.Body, o.Args
nodes := operandNodes(o) 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 != "" { if doubt != "" {
return proven.Unproven(fmt.Sprintf("{%s}: %s", body, doubt)) return proven.Unproven(fmt.Sprintf("{%s}: %s", body, doubt))
} }