Keep a template's table in one field, tableSite
This commit is contained in:
+1
-4
@@ -81,10 +81,7 @@ func (f *drawFence) checkDraws(path string, n node) error {
|
||||
// it renders, whichever draws the reaching template holds.
|
||||
// docs/decisions.md#a-table-never-reaches-its-own-family-by-any-route
|
||||
func checkOwnFamily(t *template) error {
|
||||
own := t.table
|
||||
if own == nil {
|
||||
own = t.cell.table
|
||||
}
|
||||
own := t.site.table
|
||||
if own == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -65,12 +65,12 @@ type renderTrace func(group, table string, row int, a arm)
|
||||
|
||||
func traceRead(trace renderTrace, t *template, sc renderScope, a arm) {
|
||||
var table string
|
||||
var row int
|
||||
switch {
|
||||
case t.cell.table != nil:
|
||||
table, row = t.cell.table.path, t.cell.row
|
||||
case t.table != nil:
|
||||
table, row = t.table.path, sc.rowOf(t.table)
|
||||
row := t.site.row
|
||||
if t.site.table != nil {
|
||||
table = t.site.table.path
|
||||
}
|
||||
if row == formatRow {
|
||||
row = sc.rowOf(t.site.table)
|
||||
}
|
||||
trace(strings.Clone(sc.group), strings.Clone(table), row, a)
|
||||
}
|
||||
|
||||
@@ -54,20 +54,22 @@ type template struct {
|
||||
drawGroup string // the draw group it draws in, as written; "" keeps its caller's
|
||||
fromString bool // written as a JSON string rather than an object
|
||||
isRecord bool // compiled at the top without a repeat, so its fields are record columns
|
||||
table *table // the table whose format this is, whose columns are the fields
|
||||
cell cellSite
|
||||
site tableSite
|
||||
|
||||
// Filled by `linkTemplate`, from the assembled tree:
|
||||
link templateLink
|
||||
compiled formatOps
|
||||
}
|
||||
|
||||
// cellSite is the table cell a template is compiled from; table is nil for any other template.
|
||||
type cellSite struct {
|
||||
// tableSite is the table a template belongs to, as its format or one of its cells; table is nil
|
||||
// for any other template.
|
||||
type tableSite struct {
|
||||
table *table
|
||||
row int
|
||||
row int // the cell's row, or formatRow for the format, whose columns are the fields
|
||||
}
|
||||
|
||||
const formatRow = -1
|
||||
|
||||
// templateLink is what a template resolves to in the assembled tree.
|
||||
type templateLink struct {
|
||||
refs map[string]refBinding // each reference the format reads -> what it resolves to
|
||||
@@ -172,7 +174,7 @@ func compileAt(v any, pos position) (node, error) {
|
||||
func compileItem(v any, pos position) (node, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
t, err := compileString(v, cellSite{})
|
||||
t, err := compileString(v, tableSite{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -203,12 +205,12 @@ func jsonKind(v any) string {
|
||||
return fmt.Sprintf("%T", v)
|
||||
}
|
||||
|
||||
func compileString(s string, cell cellSite) (*template, error) {
|
||||
func compileString(s string, site tableSite) (*template, error) {
|
||||
toks, err := parseChecked(s, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &template{format: s, tokens: toks, repeat: 1, fromString: true, cell: cell}, nil
|
||||
return &template{format: s, tokens: toks, repeat: 1, fromString: true, site: site}, nil
|
||||
}
|
||||
|
||||
// fixedText is one render's output when the format holds no token; repeat is the caller's.
|
||||
|
||||
+3
-3
@@ -114,9 +114,9 @@ func (s *readSurvey) walk(n node, at surveyAt) {
|
||||
}
|
||||
for _, e := range renderEdges(n) {
|
||||
to, isTemplate := e.to.(*template)
|
||||
cell := cellSite{}
|
||||
if isTemplate {
|
||||
cell = to.cell
|
||||
cell := tableSite{}
|
||||
if isTemplate && to.site.row != formatRow {
|
||||
cell = to.site
|
||||
}
|
||||
switch {
|
||||
case cell.table == nil:
|
||||
|
||||
+8
-7
@@ -80,13 +80,14 @@ func renderRoot(s *session, t *template, trace renderTrace) {
|
||||
set := holdSet{trace: trace}
|
||||
sc := renderScope{set: &set}
|
||||
switch {
|
||||
case t.table != nil:
|
||||
render(s, t.table, sc)
|
||||
for r := 0; r < t.table.rowCount(); r++ {
|
||||
case t.site.row == formatRow:
|
||||
tbl := t.site.table
|
||||
render(s, tbl, sc)
|
||||
for r := 0; r < tbl.rowCount(); r++ {
|
||||
set := holdSet{trace: trace}
|
||||
sc := renderScope{set: &set}
|
||||
sc.groupHold().pins.pin(t.table, r)
|
||||
render(s, t.table.pinnedRow, sc.at(t.table.pinnedRow, &sc.groupHold().pins))
|
||||
sc.groupHold().pins.pin(tbl, r)
|
||||
render(s, tbl.pinnedRow, sc.at(tbl.pinnedRow, &sc.groupHold().pins))
|
||||
}
|
||||
case t.repeat > 1:
|
||||
expand(s, t, sc)
|
||||
@@ -98,8 +99,8 @@ func renderRoot(s *session, t *template, trace renderTrace) {
|
||||
func renderRecordRoot(s *session, t *template, columns []Column, trace renderTrace) {
|
||||
set := holdSet{trace: trace}
|
||||
sc := renderScope{set: &set}
|
||||
if t.table != nil {
|
||||
t.table.drawIn(s, &sc.groupHold().pins)
|
||||
if t.site.row == formatRow {
|
||||
t.site.table.drawIn(s, &sc.groupHold().pins)
|
||||
}
|
||||
renderRecord(s, t, columns, sc)
|
||||
}
|
||||
|
||||
@@ -263,8 +263,8 @@ 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 = sc.at(t.table.pinnedRow, &sc.groupHold().pins)
|
||||
if t.site.row == formatRow {
|
||||
sc = sc.at(t.site.table.pinnedRow, &sc.groupHold().pins)
|
||||
}
|
||||
r := &Record{columns: append([]Column(nil), columns...)}
|
||||
for i := range r.columns {
|
||||
|
||||
+2
-2
@@ -81,8 +81,8 @@ func linkRefs(root map[string]node) error {
|
||||
// linkTemplate resolves t's references in category, "" for an inline template, and
|
||||
// compiles its format against them.
|
||||
func linkTemplate(folder []string, path, category string, t *template, root map[string]node) error {
|
||||
if t.cell.table != nil {
|
||||
path = fmt.Sprintf("%s, line %d", path, t.cell.row+2)
|
||||
if t.site.table != nil && t.site.row != formatRow {
|
||||
path = fmt.Sprintf("%s, line %d", path, t.site.row+2)
|
||||
}
|
||||
link, err := t.resolveLink(folder, path, category, root)
|
||||
if err != nil {
|
||||
|
||||
@@ -308,7 +308,7 @@ func (t *table) checkCells() error {
|
||||
if strings.IndexByte(cell, '{') < 0 && strings.IndexByte(cell, '}') < 0 {
|
||||
continue
|
||||
}
|
||||
n, err := compileString(cell, cellSite{t, row})
|
||||
n, err := compileString(cell, tableSite{t, row})
|
||||
if err != nil {
|
||||
return fmt.Errorf("line %d, %s: %w", row+2, t.header[col], err)
|
||||
}
|
||||
@@ -341,7 +341,7 @@ func (t *table) compileRowFormat(format string) error {
|
||||
if err := checkTokens(toks, t.fields); err != nil {
|
||||
return err
|
||||
}
|
||||
t.formatTemplate = &template{format: format, tokens: toks, fields: t.fields, repeat: 1, isRecord: true, table: t}
|
||||
t.formatTemplate = &template{format: format, tokens: toks, fields: t.fields, repeat: 1, isRecord: true, site: tableSite{t, formatRow}}
|
||||
t.pinnedRow = &tableRow{t}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -26,8 +26,6 @@ least modify.
|
||||
|
||||
This round, in order:
|
||||
|
||||
- Keep a template's table in one field: `template.table` and `template.cell.table` both
|
||||
answer which table it belongs to, and `checkOwnFamily` and `traceRead` branch on both.
|
||||
- Stop `readField` dereferencing a nil `held`: `renderLeaf` passes nil, safe only
|
||||
because a `readsColumn` arm is a reference path with a tail, which nothing there says.
|
||||
- Test that `disagreements` holds every key `disagreement` can build, and panic through
|
||||
|
||||
Reference in New Issue
Block a user