Add the table node, row selection and linked tables, and ship the misc registers as tables #19

Merged
lilleman merged 22 commits from table-node into main 2026-09-17 23:35:27 +02:00
3 changed files with 34 additions and 15 deletions
Showing only changes of commit c314f9cb57 - Show all commits
+4 -3
View File
@@ -965,9 +965,10 @@ renamed or retyped line is a major.
- **The rows of a table are alternatives.** Only one row renders, so a cell in one - **The rows of a table are alternatives.** Only one row renders, so a cell in one
row and a cell in another never meet, and each may select its own row of another row and a cell in another never meet, and each may select its own row of another
table; the cells of one row, and whatever they reach, do meet, and so does the table; the cells of one row, and whatever they reach, do meet, and so does the
format beside them. The family fence replays the reads of each row apart, format beside them. The rule the fence applies is that two reads meet unless
together with the reads outside any row. A choice's items get no such treatment they sit in two rows of one table, or in a row outside a selected ancestor's. A
yet: two items selecting different rows are still refused. choice's items get no such treatment yet: two items selecting different rows
are still refused.
- **A path is walked once without drawing before it is walked for real.** A path - **A path is walked once without drawing before it is walked for real.** A path
that fails below its first level then moves no seeded stream, at the cost of one that fails below its first level then moves no seeded stream, at the cost of one
draw-free walk per call, which allocates nothing. draw-free walk per call, which allocates nothing.
+20 -12
View File
@@ -363,8 +363,7 @@ func (w *drawWalk) walk(n node, at drawAt) {
} }
for _, e := range renderEdges(n) { for _, e := range renderEdges(n) {
if cell, isCell := e.to.(*template); isCell && cell.cellOf != nil { if cell, isCell := e.to.(*template); isCell && cell.cellOf != nil {
// A row already entered renders only its own cell of this column. if at.alt.excludes(cell) {
if r, in := at.alt.rowOf(cell.cellOf); in && r != cell.cellRow {
continue continue
} }
w.edge(n, e, drawAt{at.group, at.route, at.alt.enter(cell.cellOf, cell.cellRow)}) w.edge(n, e, drawAt{at.group, at.route, at.alt.enter(cell.cellOf, cell.cellRow)})
@@ -374,22 +373,31 @@ func (w *drawWalk) walk(n node, at drawAt) {
} }
} }
// excludes reports whether a cell's row cannot render with the rows entered: another
// row of its table, or a row outside an entered ancestor's.
func (s rowSet) excludes(cell *template) bool {
for _, p := range s {
if p.t == cell.cellOf {
return p.row != cell.cellRow
}
if cell.cellOf.descends(p.t) && !cell.cellOf.under(cell.cellRow, p.t, p.row) {
return true
}
}
return false
}
// 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.
func (w *drawWalk) edge(from node, e renderEdge, at drawAt) { func (w *drawWalk) edge(from node, e renderEdge, at drawAt) {
var tr *tableRead
if a, reads := refRead(from, e.label); reads { if a, reads := refRead(from, e.label); reads {
tr = tableReadOf(from.(*template).fields[a.key], a, e.to) tr := tableReadOf(from.(*template).fields[a.key], a, e.to)
if k := (drawKey{at.group, a.path, at.alt.key()}); !w.read[k] { if k := (drawKey{at.group, a.path, at.alt.key()}); !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 {
// A read that pins the column's table renders that row's cell alone. tr.pins.each(func(t *table, r int) { at.alt = at.alt.enter(t, r) })
if c, isColumn := e.to.(*column); isColumn && tr != nil {
if r, pinned := tr.pins.pinned(c.t); pinned {
if cell := c.t.cellNode(r, c.i); cell != nil {
w.walk(cell, drawAt{at.group, at.route, at.alt.enter(c.t, r)})
}
return
} }
} }
w.walk(e.to, at) w.walk(e.to, at)
+10
View File
@@ -465,6 +465,16 @@ func (t *table) descendant(name string) *table {
// parentRow is the row of t's parent that row r links to. // parentRow is the row of t's parent that row r links to.
func (t *table) parentRow(r int) int { return t.parentT.byKey[t.cell(r, t.parent)] } func (t *table) parentRow(r int) int { return t.parentT.byKey[t.cell(r, t.parent)] }
// descends reports whether a is an ancestor of t.
func (t *table) descends(a *table) bool {
for p := t.parentT; p != nil; p = p.parentT {
if p == a {
return true
}
}
return false
}
// under reports whether row r of t sits inside row pr of ancestor a. // under reports whether row r of t sits inside row pr of ancestor a.
func (t *table) under(r int, a *table, pr int) bool { func (t *table) under(r int, a *table, pr int) bool {
for c, row := t, r; c.parentT != nil; c, row = c.parentT, c.parentRow(row) { for c, row := t, r; c.parentT != nil; c, row = c.parentT, c.parentRow(row) {