Have the probe report the tables a read draws, and hold a row rendered whole in drawAt apart from the pins
This commit is contained in:
+3
-1
@@ -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
@@ -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,17 +233,28 @@ 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
|
||||||
@@ -249,12 +262,12 @@ func (w *drawWalk) walk(n node, at drawAt) {
|
|||||||
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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user