Give a table's current row one owner, the pin set, and return a column's null from its read

This commit is contained in:
2026-09-27 23:48:31 +02:00
committed by Lillem4n
parent 52292d3669
commit 3b77ed6b06
6 changed files with 38 additions and 31 deletions
-3
View File
@@ -131,9 +131,6 @@ func renderRoot(s *session, t *template) {
sc.hold().pins.pin(t.table, r)
render(s, t.table.pinnedRow, sc)
}
case t.cellOf != nil:
sc.t, sc.row = t.cellOf, t.cellRow
render(s, t, sc)
case t.repeat > 1:
expand(s, t, sc)
default:
+21 -11
View File
@@ -29,11 +29,7 @@ type draw struct {
// linkRefs prove every step, so the walk cannot fail.
func readField(s *session, t *template, held *hold, sc renderScope, a arm) draw {
if s.trace != nil {
var table string
if sc.t != nil {
table = strings.Clone(sc.t.path)
}
s.trace.read(strings.Clone(sc.group), table, sc.row, a)
traceRead(s.trace, t, sc, a)
}
if !t.held[a.key] {
if len(a.tail) > 0 {
@@ -45,6 +41,7 @@ func readField(s *session, t *template, held *hold, sc renderScope, a arm) draw
if r, done := d.value[a.path]; done {
return r
}
sc.pins = &d.pins
r := renderLeaf(s, drawPath(t.head(a.key), a.tail, a.key, &d.pins, &pathDraws{s: s, held: d, a: &a}), sc)
if d.value == nil {
d.value = map[string]draw{}
@@ -59,6 +56,18 @@ type renderTrace struct {
repeatDepth int
}
func traceRead(trace *renderTrace, t *template, sc renderScope, a arm) {
var table string
var row int
switch {
case t.cellOf != nil:
table, row = t.cellOf.path, t.cellRow
case t.table != nil:
table, row = t.table.path, sc.rows().mustRow(t.table)
}
trace.read(strings.Clone(sc.group), strings.Clone(table), row, a)
}
// readHold is the hold a held read keeps its draw in: for a reference that reads a path,
// the render's hold for its group, so its draw spans the render; for a sibling, or a
// bare reference, held.
@@ -73,14 +82,15 @@ func readHold(held *hold, sc renderScope, a arm) *hold {
// reference alone whose read drew null.
func renderLeaf(s *session, n node, sc renderScope) draw {
n = resolveChoice(s, n)
if _, isNull := n.(*nullItem); isNull {
switch leaf := n.(type) {
case *nullItem:
return draw{null: true}
case *template:
if leaf.readsColumn != nil {
return readField(s, leaf, nil, sc.in(leaf), leaf.readsColumn.a)
}
}
r := draw{text: render(s, n, sc)}
if t, _ := n.(*template); t != nil && t.readsColumn != nil {
r.null = sc.in(t).hold().value[t.readsColumn.a.path].null
}
return r
return draw{text: render(s, n, sc)}
}
// resolveChoice resolves a choice to one variant, so a bound head is a concrete node the
+11 -5
View File
@@ -11,14 +11,13 @@ type holdSet struct {
}
// renderScope is where a render reads its reference paths: a hold set, in the draw group of the
// template rendering, and the row a table's format is rendering, which its columns read. It passes
// by value, and what is read from it reaches a map key, an interface or a func value only as a
// copy; else sc, and with it every render's hold set, moves to the heap.
// template rendering, and the pin set a table's columns read their row from: a whole read's own,
// else the hold's. It passes by value, and what is read from it reaches a map key, an interface or
// a func value only as a copy; else sc, and with it every render's hold set, moves to the heap.
type renderScope struct {
set *holdSet
group string
t *table
row int
pins *pinSet
}
func eagerHoldSet() holdSet {
@@ -52,6 +51,13 @@ func (sc renderScope) in(t *template) renderScope {
return sc
}
func (sc renderScope) rows() *pinSet {
if sc.pins != nil {
return sc.pins
}
return &sc.hold().pins
}
func (sc renderScope) hold() *hold {
if sc.group == "" {
return &sc.set.unnamed
-3
View File
@@ -264,9 +264,6 @@ func recordOf(n node) (*template, []Column, error) {
// over sc's hold; a table's columns read the row pinned there.
func renderRecord(s *session, t *template, columns []Column, sc renderScope) *Record {
sc = sc.in(t)
if t.table != nil {
sc.t, sc.row = t.table, sc.hold().pins.mustRow(t.table)
}
r := &Record{columns: append([]Column(nil), columns...)}
for i := range r.columns {
column := renderLeaf(s, t.fields[r.columns[i].Name], sc)
+6 -7
View File
@@ -61,19 +61,18 @@ func render(s *session, n node, sc renderScope) string {
case *nullItem:
return ""
case *table:
sc.t, sc.row = n, n.drawRow(s)
var own pinSet
own.add(n, n.drawRow(s))
sc.pins = &own
return expand(s, n.formatTemplate, sc)
case *tableRow:
sc.t, sc.row = n.t, sc.hold().pins.mustRow(n.t)
return expand(s, n.t.formatTemplate, sc)
case *tableColumn:
if sc.t != n.t {
sc.t, sc.row = n.t, sc.hold().pins.mustRow(n.t)
}
if cell := n.t.cellTemplate(sc.row, n.i); cell != nil {
row := sc.rows().mustRow(n.t)
if cell := n.t.cellTemplate(row, n.i); cell != nil {
return render(s, cell, sc)
}
return n.t.cell(sc.row, n.i)
return n.t.cell(row, n.i)
case *template:
sc = sc.in(n)
if n.repeat == 1 {
-2
View File
@@ -21,8 +21,6 @@ Self-sufficiency 5.6), every seat capped by Locality, and all nine naming
This round, in order:
- Give a table's current row one owner: `renderScope.t` and `row` hold it beside the
`pinSet`, and `renderLeaf` reads a column's null back from a hold `readField` wrote.
- Split `walkPath`'s four modes, so a caller does not select a behaviour by which of
`level`, `leaf`, `pins`, `drawn` and `draws` it leaves nil.
- Gather the family fence beside `drawWalk.check`: `checkFamilies`, `replayPairs`,