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:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}},
|
||||
})
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user