Rename ftoken to scanUnit and session to generatorState
This commit is contained in:
+9
-9
@@ -40,19 +40,19 @@ var builtins = withTransforms(map[string]builtin{
|
||||
"lower": {arity: 1, checkArgs: posIntArg, prep: chars("abcdefghijklmnopqrstuvwxyz")},
|
||||
"base64": {arity: 1, checkArgs: posIntArg, prep: func(a []string) callFn {
|
||||
n := atoi(a[0])
|
||||
return func(s *session, _ string, _ []string) string {
|
||||
return func(s *generatorState, _ string, _ []string) string {
|
||||
return base64.StdEncoding.EncodeToString(randBytes(s, n))
|
||||
}
|
||||
}},
|
||||
"int": {arity: 2, checkArgs: intRangeArgs, prep: func(a []string) callFn {
|
||||
lo, span := atoi(a[0]), atoi(a[1])-atoi(a[0])+1
|
||||
return func(s *session, _ string, _ []string) string { return strconv.Itoa(lo + s.IntN(span)) }
|
||||
return func(s *generatorState, _ string, _ []string) string { return strconv.Itoa(lo + s.IntN(span)) }
|
||||
}, prints: DataTypeInteger, proveNumber: func(token string, prints DataType, a []string) proven {
|
||||
return printing(token, prints, bounded(float64(atoi(a[0])), float64(atoi(a[1])), true))
|
||||
}},
|
||||
"float": {arity: 3, checkArgs: floatArgs, prep: func(a []string) callFn {
|
||||
lo, hi, dp := atof(a[0]), atof(a[1]), atoi(a[2])
|
||||
return func(s *session, _ string, _ []string) string {
|
||||
return func(s *generatorState, _ string, _ []string) string {
|
||||
return formatFloat(lo+s.Float64()*(hi-lo), dp)
|
||||
}
|
||||
}, prints: DataTypeNumber, proveNumber: func(token string, _ DataType, a []string) proven {
|
||||
@@ -60,12 +60,12 @@ var builtins = withTransforms(map[string]builtin{
|
||||
}},
|
||||
"iban": {arity: 1, checkArgs: ibanArg, prep: func(a []string) callFn {
|
||||
cc := a[0]
|
||||
return func(s *session, _ string, _ []string) string { return iban(s, cc) }
|
||||
return func(s *generatorState, _ 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},
|
||||
// seq is the one stateful builtin: a per-session 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
|
||||
// default one. Deterministic by construction, so seeded output stays stable.
|
||||
"seq": {arity: -1, checkArgs: seqArg, prep: func(a []string) callFn {
|
||||
@@ -73,7 +73,7 @@ var builtins = withTransforms(map[string]builtin{
|
||||
if len(a) == 1 {
|
||||
key = a[0]
|
||||
}
|
||||
return func(s *session, _ string, _ []string) string {
|
||||
return func(s *generatorState, _ string, _ []string) string {
|
||||
return strconv.FormatUint(s.next(key), 10)
|
||||
}
|
||||
}, prints: DataTypeInteger, proveNumber: func(token string, prints DataType, _ []string) proven {
|
||||
@@ -86,18 +86,18 @@ var builtins = withTransforms(map[string]builtin{
|
||||
// sample of n characters drawn from an alphabet.
|
||||
func derive(f func(emitted string) string) func([]string) callFn {
|
||||
return func([]string) callFn {
|
||||
return func(_ *session, emitted string, _ []string) string { return f(emitted) }
|
||||
return func(_ *generatorState, emitted string, _ []string) string { return f(emitted) }
|
||||
}
|
||||
}
|
||||
func sample(f func(rng) string) func([]string) callFn {
|
||||
return func([]string) callFn {
|
||||
return func(s *session, _ string, _ []string) string { return f(s) }
|
||||
return func(s *generatorState, _ string, _ []string) string { return f(s) }
|
||||
}
|
||||
}
|
||||
func chars(alphabet string) func([]string) callFn {
|
||||
return func(a []string) callFn {
|
||||
n := atoi(a[0])
|
||||
return func(s *session, _ string, _ []string) string { return randChars(s, n, alphabet) }
|
||||
return func(s *generatorState, _ string, _ []string) string { return randChars(s, n, alphabet) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -102,10 +102,10 @@ func TestBuiltinChecksums(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestBuiltinSeqPerSession pins seq's contract: a counter from 1, advancing on
|
||||
// TestBuiltinSeqPerGenerator pins seq's contract: a counter from 1, advancing on
|
||||
// each call, named counters independent, and the whole thing scoped to one
|
||||
// session so a fresh Generator restarts at 1.
|
||||
func TestBuiltinSeqPerSession(t *testing.T) {
|
||||
// generatorState so a fresh Generator restarts at 1.
|
||||
func TestBuiltinSeqPerGenerator(t *testing.T) {
|
||||
f := engine(1)
|
||||
for i := 1; i <= 5; i++ {
|
||||
if got := mustRender(t, f, `"{seq()}"`); got != strconv.Itoa(i) {
|
||||
@@ -122,9 +122,9 @@ func TestBuiltinSeqPerSession(t *testing.T) {
|
||||
if got := mustRender(t, engine(2), `{"format":"{seq()}","repeat":3,"separator":","}`); got != "1,2,3" {
|
||||
t.Fatalf("repeat seq = %q, want 1,2,3", got)
|
||||
}
|
||||
// ...and a fresh session restarts from 1.
|
||||
// ...and a fresh generator restarts from 1.
|
||||
if got := mustRender(t, engine(2), `"{seq()}"`); got != "1" {
|
||||
t.Fatalf("new session seq = %q, want 1", got)
|
||||
t.Fatalf("new generator seq = %q, want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ func calcPrep(args []string) callFn {
|
||||
}
|
||||
placed := indexVars(expr, at)
|
||||
dp := calcDecimals(args)
|
||||
return func(_ *session, _ string, operands []string) string {
|
||||
return func(_ *generatorState, _ string, operands []string) string {
|
||||
return formatFloat(placed.eval(operands), dp)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -34,20 +34,20 @@ type Generator struct {
|
||||
// table's row lookup, built under its sync.Once, so List, NewTemplate and
|
||||
// NewRecordTemplate read it without mu.
|
||||
mu sync.Mutex
|
||||
rand *session
|
||||
rand *generatorState
|
||||
root folder // the categories as the node a path walks from, owned here so a walk allocates none
|
||||
records map[node]recordShape
|
||||
structs map[reflect.Type]structResult
|
||||
}
|
||||
|
||||
// session is one generator's mutable render state: the seeded rng plus the {seq()}
|
||||
// generatorState is one generator's state across its renders: the seeded rng plus the {seq()}
|
||||
// counters.
|
||||
type session struct {
|
||||
type generatorState struct {
|
||||
*rand.Rand
|
||||
counters map[string]uint64
|
||||
}
|
||||
|
||||
func (s *session) next(key string) uint64 {
|
||||
func (s *generatorState) next(key string) uint64 {
|
||||
s.counters[key]++
|
||||
return s.counters[key]
|
||||
}
|
||||
@@ -228,7 +228,7 @@ func join(prefix, name string) string {
|
||||
// randomBytes seeds an unseeded generator.
|
||||
var randomBytes = crand.Read
|
||||
|
||||
func newRand(seed uint64, seeded bool) (*session, error) {
|
||||
func newRand(seed uint64, seeded bool) (*generatorState, error) {
|
||||
var r *rand.Rand
|
||||
if seeded {
|
||||
r = rand.New(rand.NewPCG(seed, seed^0x9e3779b97f4a7c15))
|
||||
@@ -239,7 +239,7 @@ func newRand(seed uint64, seeded bool) (*session, error) {
|
||||
}
|
||||
r = rand.New(rand.NewPCG(binary.LittleEndian.Uint64(b[:8]), binary.LittleEndian.Uint64(b[8:])))
|
||||
}
|
||||
return &session{Rand: r, counters: map[string]uint64{}}, nil
|
||||
return &generatorState{Rand: r, counters: map[string]uint64{}}, nil
|
||||
}
|
||||
|
||||
func internalError(format string, a ...any) string {
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ftoken is one unit of a scanned format string: a literal rune or the body of a
|
||||
// scanUnit is one unit of a scanned format string: a literal rune or the body of a
|
||||
// {…} token.
|
||||
type ftoken struct {
|
||||
type scanUnit struct {
|
||||
isToken bool // a {…} body, else a literal rune
|
||||
char rune
|
||||
body string
|
||||
@@ -16,10 +16,10 @@ type ftoken struct {
|
||||
// eachToken scans a format string once and calls fn for each unit, the single
|
||||
// source of truth for how braces are read: "{{" and "}}" are literal braces, a "{"
|
||||
// opens a token that must reach its "}", and a lone "}" is an error.
|
||||
func eachToken(format string, fn func(ftoken) error) error {
|
||||
func eachToken(format string, fn func(scanUnit) error) error {
|
||||
rs := []rune(format)
|
||||
for i := 0; i < len(rs); i++ {
|
||||
var t ftoken
|
||||
var t scanUnit
|
||||
switch c := rs[i]; c {
|
||||
case '{':
|
||||
if i+1 < len(rs) && rs[i+1] == '{' {
|
||||
@@ -85,7 +85,7 @@ func parseFormat(format string) ([]formatToken, error) {
|
||||
lit.Reset()
|
||||
}
|
||||
}
|
||||
err := eachToken(format, func(t ftoken) error {
|
||||
err := eachToken(format, func(t scanUnit) error {
|
||||
if !t.isToken {
|
||||
lit.WriteRune(t.char)
|
||||
return nil
|
||||
@@ -110,11 +110,11 @@ func parseFormat(format string) ([]formatToken, error) {
|
||||
}
|
||||
|
||||
// builtin is a format-string function invoked as {name(args)}. It receives the
|
||||
// session (its rng, and the {seq()} counters), the output emitted so far in the
|
||||
// generatorState (its rng, and the {seq()} counters), 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 (rng, emitted, args) so seeded output is reproducible; seq advances
|
||||
// per-session counter state, which is itself deterministic. arity is the exact arg
|
||||
// per-generator counter state, which is itself deterministic. arity is the exact arg
|
||||
// count, or -1 for variadic (then checkArgs does all the validation).
|
||||
type builtin struct {
|
||||
arity int
|
||||
@@ -366,7 +366,7 @@ func checkSegments(a arm) error {
|
||||
// callFn is a builtin prepared for one call site: its args already parsed. It reads the
|
||||
// output emitted so far in the current expansion (a derivation's payload) and the
|
||||
// values of the operands it named, which expand read for it.
|
||||
type callFn func(s *session, emitted string, operands []string) string
|
||||
type callFn func(s *generatorState, emitted string, operands []string) string
|
||||
|
||||
// op is one compiled unit of a format string: a literal run, a name read,
|
||||
// or a builtin already prepared with its args. compile builds these so render never
|
||||
|
||||
@@ -135,13 +135,13 @@ func datePrep(a []string) callFn {
|
||||
panic(internalError("builtin arg %q reached prep unvalidated: %v", a[1], err))
|
||||
}
|
||||
layout, start, span := layoutOf(a[2]), from.Unix(), int(to.Unix()-from.Unix())+86400
|
||||
return func(s *session, _ string, _ []string) string {
|
||||
return func(s *generatorState, _ string, _ []string) string {
|
||||
return time.Unix(start+int64(s.IntN(span)), 0).UTC().Format(layout)
|
||||
}
|
||||
}
|
||||
func timePrep(a []string) callFn {
|
||||
layout := layoutOf(a[0])
|
||||
return func(s *session, _ string, _ []string) string {
|
||||
return func(s *generatorState, _ string, _ []string) string {
|
||||
return time.Unix(int64(s.IntN(86400)), 0).UTC().Format(layout)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ func (w *pathProbe) readRow(t *table, tail []string, r tableRoute) error {
|
||||
// Where pathCheck walks every variant of a choice, it walks the one drawn; at a table it selects
|
||||
// as pathCheck does and draws the row the route asks for.
|
||||
type pathDraw struct {
|
||||
s *session
|
||||
s *generatorState
|
||||
pins *pinSet
|
||||
held *hold
|
||||
a *arm
|
||||
|
||||
+2
-2
@@ -76,7 +76,7 @@ func spellPins(p *pinSet) string {
|
||||
return "row " + strings.Join(rows, ", ")
|
||||
}
|
||||
|
||||
func renderRoot(s *session, t *template, trace renderTrace) {
|
||||
func renderRoot(s *generatorState, t *template, trace renderTrace) {
|
||||
set := holdSet{trace: trace}
|
||||
sc := renderScope{set: &set}
|
||||
switch {
|
||||
@@ -96,7 +96,7 @@ func renderRoot(s *session, t *template, trace renderTrace) {
|
||||
}
|
||||
}
|
||||
|
||||
func renderRecordRoot(s *session, t *template, columns []Column, trace renderTrace) {
|
||||
func renderRecordRoot(s *generatorState, t *template, columns []Column, trace renderTrace) {
|
||||
set := holdSet{trace: trace}
|
||||
sc := renderScope{set: &set}
|
||||
if t.site.row == formatRow {
|
||||
|
||||
@@ -152,7 +152,7 @@ func (f *Generator) FakeRecord(path string) (*Record, error) {
|
||||
|
||||
// tableRecord walks a path's tail from a table to the table whose row is the record,
|
||||
// pinning the rows it selects or draws.
|
||||
func tableRecord(s *session, t *table, tail []string, sc renderScope) (node, error) {
|
||||
func tableRecord(s *generatorState, t *table, tail []string, sc renderScope) (node, error) {
|
||||
n, err := descend(s, t, tail, sc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -261,7 +261,7 @@ func recordOf(n node) (*template, []Column, error) {
|
||||
|
||||
// renderRecord draws each column once, in the name order recordOf fixed, as one render
|
||||
// over sc's hold; a table's columns read the row pinned there.
|
||||
func renderRecord(s *session, t *template, columns []Column, sc renderScope) *Record {
|
||||
func renderRecord(s *generatorState, t *template, columns []Column, sc renderScope) *Record {
|
||||
sc = sc.in(t)
|
||||
if t.site.row == formatRow {
|
||||
sc = sc.at(t.site.table.rowNode, &sc.groupHold().pins)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// rng is the randomness a builtin sample draws from; *rand.Rand satisfies it. The
|
||||
// render path takes the concrete *session instead, which keeps the hold set of the walk
|
||||
// render path takes the concrete *generatorState instead, which keeps the hold set of the walk
|
||||
// drawing through it off the heap.
|
||||
type rng interface {
|
||||
IntN(n int) int
|
||||
@@ -38,7 +38,7 @@ func (f *Generator) Fake(path string) (string, error) {
|
||||
|
||||
// descend walks a caller's path to the node it names, pinning in sc the rows it
|
||||
// selects or draws.
|
||||
func descend(s *session, root node, segments []string, sc renderScope) (node, error) {
|
||||
func descend(s *generatorState, root node, segments []string, sc renderScope) (node, error) {
|
||||
// docs/decisions.md#a-path-is-walked-once-without-drawing-before-it-is-walked-for-real
|
||||
if _, err := (&pathProbe{}).walk(root, segments); err != nil {
|
||||
return nil, err
|
||||
@@ -47,7 +47,7 @@ func descend(s *session, root node, segments []string, sc renderScope) (node, er
|
||||
}
|
||||
|
||||
// renderOnce renders n as one render, over a hold set of its own.
|
||||
func renderOnce(s *session, n node) string {
|
||||
func renderOnce(s *generatorState, n node) string {
|
||||
var set holdSet
|
||||
return render(s, n, renderScope{set: &set})
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func renderOnce(s *session, n node) string {
|
||||
// front, so rendering a compiled tree cannot fail. sc holds the reference draws the
|
||||
// render shares; each repeat iteration renders over a hold set of its own.
|
||||
// A child this switch renders is one renderEdges must list too, or the fences miss it.
|
||||
func render(s *session, n node, sc renderScope) string {
|
||||
func render(s *generatorState, n node, sc renderScope) string {
|
||||
switch n := n.(type) {
|
||||
case *choice:
|
||||
return render(s, pick(s, n), sc)
|
||||
@@ -99,7 +99,7 @@ func render(s *session, n node, sc renderScope) string {
|
||||
// render's loop, its hold set would move to the heap.
|
||||
//
|
||||
//go:noinline
|
||||
func expandAnew(s *session, t *template) string {
|
||||
func expandAnew(s *generatorState, t *template) string {
|
||||
var set holdSet
|
||||
return expand(s, t, renderScope{set: &set})
|
||||
}
|
||||
@@ -107,7 +107,7 @@ func expandAnew(s *session, t *template) string {
|
||||
// pick selects one item. Uniform choices are O(1); weighted choices are an
|
||||
// O(log n) search over precomputed cumulative weights. compile guarantees a
|
||||
// non-empty choice and a finite positive total, so the index is always in range.
|
||||
func pick(s *session, c *choice) node {
|
||||
func pick(s *generatorState, c *choice) node {
|
||||
if c.cum == nil {
|
||||
return c.items[s.IntN(len(c.items))]
|
||||
}
|
||||
@@ -116,7 +116,7 @@ func pick(s *session, c *choice) node {
|
||||
|
||||
// expand renders a template's compiled ops. compile validated every token, so this
|
||||
// cannot fail.
|
||||
func expand(s *session, t *template, sc renderScope) string {
|
||||
func expand(s *generatorState, t *template, sc renderScope) string {
|
||||
var b strings.Builder
|
||||
b.Grow(t.compiled.grow)
|
||||
// One draw per held name, for this expansion only: a nested template and each
|
||||
@@ -157,7 +157,7 @@ func expand(s *session, t *template, sc renderScope) string {
|
||||
// reads — is drawn once and kept in held, so {place.postal-code} and {place.locality}
|
||||
// read one row, either read twice gives one value, and a shown operand is the operand
|
||||
// computed. Every other name is drawn afresh, so {word} {word} still draws twice.
|
||||
func readField(s *session, t *template, held *hold, sc renderScope, a arm) readValue {
|
||||
func readField(s *generatorState, t *template, held *hold, sc renderScope, a arm) readValue {
|
||||
if isRef(a.head) && len(a.tail) > 0 {
|
||||
return readReference(s, t, sc, a)
|
||||
}
|
||||
@@ -178,7 +178,7 @@ func readField(s *session, t *template, held *hold, sc renderScope, a arm) readV
|
||||
|
||||
// readReference reads a reference path, kept in the render's hold for its group, so its draw
|
||||
// spans the render.
|
||||
func readReference(s *session, t *template, sc renderScope, a arm) readValue {
|
||||
func readReference(s *generatorState, t *template, sc renderScope, a arm) readValue {
|
||||
if sc.set.trace != nil {
|
||||
traceRead(sc.set.trace, t, sc, a)
|
||||
}
|
||||
@@ -186,7 +186,7 @@ func readReference(s *session, t *template, sc renderScope, a arm) readValue {
|
||||
return readHeld(s, t, &group.hold, &group.pins, sc, a)
|
||||
}
|
||||
|
||||
func readHeld(s *session, t *template, held *hold, pins *pinSet, sc renderScope, a arm) readValue {
|
||||
func readHeld(s *generatorState, t *template, held *hold, pins *pinSet, sc renderScope, a arm) readValue {
|
||||
if r, done := held.value[a.path]; done {
|
||||
return r
|
||||
}
|
||||
@@ -215,7 +215,7 @@ func traceRead(trace renderTrace, t *template, sc renderScope, a arm) {
|
||||
|
||||
// renderLeaf draws and renders what a read lands on: null on a null item, or on a column of one
|
||||
// reference alone whose read drew null.
|
||||
func renderLeaf(s *session, n node, sc renderScope) readValue {
|
||||
func renderLeaf(s *generatorState, n node, sc renderScope) readValue {
|
||||
n = resolveChoice(s, n)
|
||||
switch leaf := n.(type) {
|
||||
case *nullItem:
|
||||
@@ -231,7 +231,7 @@ func renderLeaf(s *session, n node, sc renderScope) readValue {
|
||||
// resolveChoice resolves a choice to one variant, so a held head is a concrete node the
|
||||
// rest of the expansion shares. Nested choices unwrap too: a draw is one value, not
|
||||
// another set to pick from.
|
||||
func resolveChoice(s *session, n node) node {
|
||||
func resolveChoice(s *generatorState, n node) node {
|
||||
for c, ok := n.(*choice); ok; c, ok = n.(*choice) {
|
||||
n = pick(s, c)
|
||||
}
|
||||
|
||||
@@ -349,10 +349,10 @@ func (p *valueProof) checkField(label string, ft reflect.Type, column node) erro
|
||||
}
|
||||
|
||||
// fill draws the record into v's tagged fields, then each nested struct as a record of its own.
|
||||
func (s *structShape) fill(sess *session, v reflect.Value) {
|
||||
func (s *structShape) fill(state *generatorState, v reflect.Value) {
|
||||
if s.record != nil {
|
||||
var set holdSet
|
||||
for i, c := range renderRecord(sess, s.record, s.columns, renderScope{set: &set}).columns {
|
||||
for i, c := range renderRecord(state, s.record, s.columns, renderScope{set: &set}).columns {
|
||||
setColumn(fieldAt(v, s.fieldIndexes[i]), c)
|
||||
}
|
||||
}
|
||||
@@ -364,7 +364,7 @@ func (s *structShape) fill(sess *session, v reflect.Value) {
|
||||
}
|
||||
field = field.Elem()
|
||||
}
|
||||
n.shape.fill(sess, field)
|
||||
n.shape.fill(state, field)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -472,20 +472,20 @@ func (t *table) builtLookup() *rowLookup {
|
||||
}
|
||||
|
||||
// drawRow picks a row over the whole table.
|
||||
func (t *table) drawRow(s *session) int {
|
||||
func (t *table) drawRow(s *generatorState) int {
|
||||
if t.cum == nil {
|
||||
return s.IntN(t.rowCount())
|
||||
}
|
||||
return pickCum(s, t.cum)
|
||||
}
|
||||
|
||||
func pickCum(s *session, cum []float64) int {
|
||||
func pickCum(s *generatorState, cum []float64) int {
|
||||
x := s.Float64() * cum[len(cum)-1]
|
||||
return min(sort.Search(len(cum), func(i int) bool { return cum[i] > x }), len(cum)-1) // x can round up to the total
|
||||
}
|
||||
|
||||
// drawUnder picks a row among those linked to parent row pr.
|
||||
func (t *table) drawUnder(s *session, pr int) int {
|
||||
func (t *table) drawUnder(s *generatorState, pr int) int {
|
||||
lookup := t.builtLookup()
|
||||
k := t.parentT.cell(pr, t.parentT.keyIndex)
|
||||
rows := lookup.rowsByParent[k]
|
||||
@@ -498,7 +498,7 @@ func (t *table) drawUnder(s *session, pr int) int {
|
||||
// drawIn is the render's row of t: the one pinned in p, else one drawn inside the nearest
|
||||
// pinned ancestor — its parent drawn inside that first where the ancestor is further up — or
|
||||
// over the whole table, and pinned with its ancestors.
|
||||
func (t *table) drawIn(s *session, p *pinSet) int {
|
||||
func (t *table) drawIn(s *generatorState, p *pinSet) int {
|
||||
if r, ok := p.pinned(t); ok {
|
||||
return r
|
||||
}
|
||||
|
||||
@@ -31,9 +31,6 @@ on 2026-09-29 a third time (Navigation 7.0, Locality 5.6, Shape 6.3, Self-suffic
|
||||
|
||||
This round, in order:
|
||||
|
||||
- Rename `ftoken` to `scanUnit`, beside `formatToken`, and `session` to
|
||||
`generatorState`: three seats confused the token types, and both architects read
|
||||
`session` as per-render state.
|
||||
- State at `pinSet.pin` that its caller proved r sits inside the nearest pinned
|
||||
ancestor, which `pinRow` and `drawIn` do.
|
||||
- Delete the prose two or more seats found empty: `loadData`'s comment, which also names
|
||||
|
||||
+1
-1
@@ -70,7 +70,7 @@ func transformPrep(outer func(string) string) func([]string) callFn {
|
||||
if err != nil {
|
||||
panic(internalError("transform arg %q reached prep unvalidated: %v", a[0], err))
|
||||
}
|
||||
return func(_ *session, _ string, operands []string) string {
|
||||
return func(_ *generatorState, _ string, operands []string) string {
|
||||
v := operands[0]
|
||||
for i := len(chain) - 1; i >= 0; i-- {
|
||||
v = chain[i](v)
|
||||
|
||||
Reference in New Issue
Block a user