Give rows, field, walk, column, expr and of one meaning each: rowCount, readRows, gatherFields, addField, addTag, renderCount and the prove methods

This commit is contained in:
2026-09-25 18:53:42 +02:00
committed by Lillem4n
parent 4b087df57e
commit 65091233a8
8 changed files with 72 additions and 74 deletions
+2 -2
View File
@@ -124,8 +124,8 @@ type categoryFiles struct {
tsv map[string]bool
}
// rows reads the rows file a category names beside it.
func (c *categoryFiles) rows(name string) (string, error) {
// readRows reads the rows file a category names beside it.
func (c *categoryFiles) readRows(name string) (string, error) {
if _, present := c.tsv[name]; !present {
return "", fmt.Errorf("rows names %s, which is not beside it in %s", name, c.src.name(c.dir))
}
+2 -2
View File
@@ -166,7 +166,7 @@ func disagreement(a *template, da DataType, b *template, db DataType) error {
switch {
case da != DataTypeString && db != DataTypeString:
return bothTyped(a, da, b, db)
case typed.datatype == DataTypeString && (&valueProof{}).columnItem(bare).not[want] != "":
case typed.datatype == DataTypeString && (&valueProof{}).proveColumnItem(bare).not[want] != "":
return fmt.Errorf(`item %q is not %s, the datatype item %q takes from the column it reads; to read that column as text, %s`, bare.format, dataTypeNouns[want], typed.format, asText(typed))
case bare.fromString: // an object may carry a weight, which this spelling would drop
return fmt.Errorf(`item %q declares no datatype, and a column holds one; write it as {"format":%q,"datatype":%q}`, bare.format, bare.format, want)
@@ -184,7 +184,7 @@ func bothTyped(a *template, da DataType, b *template, db DataType) error {
switch {
case read.datatype != DataTypeString:
return fmt.Errorf("its items hold %s and %s; a column holds one datatype", da, db)
case (&valueProof{}).columnItem(read).not[other] == "":
case (&valueProof{}).proveColumnItem(read).not[other] == "":
return fmt.Errorf("its items hold %s and %s; a column holds one datatype, so %s", da, db, typedAs(read, other))
}
return fmt.Errorf("its items hold %s and %s; a column holds one datatype, so to read %q as text, %s", da, db, read.format, asText(read))
+5 -5
View File
@@ -67,7 +67,7 @@ func contained(n node) []namedNode {
return nil
}
var out []namedNode
for r := 0; r < n.t.rows(); r++ {
for r := 0; r < n.t.rowCount(); r++ {
if cell := n.t.cellTemplate(r, n.i); cell != nil {
out = append(out, namedNode{node: cell})
}
@@ -171,13 +171,13 @@ func pathLeaves(n node, tail []string) []node {
type reachMemo map[node]int
func (m reachMemo) of(n node) int {
func (m reachMemo) renderCount(n node) int {
if r, done := m[n]; done {
return r
}
r := 1
for _, e := range renderEdges(n) {
if c := m.of(e.to); c > r {
if c := m.renderCount(e.to); c > r {
r = c
}
}
@@ -192,8 +192,8 @@ func (m reachMemo) of(n node) int {
// path, so nested repeats cannot build what one repeat may not.
// docs/decisions.md#the-repeat-cap-bounds-renders-not-bytes
func repeatCheck(path string, n node, mem reachMemo) error {
if t, ok := n.(*template); ok && t.repeat > 1 && mem.of(n) > MaxRepeat {
return fmt.Errorf("%s: repeat %d multiplies to %d renders along one path, above the maximum %d", path, t.repeat, mem.of(n), MaxRepeat)
if t, ok := n.(*template); ok && t.repeat > 1 && mem.renderCount(n) > MaxRepeat {
return fmt.Errorf("%s: repeat %d multiplies to %d renders along one path, above the maximum %d", path, t.repeat, mem.renderCount(n), MaxRepeat)
}
return nil
}
+11 -11
View File
@@ -105,7 +105,7 @@ func (sc *structCompile) record(t reflect.Type, label string) (*structShape, err
sc.visiting[t] = true
defer delete(sc.visiting, t)
c := &structFields{structCompile: sc, t: t, label: label, tags: map[string]any{}, shape: &structShape{}}
if err := c.walk(t, nil); err != nil {
if err := c.gatherFields(t, nil); err != nil {
return nil, err
}
if len(c.tags) > 0 {
@@ -123,19 +123,19 @@ func (sc *structCompile) spend(label string) error {
return fmt.Errorf(`%s: the struct fields reach more than %d structs; leave a struct field unfilled with fake:"-"`, label, maxStructs)
}
// walk gathers the fields of struct type t, which sits at index within c.t.
func (c *structFields) walk(t reflect.Type, index []int) error {
// gatherFields gathers the fields of struct type t, which sits at index within c.t.
func (c *structFields) gatherFields(t reflect.Type, index []int) error {
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
sf.Index = append(index[:len(index):len(index)], i)
if err := c.field(sf); err != nil {
if err := c.addField(sf); err != nil {
return err
}
}
return nil
}
func (c *structFields) field(sf reflect.StructField) error {
func (c *structFields) addField(sf reflect.StructField) error {
tag, tagged := sf.Tag.Lookup("fake")
elem := structOf(sf.Type)
switch {
@@ -145,7 +145,7 @@ func (c *structFields) field(sf reflect.StructField) error {
}
return nil
case tagged:
return c.column(sf, tag)
return c.addTag(sf, tag)
case elem == nil || c.visiting[elem]:
return nil
case sf.Anonymous:
@@ -167,8 +167,8 @@ func structOf(t reflect.Type) reflect.Type {
return t
}
// column adds a tagged field's tag to the record, refusing one another field hides.
func (c *structFields) column(sf reflect.StructField, tag string) error {
// addTag adds a tagged field's tag to the record, refusing one another field hides.
func (c *structFields) addTag(sf reflect.StructField, tag string) error {
if visible, ok := c.t.FieldByName(sf.Name); !ok || !slices.Equal(visible.Index, sf.Index) {
return fmt.Errorf("%s.%s: hidden by another field named %s, so its fake tag cannot fill it; rename one", c.label, fieldPath(c.t, sf.Index), sf.Name)
}
@@ -196,7 +196,7 @@ func (c *structFields) embed(sf reflect.StructField, elem reflect.Type) error {
c.visiting[elem] = true
defer delete(c.visiting, elem)
tags, nested := len(c.tags), len(c.shape.nested)
if err := c.walk(elem, sf.Index); err != nil {
if err := c.gatherFields(elem, sf.Index); err != nil {
return err
}
if sf.Type.Kind() == reflect.Pointer && !sf.IsExported() && (len(c.tags) > tags || len(c.shape.nested) > nested) {
@@ -327,7 +327,7 @@ func (p *valueProof) checkField(label string, ft reflect.Type, column node) erro
elem := ft
if ft.Kind() == reflect.Pointer {
elem = ft.Elem()
} else if p.column(column).null {
} else if p.proveColumn(column).null {
return fmt.Errorf("%s: its tag can draw null, which %s cannot hold; make it *%s", label, ft, ft)
}
kind := columnKinds[elem.Kind()]
@@ -335,7 +335,7 @@ func (p *valueProof) checkField(label string, ft reflect.Type, column node) erro
return nil
}
for _, it := range items {
v := p.columnItem(it)
v := p.proveColumnItem(it)
if reason := v.not[kind.datatype]; reason != "" {
return fmt.Errorf("%s (%s): %s", label, ft, reason)
}
+16 -16
View File
@@ -58,7 +58,7 @@ type row struct{ t *table }
func (*row) isNode() {}
func (t *table) rows() int { return len(t.cells) / len(t.columns) }
func (t *table) rowCount() int { return len(t.cells) / len(t.columns) }
func (t *table) cell(row, col int) string { return t.cells[row*len(t.columns)+col] }
@@ -89,7 +89,7 @@ func compileTable(m map[string]any, category string, files *categoryFiles) (*tab
if err != nil {
return nil, err
}
data, err := files.rows(o.rows)
data, err := files.readRows(o.rows)
if err != nil {
return nil, err
}
@@ -184,7 +184,7 @@ func (t *table) parseRows(data string) error {
}
rest = more
}
if t.rows() < 2 {
if t.rowCount() < 2 {
return fmt.Errorf("has one row, which is a template; write it as one")
}
return nil
@@ -240,8 +240,8 @@ func (t *table) proveNamesInsideParent() error {
if t.key >= 0 || t.name < 0 {
return nil
}
inside := make(map[string]int, t.rows())
for r := 0; r < t.rows(); r++ {
inside := make(map[string]int, t.rowCount())
for r := 0; r < t.rowCount(); r++ {
k := t.cell(r, t.parent) + "\t" + t.cell(r, t.name)
if first, dup := inside[k]; dup {
return fmt.Errorf("%s line %d: name %q repeats line %d inside %s %q; a name selects one row inside its parent; drop one, or add a key column", t.file, r+2, t.cell(r, t.name), first+2, t.columns[t.parent], t.cell(r, t.parent))
@@ -256,8 +256,8 @@ func (t *table) indexKeys() error {
if t.key < 0 {
return nil
}
t.byKey = make(map[string]int, t.rows())
for r := 0; r < t.rows(); r++ {
t.byKey = make(map[string]int, t.rowCount())
for r := 0; r < t.rowCount(); r++ {
k := t.cell(r, t.key)
if k == "" {
return fmt.Errorf("%s line %d: the key is empty", t.file, r+2)
@@ -267,7 +267,7 @@ func (t *table) indexKeys() error {
}
t.byKey[k] = r
}
for r := 0; r < t.rows() && t.name >= 0; r++ {
for r := 0; r < t.rowCount() && t.name >= 0; r++ {
if n := t.cell(r, t.name); t.byKey[n] != r {
if other, isKey := t.byKey[n]; isKey {
return fmt.Errorf("%s line %d: name %q is the key of line %d, which a selector reads first, so the name could never select this row", t.file, r+2, n, other+2)
@@ -282,7 +282,7 @@ func (t *table) sumWeights() error {
if t.weight < 0 {
return nil
}
t.cum = make([]float64, t.rows())
t.cum = make([]float64, t.rowCount())
total := 0.0
for r := range t.cum {
w, err := strconv.ParseFloat(t.cell(r, t.weight), 64)
@@ -419,15 +419,15 @@ func (t *table) linkParent(path string, siblings map[string]node) error {
return fmt.Errorf("%q is named like a column of %q, its ancestor, so %s.%s could read either; rename one", t.category, q.category, q.category, t.category)
}
}
linked := make(map[string]bool, p.rows())
for r := 0; r < t.rows(); r++ {
linked := make(map[string]bool, p.rowCount())
for r := 0; r < t.rowCount(); r++ {
k := t.cell(r, t.parent)
if _, ok := p.byKey[k]; !ok {
return fmt.Errorf("%s line %d: %s %q is no key of %s", t.file, r+2, name, k, p.file)
}
linked[k] = true
}
for r := 0; r < p.rows(); r++ {
for r := 0; r < p.rowCount(); r++ {
if k := p.cell(r, p.key); !linked[k] {
return fmt.Errorf("%s links no row to %s %q; every %s row needs one, or drop line %d of %s", t.file, name, k, name, r+2, p.file)
}
@@ -443,15 +443,15 @@ func (t *table) linkParent(path string, siblings map[string]node) error {
func (t *table) indexed() *tableIndex {
t.once.Do(func() {
if t.name >= 0 {
t.index.byName = make(map[string][]int, t.rows())
for r := 0; r < t.rows(); r++ {
t.index.byName = make(map[string][]int, t.rowCount())
for r := 0; r < t.rowCount(); r++ {
n := t.cell(r, t.name)
t.index.byName[n] = append(t.index.byName[n], r)
}
}
if t.parent >= 0 {
t.index.children = map[string][]int{}
for r := 0; r < t.rows(); r++ {
for r := 0; r < t.rowCount(); r++ {
k := t.cell(r, t.parent)
t.index.children[k] = append(t.index.children[k], r)
}
@@ -476,7 +476,7 @@ func (t *table) indexed() *tableIndex {
// interface so that the walk that draws through it keeps its hold set off the heap.
func (t *table) draw(s *session) int {
if t.cum == nil {
return s.IntN(t.rows())
return s.IntN(t.rowCount())
}
return pickCum(s, t.cum)
}
+2 -2
View File
@@ -982,7 +982,7 @@ func TestEnteredRowsAgreeWithPinning(t *testing.T) {
}
var none pinSet
for _, entered := range tables {
for row := 0; row < entered.rows(); row++ {
for row := 0; row < entered.rowCount(); row++ {
whole := drawAt{drawn: entered}
whole.whole.add(entered, row)
s := none.entered(entered, row)
@@ -993,7 +993,7 @@ func TestEnteredRowsAgreeWithPinning(t *testing.T) {
t.Errorf("a render draws %s beside %s, which pinning it there refuses", cand.selectorSpelling(r), entered.selectorSpelling(row))
}
}
for cr := 0; cr < cand.rows(); cr++ {
for cr := 0; cr < cand.rowCount(); cr++ {
beside := s.clone()
refused := beside.pinRow(cand, cr) != nil
candAt := drawAt{pins: none.entered(cand, cr)}
+3 -5
View File
@@ -19,11 +19,9 @@ Self-sufficiency 5.6), every seat capped by Locality or Self-sufficiency.
This round, in order:
- Give `rows` and `field` one meaning each, per the decision "One name, one meaning":
`categoryFiles.rows` returns a TSV file name where `table.rows` counts rows, and
`formatOps.field` compiles a `{field}` token where `structFields.field` reads a Go
struct field. Rename every other shared name that names two things — `walk`,
`column`, `expr` and `of` included.
- Rename the shared names left that name two things, per the decision "One name, one
meaning": judge each of `check`, `draw`, `drawn`, `head`, `key`, `name`, `named`,
`names`, `null`, `number`, `record` and `variant`.
- Run the nine-seat panel again and file what it names here.
### Data
+31 -31
View File
@@ -37,23 +37,23 @@ func (p *valueProof) checkDatatype(path string, n node) error {
if d := readDatatype(t); d == t.datatype {
return fmt.Errorf(`%s: %s takes datatype %s from the column it reads; drop "datatype"`, path, t.format, d)
}
if reason := p.columnItem(t).not[t.datatype]; reason != "" {
if reason := p.proveColumnItem(t).not[t.datatype]; reason != "" {
return fmt.Errorf("%s: datatype %s: %s", path, t.datatype, reason)
}
return nil
}
// columnItem proves a column item: what it renders, or, when it is a column it reads, that column.
func (p *valueProof) columnItem(t *template) proven {
// proveColumnItem proves a column item: what it renders, or, when it is a column it reads, that column.
func (p *valueProof) proveColumnItem(t *template) proven {
if t.readsColumn == nil {
return p.of(t)
return p.prove(t)
}
return p.column(t.readsColumn.column)
return p.proveColumn(t.readsColumn.column)
}
// column proves a column over what its items draw, a null item marking it null rather than
// proveColumn proves a column over what its items draw, a null item marking it null rather than
// rendering "".
func (p *valueProof) column(n node) proven {
func (p *valueProof) proveColumn(n node) proven {
if v, done := p.columns[n]; done {
return v
}
@@ -63,7 +63,7 @@ func (p *valueProof) column(n node) proven {
items, nullable := columnItems(n)
var v proven
for i, it := range items {
if w := p.columnItem(it); i == 0 {
if w := p.proveColumnItem(it); i == 0 {
v = w
} else {
v = v.or(w)
@@ -74,7 +74,7 @@ func (p *valueProof) column(n node) proven {
return v
}
func (p *valueProof) of(n node) proven {
func (p *valueProof) prove(n node) proven {
if v, done := p.memo[n]; done {
return v
}
@@ -84,11 +84,11 @@ func (p *valueProof) of(n node) proven {
var v proven
switch n := n.(type) {
case *choice:
v = p.unite(n.items)
v = p.proveUnion(n.items)
case *template:
v = p.template(n)
v = p.proveTemplate(n)
case *column:
v = p.cells(n)
v = p.proveCells(n)
case *row:
v = unproven(fmt.Sprintf("%q renders a row of %s, which is composed text", n.t.format.format, n.t.category))
default:
@@ -98,13 +98,13 @@ func (p *valueProof) of(n node) proven {
return v
}
// cells proves a table column over every cell it may render.
func (p *valueProof) cells(c *column) proven {
// proveCells proves a table column over every cell it may render.
func (p *valueProof) proveCells(c *column) proven {
var v proven
for r := 0; r < c.t.rows(); r++ {
for r := 0; r < c.t.rowCount(); r++ {
var w proven
if cell := c.t.cellTemplate(r, c.i); cell != nil {
w = p.of(cell)
w = p.prove(cell)
} else {
w = literalValue(c.t.cell(r, c.i))
}
@@ -117,10 +117,10 @@ func (p *valueProof) cells(c *column) proven {
return v
}
func (p *valueProof) unite(nodes []node) proven {
v := p.of(nodes[0])
func (p *valueProof) proveUnion(nodes []node) proven {
v := p.prove(nodes[0])
for _, n := range nodes[1:] {
v = v.or(p.of(n))
v = v.or(p.prove(n))
}
return v
}
@@ -140,9 +140,9 @@ func (v proven) or(w proven) proven {
return v
}
// template proves a template that renders one value: fixed text, or a format that is
// proveTemplate proves a template that renders one value: fixed text, or a format that is
// one token alone.
func (p *valueProof) template(t *template) proven {
func (p *valueProof) proveTemplate(t *template) proven {
switch {
case t.repeat != 1:
return unproven(fmt.Sprintf("%q carries a repeat, which composes text rather than one value", t.format))
@@ -161,9 +161,9 @@ func (p *valueProof) template(t *template) proven {
for _, a := range o.arms {
leaves = append(leaves, pathLeaves(t.head(a.key), a.tail)...)
}
return p.unite(leaves)
return p.proveUnion(leaves)
case name == "calc":
return p.calc(t, body, args)
return p.proveCalc(t, body, args)
case builtins[name].number != nil:
return builtins[name].number(body, builtins[name].prints, args)
case isTransform:
@@ -172,12 +172,12 @@ func (p *valueProof) template(t *template) proven {
return printing(body, DataTypeString, proven{notOperand: fmt.Sprintf("{%s} prints text, not a number", body)})
}
func (p *valueProof) calc(t *template, body string, args []string) proven {
func (p *valueProof) proveCalc(t *template, body string, args []string) proven {
expr, err := parseCalc(args[0])
if err != nil {
panic(fmt.Sprintf("fejkdata: calc(%q) reached a proof unparsed: %v", args[0], err))
}
v, doubt := p.expr(expr, t.fields)
v, doubt := p.proveExpr(expr, t.fields)
if doubt == "" && !(magnitude(v) <= calcLimit) {
doubt = calcText(expr) + " is not proven within 1e300"
}
@@ -191,28 +191,28 @@ func (p *valueProof) calc(t *template, body string, args []string) proven {
// math.MaxFloat64 that rounding in the bounds cannot hide an overflow.
const calcLimit = 1e300
// expr bounds a calc expression from its operands, or says why it cannot.
func (p *valueProof) expr(n calcNode, fields map[string]node) (proven, string) {
// proveExpr bounds a calc expression from its operands, or says why it cannot.
func (p *valueProof) proveExpr(n calcNode, fields map[string]node) (proven, string) {
switch n := n.(type) {
case calcNum:
v := float64(n)
return bounded(v, v, v == math.Trunc(v)), ""
case calcVar:
v := p.of(fields[string(n)])
v := p.prove(fields[string(n)])
if v.notOperand != "" {
return proven{}, fmt.Sprintf("operand %q: %s", string(n), v.notOperand)
}
return proven{lo: v.lo, hi: v.hi, nonZero: v.nonZero, integral: v.integral}, ""
case calcNeg:
v, doubt := p.expr(n.x, fields)
v, doubt := p.proveExpr(n.x, fields)
v.lo, v.hi = -v.hi, -v.lo
return v, doubt
case calcBin:
l, doubt := p.expr(n.l, fields)
l, doubt := p.proveExpr(n.l, fields)
if doubt != "" {
return l, doubt
}
r, doubt := p.expr(n.r, fields)
r, doubt := p.proveExpr(n.r, fields)
if doubt != "" {
return r, doubt
}