Answer architecture round 2: guard Noun's range, name calc once as builtinfunc.Calc, and place readTableOptions in item 46

This commit is contained in:
2026-10-05 15:48:34 +02:00
committed by Lillem4n
parent a229ae90a2
commit 679bd43c7c
7 changed files with 15 additions and 6 deletions
+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 != "calc" || !slices.ContainsFunc(o.operands, func(a arm) bool { return a.kind == namedRead }) { if o.Fn != builtinfunc.Calc || !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
@@ -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 == "calc" { if err == nil && tok.Fn == builtinfunc.Calc {
err = checkCalcFields(tok.Args, fields) err = checkCalcFields(tok.Args, fields)
} }
if err != nil { if err != nil {
+4
View File
@@ -43,6 +43,10 @@ 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
// it holds.
const Calc = "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 {
IntN(n int) int IntN(n int) int
+1 -1
View File
@@ -66,7 +66,7 @@ var builtins = withTransforms(map[string]builtin{
}}, }},
"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}, Calc: {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.
+6 -1
View File
@@ -31,4 +31,9 @@ func (d DataType) String() string {
} }
// Noun is the datatype as an error names what a value is. // Noun is the datatype as an error names what a value is.
func Noun(d DataType) string { return nouns[d] } func Noun(d DataType) string {
if d < 0 || d >= Count {
return d.String()
}
return nouns[d]
}
+1 -1
View File
@@ -380,7 +380,7 @@ Require the path step to reach a sibling category.
### 46. Report the same error every load for a table with two bad options, and for a folder with two unnamed rows files. ### 46. Report the same error every load for a table with two bad options, and for a folder with two unnamed rows files.
`readTableOptions` and `walkDir` in `internal/datafiles` return on the first in Go's map order. `readTableOptions` in `table.go` and `walkDir` in `internal/datafiles` return on the first in Go's map order.
### 107. Move the template engine into `internal/`, leaving the root the public API and its options. ### 107. Move the template engine into `internal/`, leaving the root the public API and its options.
+1 -1
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 == "calc": case name == builtinfunc.Calc:
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))