Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
6 changed files with 64 additions and 58 deletions
Showing only changes of commit 4a016c119c - Show all commits
+3 -1
View File
@@ -412,7 +412,9 @@ another never meet, and each may select its own row of another table; the cells
row, and whatever they reach, do meet, and so does the format beside them. The rule the row, and whatever they reach, do meet, and so does the format beside them. The rule the
fence applies is that two reads meet unless they sit in rows that never render together: fence applies is that two reads meet unless they sit in rows that never render together:
rows falling under different rows of a table a path pinned, two rows of that table rows falling under different rows of a table a path pinned, two rows of that table
itself included. A choice's items get no such treatment yet: two items selecting itself included. A table read whole draws its row apart from every pin, so its rows
are alternatives only to each other, and a cell of one meets a read pinning a region
the row is not in. A choice's items get no such treatment yet: two items selecting
different rows are still refused. different rows are still refused.
## A table never reaches its own family, by any route ## A table never reaches its own family, by any route
+26 -13
View File
@@ -179,12 +179,14 @@ type drawWalk struct {
} }
// drawAt is where a walk stands: the draw group it draws in, how the render's root reached it, the // drawAt is where a walk stands: the draw group it draws in, how the render's root reached it, the
// table rows it entered, and the table a whole read draws a row of. // table rows it pinned, the table a whole read draws a row of, and the row of it whose cells the
// walk is in.
type drawAt struct { type drawAt struct {
group string group string
route drawRoute route drawRoute
alt pinSet alt pinSet
drawn *table // left out of the visit keys: only this table's own cells compare against it, which the own-family fence keeps true drawn *table // left out of the visit keys: only this table's own cells compare against it, which the own-family fence keeps true
whole tablePin
} }
// drawRoute is how a render reaches a draw: as its author spells it, and the root edge's label. // drawRoute is how a render reaches a draw: as its author spells it, and the root edge's label.
@@ -216,7 +218,7 @@ func newDrawWalk() *drawWalk {
// walk follows what rendering n renders. A repeat renders over draws of its own, so the walk stops // walk follows what rendering n renders. A repeat renders over draws of its own, so the walk stops
// there. // there.
func (w *drawWalk) walk(n node, at drawAt) { func (w *drawWalk) walk(n node, at drawAt) {
v := nodeVisit{n, at.group, at.alt.key()} v := nodeVisit{n, at.group, at.rowsKey()}
if w.seen[v] { if w.seen[v] {
return return
} }
@@ -231,30 +233,41 @@ func (w *drawWalk) walk(n node, at drawAt) {
at.drawn = t at.drawn = t
} }
for _, e := range renderEdges(n) { for _, e := range renderEdges(n) {
if cell, isCell := e.to.(*template); isCell && cell.cellOf != nil { cell, isCell := e.to.(*template)
if at.alt.clash(cell.cellOf, cell.cellRow) != nil { switch {
continue case !isCell || cell.cellOf == nil:
}
in := at
in.alt = at.alt.entered(cell.cellOf, cell.cellRow, cell.cellOf != at.drawn)
w.edge(n, e, in)
continue
}
w.edge(n, e, at) w.edge(n, e, at)
case cell.cellOf == at.drawn:
in := at
in.whole = tablePin{cell.cellOf, cell.cellRow}
w.edge(n, e, in)
case at.alt.clash(cell.cellOf, cell.cellRow) == nil:
in := at
in.alt = at.alt.entered(cell.cellOf, cell.cellRow)
w.edge(n, e, in)
} }
} }
}
// rowsKey spells the rows the walk stands in, pinned and whole, for a map.
func (at drawAt) rowsKey() string {
if at.whole.t == nil {
return at.alt.key()
}
return fmt.Sprintf("%s%p{%d}", at.alt.key(), at.whole.t, at.whole.row)
}
// edge records the reference an edge reads, then walks on with every row the read // edge records the reference an edge reads, then walks on with every row the read
// pins entered, so a selected row renders only its own cells. // pins entered, so a selected row renders only its own cells.
func (w *drawWalk) edge(from node, e renderEdge, at drawAt) { func (w *drawWalk) edge(from node, e renderEdge, at drawAt) {
if a, reads := refRead(from, e.label); reads { if a, reads := refRead(from, e.label); reads {
tr := tableReadOf(from.(*template).head(a.key), a, e.to) tr := tableReadOf(from.(*template).head(a.key), a, e.to)
if k := (readKey{at.group, a.path, at.alt.key()}); !w.read[k] { if k := (readKey{at.group, a.path, at.rowsKey()}); !w.read[k] {
w.read[k] = true w.read[k] = true
w.reads = append(w.reads, pathRead{at, a, tr}) w.reads = append(w.reads, pathRead{at, a, tr})
} }
if tr != nil { if tr != nil {
tr.pins.each(func(t *table, r int) { at.alt = at.alt.entered(t, r, true) }) tr.pins.each(func(t *table, r int) { at.alt = at.alt.entered(t, r) })
} }
} }
w.walk(e.to, at) w.walk(e.to, at)
+6 -15
View File
@@ -33,33 +33,21 @@ func tableReadOf(head node, a arm, leaf node) *tableRead {
return nil return nil
} }
tr := &tableRead{head: t, drawn: map[*table]bool{}} tr := &tableRead{head: t, drawn: map[*table]bool{}}
_, _ = walkPath(t, a.tail, pathWalk{mode: walkProbe, pins: &tr.pins}) _, _ = walkPath(t, a.tail, pathWalk{mode: walkProbe, pins: &tr.pins, drawn: tr.drawn})
written := a.name[:len(a.name)-len(joinSegments(a.tail))] written := a.name[:len(a.name)-len(joinSegments(a.tail))]
cur := t cur := t
tr.draws(cur)
for i, seg := range a.tail { for i, seg := range a.tail {
switch d := cur.descendant(seg); { switch d := cur.descendant(seg); {
case isSelector(seg): case isSelector(seg):
tr.sels = append(tr.sels, tableSel{cur, written + joinSegments(a.tail[:i+1])}) tr.sels = append(tr.sels, tableSel{cur, written + joinSegments(a.tail[:i+1])})
case d != nil: case d != nil:
cur = d cur = d
tr.draws(cur)
} }
} }
_, tr.whole = leaf.(*row) _, tr.whole = leaf.(*row)
return tr return tr
} }
// draws marks t and its ancestors drawn, up to the first the read pins.
func (r *tableRead) draws(t *table) {
for ; t != nil; t = t.parentT {
if _, pinned := r.pins.pinned(t); pinned {
return
}
r.drawn[t] = true
}
}
// joinSegments spells segments as a path: a selector attaches to the name before it. // joinSegments spells segments as a path: a selector attaches to the name before it.
func joinSegments(segs []string) string { func joinSegments(segs []string) string {
var b strings.Builder var b strings.Builder
@@ -228,10 +216,13 @@ func checkOwnFamily(t *template) error {
return nil return nil
} }
// alternatives reports whether two reads sit in different rows of one table. Not clash: a row drawn // alternatives reports whether two reads sit in different rows of one table: rows the walks pinned,
// whole is held without its ancestors, since the render draws it over the whole table. // or rows of one whole draw.
// docs/decisions.md#the-rows-of-a-table-are-alternatives // docs/decisions.md#the-rows-of-a-table-are-alternatives
func alternatives(a, b drawAt) bool { func alternatives(a, b drawAt) bool {
if a.whole.t != nil && a.whole.t == b.whole.t && a.whole.row != b.whole.row {
return true
}
found := false found := false
a.alt.each(func(t *table, r int) { a.alt.each(func(t *table, r int) {
if br, in := b.alt.pinned(t); in && br != r { if br, in := b.alt.pinned(t); in && br != r {
+13 -6
View File
@@ -136,7 +136,8 @@ const (
// walkCover stops at a choice, handing it whole to leaf, and reads no row. // walkCover stops at a choice, handing it whole to leaf, and reads no row.
walkCover walkCover
// walkProbe proves as walkEvery does, walking one variant, so a path that // walkProbe proves as walkEvery does, walking one variant, so a path that
// resolves resolves whichever variants and rows are drawn. // resolves resolves whichever variants and rows are drawn, and marks in drawn
// the tables a draw would pin.
walkProbe walkProbe
// walkDraw draws the rows and variants a proved path reads; drawPath is its // walkDraw draws the rows and variants a proved path reads; drawPath is its
// one entry. // one entry.
@@ -150,6 +151,7 @@ type pathWalk struct {
level func(t *template, rest []string) error level func(t *template, rest []string) error
leaf func(n node) error leaf func(n node) error
pins *pinSet pins *pinSet
drawn map[*table]bool
draws *pathDraws draws *pathDraws
} }
@@ -299,14 +301,19 @@ func (t *table) step(tail []string) (column node, child *table, err error) {
return nil, child, nil return nil, child, nil
} }
// readRow pins the row a path reads of t: the one its selector names, or, where the // readRow pins the row a path reads of t: the one its selector names, or one drawn
// walk draws, one drawn where the path reads into the table. // where the path reads into the table.
func readRow(w pathWalk, t *table, sel string, draw bool) error { func readRow(w pathWalk, t *table, sel string, draw bool) error {
if sel != "" { switch {
case sel != "":
return w.pins.selectRow(t, sel) return w.pins.selectRow(t, sel)
} case !draw:
if draw && w.mode == walkDraw { case w.mode == walkDraw:
t.drawIn(w.draws.s, w.pins) t.drawIn(w.draws.s, w.pins)
case w.drawn != nil:
for stop := w.pins.nearestPinned(t); t != stop; t = t.parentT {
w.drawn[t] = true
}
} }
return nil return nil
} }
+17 -18
View File
@@ -12,8 +12,7 @@ type tablePin struct {
row int row int
} }
// pinSet is the table rows fixed so far. A fence walk's set also holds a row rendered whole alone, // pinSet is the table rows fixed so far.
// which pin never does.
type pinSet struct { type pinSet struct {
inline [8]tablePin // sized so a render over a country's five-deep geo tree stays off the heap inline [8]tablePin // sized so a render over a country's five-deep geo tree stays off the heap
n int n int
@@ -39,7 +38,6 @@ func (p *pinSet) mustRow(t *table) int {
return r return r
} }
// add pins row r of t alone.
func (p *pinSet) add(t *table, r int) { func (p *pinSet) add(t *table, r int) {
if p.n < len(p.inline) { if p.n < len(p.inline) {
p.inline[p.n] = tablePin{t, r} p.inline[p.n] = tablePin{t, r}
@@ -54,18 +52,25 @@ func (p *pinSet) add(t *table, r int) {
// pin pins row r of t, and the rows of t's ancestors it links to. // pin pins row r of t, and the rows of t's ancestors it links to.
func (p *pinSet) pin(t *table, r int) { func (p *pinSet) pin(t *table, r int) {
for { for stop := p.nearestPinned(t); t != stop; t = t.parentT {
if _, done := p.pinned(t); done {
return
}
p.add(t, r) p.add(t, r)
if t.parentT == nil { if t.parentT != stop {
return r = t.parentRow(r)
} }
t, r = t.parentT, t.parentRow(r)
} }
} }
// nearestPinned is the first of t and its ancestors p pins, where pinning a row of t stops; nil
// where none is.
func (p *pinSet) nearestPinned(t *table) *table {
for ; t != nil; t = t.parentT {
if _, ok := p.pinned(t); ok {
return t
}
}
return nil
}
// each calls fn for every pinned row, in pin order, the spilled ones by path. // each calls fn for every pinned row, in pin order, the spilled ones by path.
func (p *pinSet) each(fn func(t *table, r int)) { func (p *pinSet) each(fn func(t *table, r int)) {
for _, q := range p.inline[:p.n] { for _, q := range p.inline[:p.n] {
@@ -141,16 +146,10 @@ func (p pinSet) clone() pinSet {
return p return p
} }
// entered is p with row r of t: pinned where the render pins it, alone where the render draws it // entered is p with row r of t pinned. p is left as it was, since a fence walk branches.
// to render whole. p is left as it was, since a fence walk branches. func (p pinSet) entered(t *table, r int) pinSet {
func (p pinSet) entered(t *table, r int, pinsAncestors bool) pinSet {
p = p.clone() p = p.clone()
switch _, in := p.pinned(t); {
case pinsAncestors:
p.pin(t, r) p.pin(t, r)
case !in:
p.add(t, r)
}
return p return p
} }
-6
View File
@@ -19,12 +19,6 @@ Self-sufficiency 5.6), every seat capped by Locality or Self-sufficiency.
This round, in order: This round, in order:
- Have the check mode report the tables a read draws, so `tableRead.drawn` and
`entered`'s `pinsAncestors` flag stop restating `walkTable`'s draw condition and
`table.drawIn`'s ancestor rule: a change to how a render draws rows still leaves the
fence proving the old rule. Hold a row rendered whole in `drawAt` beside `drawn`, so
`pinSet` holds only what `pin` pins and `alternatives` needs no exception. Settle a
cell of a municipality drawn whole beside a path pinning a region it is not in.
- Register a transform once: `transforms` restates the `lowercase`, `uppercase` and - Register a transform once: `transforms` restates the `lowercase`, `uppercase` and
`ascii` entries in `builtins`, and `valueProof.template` classifies by the first while `ascii` entries in `builtins`, and `valueProof.template` classifies by the first while
render calls the second. Derive the numeric builtins `valueProof.template` lists in render calls the second. Derive the numeric builtins `valueProof.template` lists in