Move renderEnv's methods into env.go, a table's route and draw steps into table.go, and the compiled read into arm.go
This commit is contained in:
@@ -4,7 +4,9 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/larvit/fejkdata/internal/drawstate"
|
||||
"github.com/larvit/fejkdata/internal/grammar"
|
||||
"github.com/larvit/fejkdata/internal/invariant"
|
||||
"github.com/larvit/fejkdata/internal/rows"
|
||||
)
|
||||
|
||||
@@ -233,3 +235,129 @@ func (t *table) linkParent(siblings map[string]node) error {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// tableRoute is how a path passes one table: the row it reads, by selector or
|
||||
// drawn, what it goes on into, and whether that is a linked table.
|
||||
type tableRoute struct {
|
||||
sel string
|
||||
draw bool
|
||||
next node
|
||||
rest []string
|
||||
descends bool
|
||||
up bool
|
||||
}
|
||||
|
||||
// route is how tail passes t. descended means the previous route stepped into t
|
||||
// from a row of an ancestor table, so t reads a row even where tail is empty; a
|
||||
// table reached otherwise, with no selector and an empty tail, is left to a render's
|
||||
// own draw.
|
||||
func (t *table) route(tail []string, descended bool) (tableRoute, error) {
|
||||
sel, tail, err := t.selector(tail)
|
||||
if err != nil {
|
||||
return tableRoute{}, err
|
||||
}
|
||||
if len(tail) > 0 && tail[0] == ".." {
|
||||
if err := t.rows.ProveStepUp(tail[1:]); err != nil {
|
||||
return tableRoute{}, err
|
||||
}
|
||||
return tableRoute{sel: sel, draw: sel == "", next: t.rows.Parent().Owner(), rest: tail[2:], descends: true, up: true}, nil
|
||||
}
|
||||
column, child, err := t.step(tail)
|
||||
if err != nil {
|
||||
return tableRoute{}, err
|
||||
}
|
||||
// A selector further down pins this table by ancestry, so the walk draws only
|
||||
// where none follows; drawing first could draw a row the selector is not inside.
|
||||
r := tableRoute{sel: sel, draw: sel == "" && (descended || len(tail) > 0) && !grammar.HasSelector(tail)}
|
||||
switch {
|
||||
case len(tail) == 0 && sel == "" && !descended:
|
||||
r.next = t
|
||||
case len(tail) == 0:
|
||||
r.next = t.rowNode
|
||||
case child != nil:
|
||||
r.next, r.rest, r.descends = child, tail[1:], true
|
||||
default:
|
||||
r.next, r.rest = column, tail[1:]
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// routeSteps appends the steps r takes past t, the first at at, pinning in pins the row
|
||||
// it selects.
|
||||
func routeSteps(steps []pathStep, pins *pinSet, t *table, r tableRoute, at int) ([]pathStep, error) {
|
||||
if r.sel != "" {
|
||||
row, err := pins.Select(t.rows, r.sel)
|
||||
if err != nil {
|
||||
return steps, err
|
||||
}
|
||||
steps = append(steps, pathStep{kind: stepSelect, at: at, name: r.sel, row: row})
|
||||
at++
|
||||
}
|
||||
if r.draw {
|
||||
steps = append(steps, pathStep{kind: stepDraw, at: at})
|
||||
}
|
||||
switch next := r.next.(type) {
|
||||
case *table:
|
||||
switch {
|
||||
case r.up:
|
||||
steps = append(steps, pathStep{kind: stepParent, at: at})
|
||||
case next != t:
|
||||
steps = append(steps, pathStep{kind: stepChild, at: at, name: next.rows.Segment()})
|
||||
}
|
||||
case *tableRow:
|
||||
steps = append(steps, pathStep{kind: stepRow, at: at})
|
||||
case *tableColumn:
|
||||
steps = append(steps, pathStep{kind: stepColumn, at: at, name: next.name()})
|
||||
default:
|
||||
panic(invariant.Broken("%s: a route onto %T", t.rows.Segment(), r.next))
|
||||
}
|
||||
return steps, nil
|
||||
}
|
||||
|
||||
func (t *table) drawStep(s *drawstate.State, st pathStep, pins *pinSet) node {
|
||||
switch st.kind {
|
||||
case stepSelect:
|
||||
if err := pins.PinRow(t.rows, st.row); err != nil {
|
||||
panic(invariant.Broken("%s[%s]: %v", t.rows.Segment(), st.name, err))
|
||||
}
|
||||
return t
|
||||
case stepDraw:
|
||||
t.rows.DrawIn(s, pins)
|
||||
return t
|
||||
case stepRow:
|
||||
return t.rowNode
|
||||
case stepColumn:
|
||||
return t.formatTemplate.fields[st.name]
|
||||
case stepChild:
|
||||
return t.rows.Descendant(st.name).Owner()
|
||||
case stepParent:
|
||||
return t.rows.Parent().Owner()
|
||||
}
|
||||
panic(invariant.Broken("drawStep has no case for step kind %d", st.kind))
|
||||
}
|
||||
|
||||
func (t *table) selector(tail []string) (sel string, rest []string, err error) {
|
||||
if len(tail) == 0 || !grammar.IsSelector(tail[0]) {
|
||||
return "", tail, nil
|
||||
}
|
||||
sel, rest = grammar.SelectorOf(tail[0]), tail[1:]
|
||||
if len(rest) > 0 && grammar.IsSelector(rest[0]) {
|
||||
return "", nil, fmt.Errorf("%s[%s] is selected twice; one selector names its row", t.rows.Segment(), sel)
|
||||
}
|
||||
return sel, rest, nil
|
||||
}
|
||||
|
||||
// step is what a tail's first segment names in t: a column, or a table linked to it.
|
||||
func (t *table) step(tail []string) (column node, child *table, err error) {
|
||||
if len(tail) == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if column, ok := t.formatTemplate.fields[tail[0]]; ok {
|
||||
return column, nil, nil
|
||||
}
|
||||
d := t.rows.Descendant(tail[0])
|
||||
if d == nil {
|
||||
return nil, nil, fmt.Errorf("no column or linked table %q in %s", tail[0], t.rows.Segment())
|
||||
}
|
||||
return nil, d.Owner(), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user