Answer prose round 1: the restructure in three named parts, Category.Folders and proven.Facts for one meaning per name, plainer builtinfunc and datafiles comments, and no false iban rationale

This commit is contained in:
2026-10-05 15:59:32 +02:00
committed by Lillem4n
parent 4f484cd780
commit 643efc8650
16 changed files with 79 additions and 84 deletions
+10 -12
View File
@@ -17,12 +17,9 @@ import (
// values of the operands it named, which the caller read for it.
type Call func(s *drawstate.State, emitted string, operands []string) string
// builtin is a format-string function invoked as {name(args)}. It receives the
// draw state, the output emitted so far in the current expansion (for derivations
// such as a checksum over preceding digits), and the values of the operands it named
// (calc and the transforms name them). All must stay pure over (draw state, emitted, operands) so
// seeded output is reproducible. arity is the exact arg count, or -1 for variadic (then
// checkArgs does all the validation).
// builtin is a format-string function invoked as {name(args)}. Its Call stays pure over its
// inputs, so seeded output is reproducible. arity is the exact arg count, or -1 for variadic,
// where checkArgs does all the validation.
type builtin struct {
arity int
// prep parses validated args once, at compile time, into the closure a render calls.
@@ -36,15 +33,15 @@ type builtin struct {
// proveNumber bounds the number a call's text reads as, token its body, and says which
// datatypes that text is not; set it where every render reads as a finite number, which
// makes the call a calc operand, and leave it nil otherwise.
proveNumber func(token string, prints datatype.DataType, args []string) proven.Value
proveNumber func(token string, prints datatype.DataType, args []string) proven.Facts
// prints is the datatype a call's text is, handed to proveNumber: datatype.String where it
// reads as a number no column should type, as digits' leading zeros; unset where
// proveNumber is nil.
prints datatype.DataType
}
// CalcName is the builtin whose operands the engine checks and proves, since only the engine
// holds their nodes.
// CalcName is the builtin whose operands package fejkdata checks and proves, since only it
// holds the nodes they read.
const CalcName = "calc"
// rng is the randomness a builtin sample draws from, which *drawstate.State satisfies.
@@ -92,11 +89,12 @@ func IsTransform(name string) bool {
}
// ProveNumber proves a call whose every render reads as a finite number, token its body;
// false for any other call. A calc's proof reads its operands, which the caller proves.
func ProveNumber(name, token string, args []string) (proven.Value, bool) {
// false for any other call, calc included: proven.OfCalc proves a calc from its operands,
// which only the caller holds.
func ProveNumber(name, token string, args []string) (proven.Facts, bool) {
b := builtins[name]
if b.proveNumber == nil {
return proven.Value{}, false
return proven.Facts{}, false
}
return b.proveNumber(token, b.prints, args), true
}
+1 -1
View File
@@ -29,7 +29,7 @@ func TestNoRefOperandsMatchesTheOperandGrammar(t *testing.T) {
continue
}
if takesRef := slices.ContainsFunc(b.operands([]string{"/x"}), grammar.IsRef); b.noRefOperands == takesRef {
t.Errorf("%s: noRefOperands = %v, but its operands func reads a reference: %v", name, b.noRefOperands, takesRef)
t.Errorf("%s: noRefOperands = %v, yet a reference /x read as an operand: %v", name, b.noRefOperands, takesRef)
}
}
}
+4 -4
View File
@@ -35,7 +35,7 @@ var builtins = withTransforms(map[string]builtin{
"ulid": {arity: 0, prep: sample(ulid)},
"nanoid": {arity: 1, checkArgs: posIntArg, prep: chars(nanoidAlphabet)},
"hex": {arity: 1, checkArgs: posIntArg, prep: chars(hexDigits)},
"digits": {arity: 1, checkArgs: posIntArg, prep: chars("0123456789"), prints: datatype.String, proveNumber: func(token string, prints datatype.DataType, a []string) proven.Value {
"digits": {arity: 1, checkArgs: posIntArg, prep: chars("0123456789"), prints: datatype.String, proveNumber: func(token string, prints datatype.DataType, a []string) proven.Facts {
return proven.Printing(token, prints, proven.Bounded(0, math.Pow(10, float64(atoi(a[0])))-1, true))
}},
"upper": {arity: 1, checkArgs: posIntArg, prep: chars("ABCDEFGHIJKLMNOPQRSTUVWXYZ")},
@@ -49,7 +49,7 @@ var builtins = withTransforms(map[string]builtin{
"int": {arity: 2, checkArgs: intRangeArgs, prep: func(a []string) Call {
lo, span := atoi(a[0]), atoi(a[1])-atoi(a[0])+1
return func(s *drawstate.State, _ string, _ []string) string { return strconv.Itoa(lo + s.IntN(span)) }
}, prints: datatype.Integer, proveNumber: func(token string, prints datatype.DataType, a []string) proven.Value {
}, prints: datatype.Integer, proveNumber: func(token string, prints datatype.DataType, a []string) proven.Facts {
return proven.Printing(token, prints, proven.Bounded(float64(atoi(a[0])), float64(atoi(a[1])), true))
}},
"float": {arity: 3, checkArgs: floatArgs, prep: func(a []string) Call {
@@ -57,7 +57,7 @@ var builtins = withTransforms(map[string]builtin{
return func(s *drawstate.State, _ string, _ []string) string {
return formatFloat(lo+s.Float64()*(hi-lo), dp)
}
}, prints: datatype.Number, proveNumber: func(token string, _ datatype.DataType, a []string) proven.Value {
}, prints: datatype.Number, proveNumber: func(token string, _ datatype.DataType, a []string) proven.Facts {
return proven.PrintedNumber(token, proven.Bounded(atof(a[0]), atof(a[1]), false), atoi(a[2]))
}},
"iban": {arity: 1, checkArgs: ibanArg, prep: func(a []string) Call {
@@ -78,7 +78,7 @@ var builtins = withTransforms(map[string]builtin{
return func(s *drawstate.State, _ string, _ []string) string {
return strconv.FormatUint(s.Seq(key), 10)
}
}, prints: datatype.Integer, proveNumber: func(token string, prints datatype.DataType, _ []string) proven.Value {
}, prints: datatype.Integer, proveNumber: func(token string, prints datatype.DataType, _ []string) proven.Facts {
return proven.Printing(token, prints, proven.Bounded(1, math.MaxInt64, true))
}},
})
+1 -3
View File
@@ -72,9 +72,7 @@ func ibanArg(a []string) error {
return nil
}
// iban generates a structurally valid IBAN for cc: a numeric BBAN of the right
// length, then mod-97 check digits. Real bank/branch structure isn't modelled —
// the result passes length and checksum validation, which is what fake data needs.
// iban generates an IBAN for cc: a numeric BBAN of the right length, then mod-97 check digits.
func iban(r rng, cc string) string {
bban := make([]byte, ibanLen[cc]-4)
for i := range bban {
+1 -1
View File
@@ -48,7 +48,7 @@ func unwrapTransform(arg string) (leaf string, chain []func(string) string, err
}
}
// transformArg proves a transform's chain.
// transformArg checks that each call nested in the arg is a transform taking one arg.
func transformArg(a []string) error {
_, _, err := unwrapTransform(a[0])
return err