Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33
@@ -960,14 +960,15 @@ Where the project is heading; the sections before Audience document what ships t
|
|||||||
```
|
```
|
||||||
doc.go the package doc, and the vocabulary the package is written in
|
doc.go the package doc, and the vocabulary the package is written in
|
||||||
fejkdata.go Generator, New, options, List
|
fejkdata.go Generator, New, options, List
|
||||||
|
list.go the paths List advertises, every one a node reaches a direct descent at a time
|
||||||
shipped.go the embedded data set, and loading a shipped category on the first call reaching it
|
shipped.go the embedded data set, and loading a shipped category on the first call reaching it
|
||||||
shippedindex.go the index of shipped categories, generated from data/
|
shippedindex.go the index of shipped categories, generated from data/
|
||||||
node.go the node model and JSON -> node compilation
|
node.go the node model and JSON -> node compilation
|
||||||
table.go tables: their options, format and cells, the link to the parent beside them, and how a path passes and draws a table
|
table.go tables: their options, format and cells, the link to the parent beside them, and how a path passes and draws a table
|
||||||
name.go names: {x as n} bindings, the scopes they live in, and the reads they answer
|
name.go names: {x as n} bindings, the scopes they live in, the reads they answer, and what each resolves to at load: its target, its reads and the keys they address
|
||||||
namefence.go the load fences over names
|
namefence.go the load fences over names
|
||||||
pick.go a render's named picks: the frames of the name scopes rendering, the memo a pick keeps, and the reads kept under it
|
pick.go a render's named picks: the frames of the name scopes rendering, the memo a pick keeps, and the reads kept under it
|
||||||
env.go renderEnv: what a render reads names and rows through, and the frames a read opens and finds
|
env.go renderEnv: what a render reads names and rows through, the stack of frames it renders in, and the frames a read opens and finds
|
||||||
path.go the dotted-path walks, and proving a path reaches a node
|
path.go the dotted-path walks, and proving a path reaches a node
|
||||||
render.go Fake, the recursive renderer (choices, format strings, expansions) and the reads its tokens make
|
render.go Fake, the recursive renderer (choices, format strings, expansions) and the reads its tokens make
|
||||||
record.go records: Record, the JSON/CSV/SQL serializers, and their entry points
|
record.go records: Record, the JSON/CSV/SQL serializers, and their entry points
|
||||||
@@ -978,6 +979,7 @@ arm.go the compiled read of one {a|b} alternative or operand: its head,
|
|||||||
reference.go one reference's resolution: its sigil, its category, its tail
|
reference.go one reference's resolution: its sigil, its category, its tail
|
||||||
resolve.go resolving templates against the assembled tree in steps, each over every template before the next
|
resolve.go resolving templates against the assembled tree in steps, each over every template before the next
|
||||||
graph.go the node graph: tree walks, containment and render edges, and the cycle and repeat fences
|
graph.go the node graph: tree walks, containment and render edges, and the cycle and repeat fences
|
||||||
|
sorted.go sortedNames: a map's keys, sorted
|
||||||
calc.go the {calc()} operand checks: never a number, and a constant zero divisor
|
calc.go the {calc()} operand checks: never a number, and a constant zero divisor
|
||||||
datatype.go column datatypes: DataType, where datatype and null may sit, a column's datatype
|
datatype.go column datatypes: DataType, where datatype and null may sit, a column's datatype
|
||||||
valueproof.go the value proof: what a typed column, calc operand or struct field holds, checked at load
|
valueproof.go the value proof: what a typed column, calc operand or struct field holds, checked at load
|
||||||
|
|||||||
@@ -11,6 +11,21 @@ type readValue struct {
|
|||||||
null bool
|
null bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// frameStack is the frames of the name scopes rendering, innermost last. A render's env points
|
||||||
|
// at it, and a repeat iteration's shares it: holding the frames in a renderEnv would move every
|
||||||
|
// render's env to the heap.
|
||||||
|
type frameStack struct {
|
||||||
|
frames []*pickFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *frameStack) push(f *pickFrame) int {
|
||||||
|
mark := len(st.frames)
|
||||||
|
st.frames = append(st.frames, f)
|
||||||
|
return mark
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st *frameStack) pop(mark int) { st.frames = st.frames[:mark] }
|
||||||
|
|
||||||
// renderEnv is where a render reads: the frames of the name scopes rendering; and row, the row
|
// renderEnv is where a render reads: the frames of the name scopes rendering; and row, the row
|
||||||
// of the table rendering, which its columns read. It passes by value, and what is read from it
|
// of the table 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 env, and with it every
|
// reaches a map key, an interface or a func value only as a copy; else env, and with it every
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/larvit/fejkdata/internal/builtinfunc"
|
||||||
"github.com/larvit/fejkdata/internal/grammar"
|
"github.com/larvit/fejkdata/internal/grammar"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ type nameBinding struct {
|
|||||||
binder *template
|
binder *template
|
||||||
|
|
||||||
// Filled by `resolveTemplates`, once every check it runs passed:
|
// Filled by `resolveTemplates`, once every check it runs passed:
|
||||||
nameTarget
|
target nameTarget
|
||||||
// addressed is every key a read of the name lands on or passes, the spelling of the
|
// addressed is every key a read of the name lands on or passes, the spelling of the
|
||||||
// first read reaching it beside it; a pick keeps the draws at these keys, and only these.
|
// first read reaching it beside it; a pick keeps the draws at these keys, and only these.
|
||||||
addressed map[pickKey]string
|
addressed map[pickKey]string
|
||||||
@@ -45,6 +46,13 @@ type nameUse struct {
|
|||||||
operand, noRef, nested bool
|
operand, noRef, nested bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nameTarget is what a binding resolves to in the assembled tree: start, the node its head names, and
|
||||||
|
// the path it reads into that node.
|
||||||
|
type nameTarget struct {
|
||||||
|
start node
|
||||||
|
tail []string
|
||||||
|
}
|
||||||
|
|
||||||
// bindsField reports whether b binds a path into a field, so a read of it stays in the category.
|
// bindsField reports whether b binds a path into a field, so a read of it stays in the category.
|
||||||
func (b *nameBinding) bindsField() bool { return !grammar.IsRef(b.ref) }
|
func (b *nameBinding) bindsField() bool { return !grammar.IsRef(b.ref) }
|
||||||
|
|
||||||
@@ -257,3 +265,54 @@ func namedReads(t *template) []namedReadAt {
|
|||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nameTargets resolves what each binding of ts binds, from its binder's references.
|
||||||
|
func nameTargets(ts []templateSite) map[*nameBinding]nameTarget {
|
||||||
|
targets := map[*nameBinding]nameTarget{}
|
||||||
|
for _, s := range ts {
|
||||||
|
for _, tok := range s.t.tokens {
|
||||||
|
if tok.Kind == grammar.NameBind {
|
||||||
|
a := splitArm(tok.BoundRef, s.t.refs.byName)
|
||||||
|
targets[s.t.nameScope.bindings[tok.Bound]] = nameTarget{start: s.t.startOf(a.head), tail: a.tail}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targets
|
||||||
|
}
|
||||||
|
|
||||||
|
// addressedKeys is every key the reads of each name in ts land on or pass, from the name's own
|
||||||
|
// level, with the spelling of the first read reaching it.
|
||||||
|
func addressedKeys(ts []templateSite, targets map[*nameBinding]nameTarget) map[*nameBinding]map[pickKey]string {
|
||||||
|
keys := map[*nameBinding]map[pickKey]string{}
|
||||||
|
for _, s := range ts {
|
||||||
|
for _, r := range namedReads(s.t) {
|
||||||
|
b := r.a.named
|
||||||
|
if keys[b] == nil {
|
||||||
|
keys[b] = map[pickKey]string{}
|
||||||
|
}
|
||||||
|
for _, key := range r.a.levels[len(targets[b].tail):] {
|
||||||
|
if _, seen := keys[b][key]; !seen {
|
||||||
|
keys[b][key] = r.a.spelling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameUses(ts []templateSite) map[*nameBinding][]nameUse {
|
||||||
|
uses := map[*nameBinding][]nameUse{}
|
||||||
|
for _, s := range ts {
|
||||||
|
for _, r := range namedReads(s.t) {
|
||||||
|
b := r.a.named
|
||||||
|
uses[b] = append(uses[b], nameUse{
|
||||||
|
tail: grammar.JoinSegments(r.a.tail),
|
||||||
|
in: s.t,
|
||||||
|
operand: r.operand,
|
||||||
|
noRef: r.operand && builtinfunc.NoRefOperands(r.o.Fn),
|
||||||
|
nested: s.t.nameScope != b.scope,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uses
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,21 +69,6 @@ func newPickFrame(scope *nameScope) *pickFrame {
|
|||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// frameStack is the frames of the name scopes rendering, innermost last. A render's env points
|
|
||||||
// at it, and a repeat iteration's shares it: holding the frames in a renderEnv would move every
|
|
||||||
// render's env to the heap.
|
|
||||||
type frameStack struct {
|
|
||||||
frames []*pickFrame
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st *frameStack) push(f *pickFrame) int {
|
|
||||||
mark := len(st.frames)
|
|
||||||
st.frames = append(st.frames, f)
|
|
||||||
return mark
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st *frameStack) pop(mark int) { st.frames = st.frames[:mark] }
|
|
||||||
|
|
||||||
// scopeAround is the innermost name scope a render of n reads names in, short of the frames n
|
// scopeAround is the innermost name scope a render of n reads names in, short of the frames n
|
||||||
// renders itself, one per iteration of a repeat.
|
// renders itself, one per iteration of a repeat.
|
||||||
func scopeAround(n node) *nameScope {
|
func scopeAround(n node) *nameScope {
|
||||||
@@ -129,7 +114,7 @@ func readName(s *drawstate.State, env renderEnv, a arm) readValue {
|
|||||||
if r, done := p.memo.value[a.key()]; done {
|
if r, done := p.memo.value[a.key()]; done {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
leaf, pins := p.draw(s, a.named.start, a.steps, a.levels)
|
leaf, pins := p.draw(s, a.named.target.start, a.steps, a.levels)
|
||||||
if a.named.bindsField() {
|
if a.named.bindsField() {
|
||||||
return p.renderAt(s, leaf, pins, a.key(), env)
|
return p.renderAt(s, leaf, pins, a.key(), env)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,8 +266,8 @@ func recordColumns(t *template) []recordColumn {
|
|||||||
if tok.Kind != grammar.NameBind {
|
if tok.Kind != grammar.NameBind {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if b := t.nameScope.bindings[tok.Bound]; b.bindsField() && len(b.tail) == 0 && whole[b.start] == nil {
|
if b := t.nameScope.bindings[tok.Bound]; b.bindsField() && len(b.target.tail) == 0 && whole[b.target.start] == nil {
|
||||||
whole[b.start] = b
|
whole[b.target.start] = b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
names := sortedNames(t.fields)
|
names := sortedNames(t.fields)
|
||||||
|
|||||||
+1
-60
@@ -3,7 +3,6 @@ package fejkdata
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/larvit/fejkdata/internal/builtinfunc"
|
|
||||||
"github.com/larvit/fejkdata/internal/grammar"
|
"github.com/larvit/fejkdata/internal/grammar"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -45,13 +44,6 @@ func resolveInlineTemplates(nodes nodeSet, root map[string]node) error {
|
|||||||
return resolveTemplates(ts, root)
|
return resolveTemplates(ts, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// nameTarget is what a binding resolves to in the assembled tree: start, the node its head names, and
|
|
||||||
// the path it reads into that node.
|
|
||||||
type nameTarget struct {
|
|
||||||
start node
|
|
||||||
tail []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolvedNames is what resolveTemplates resolved about the names of a set of templates: each binding's
|
// resolvedNames is what resolveTemplates resolved about the names of a set of templates: each binding's
|
||||||
// target, the keys its reads address, and its reads.
|
// target, the keys its reads address, and its reads.
|
||||||
type resolvedNames struct {
|
type resolvedNames struct {
|
||||||
@@ -94,62 +86,11 @@ func resolveTemplates(ts []templateSite, root map[string]node) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for b, target := range targets {
|
for b, target := range targets {
|
||||||
b.nameTarget, b.addressed = target, names.addressed[b]
|
b.target, b.addressed = target, names.addressed[b]
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nameTargets resolves what each binding of ts binds, from its binder's references.
|
|
||||||
func nameTargets(ts []templateSite) map[*nameBinding]nameTarget {
|
|
||||||
targets := map[*nameBinding]nameTarget{}
|
|
||||||
for _, s := range ts {
|
|
||||||
for _, tok := range s.t.tokens {
|
|
||||||
if tok.Kind == grammar.NameBind {
|
|
||||||
a := splitArm(tok.BoundRef, s.t.refs.byName)
|
|
||||||
targets[s.t.nameScope.bindings[tok.Bound]] = nameTarget{start: s.t.startOf(a.head), tail: a.tail}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return targets
|
|
||||||
}
|
|
||||||
|
|
||||||
// addressedKeys is every key the reads of each name in ts land on or pass, from the name's own
|
|
||||||
// level, with the spelling of the first read reaching it.
|
|
||||||
func addressedKeys(ts []templateSite, targets map[*nameBinding]nameTarget) map[*nameBinding]map[pickKey]string {
|
|
||||||
keys := map[*nameBinding]map[pickKey]string{}
|
|
||||||
for _, s := range ts {
|
|
||||||
for _, r := range namedReads(s.t) {
|
|
||||||
b := r.a.named
|
|
||||||
if keys[b] == nil {
|
|
||||||
keys[b] = map[pickKey]string{}
|
|
||||||
}
|
|
||||||
for _, key := range r.a.levels[len(targets[b].tail):] {
|
|
||||||
if _, seen := keys[b][key]; !seen {
|
|
||||||
keys[b][key] = r.a.spelling
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
|
|
||||||
func nameUses(ts []templateSite) map[*nameBinding][]nameUse {
|
|
||||||
uses := map[*nameBinding][]nameUse{}
|
|
||||||
for _, s := range ts {
|
|
||||||
for _, r := range namedReads(s.t) {
|
|
||||||
b := r.a.named
|
|
||||||
uses[b] = append(uses[b], nameUse{
|
|
||||||
tail: grammar.JoinSegments(r.a.tail),
|
|
||||||
in: s.t,
|
|
||||||
operand: r.operand,
|
|
||||||
noRef: r.operand && builtinfunc.NoRefOperands(r.o.Fn),
|
|
||||||
nested: s.t.nameScope != b.scope,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uses
|
|
||||||
}
|
|
||||||
|
|
||||||
// columnRead is a record's column read by a format that only reads one reference or name,
|
// columnRead is a record's column read by a format that only reads one reference or name,
|
||||||
// which is the column: it takes the column's datatype and null. category and field name it;
|
// which is the column: it takes the column's datatype and null. category and field name it;
|
||||||
// category is "" for a column of the reading template's own record, which checkColumns reaches
|
// category is "" for a column of the reading template's own record, which checkColumns reaches
|
||||||
|
|||||||
Reference in New Issue
Block a user