Make great documentation goal 1.2, and plan the README's reorganisation and the nested-template gaps #33

Open
lilleman wants to merge 966 commits from worktree-todo-relative-dates-exact-counts into main
8 changed files with 23 additions and 21 deletions
Showing only changes of commit 1419673b96 - Show all commits
+1 -1
View File
@@ -968,7 +968,7 @@ record.go records: Record, the JSON/CSV/SQL serializers, and their entry p
struct.go structs: FakeStruct, fake tags as one record's columns, and a field's Go type as its column's datatype struct.go structs: FakeStruct, fake tags as one record's columns, and a field's Go type as its column's datatype
inline.go inline templates: Template, NewTemplate, FakeTemplate, IsTemplate, and their compile and resolve inline.go inline templates: Template, NewTemplate, FakeTemplate, IsTemplate, and their compile and resolve
format.go a format's tokens checked against their fields, and compiled into ops format.go a format's tokens checked against their fields, and compiled into ops
arm.go the compiled read: an arm, the path from its head to its leaf, and the op holding it arm.go the compiled read of one {a|b} alternative or operand: its head, the path to its leaf, and the op holding it
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
+2 -2
View File
@@ -11,8 +11,8 @@ import (
"github.com/larvit/fejkdata/internal/invariant" "github.com/larvit/fejkdata/internal/invariant"
) )
// checkCalcFields leaves an operand no field holds for a name, which checkCalcNames checks once // checkCalcFields checks each calc operand a field holds; an operand no field holds is a name,
// names resolve. // which checkCalcNames checks once names resolve.
func checkCalcFields(args []string, fields map[string]node) error { func checkCalcFields(args []string, fields map[string]node) error {
return checkOperands(args[0], builtinfunc.ParsedCalc(args[0]), func(name string) []node { return checkOperands(args[0], builtinfunc.ParsedCalc(args[0]), func(name string) []node {
if n, ok := fields[name]; ok { if n, ok := fields[name]; ok {
+4 -4
View File
@@ -37,9 +37,9 @@ NVDB_PAGE = 50000
OUT = Path(__file__).resolve().parent.parent / "data" / "geo" / "SE" OUT = Path(__file__).resolve().parent.parent / "data" / "geo" / "SE"
CACHE = Path(__file__).resolve().parent / "cache" CACHE = Path(__file__).resolve().parent / "cache"
TIMEZONE = "Europe/Stockholm" TIMEZONE = "Europe/Stockholm"
# This script's reading of the "exceptions in big cities" in docs/research/research-geo-se.md, postnummer Structure. # This script's reading of the "exceptions in big cities" in docs/research/research-geo-se.md, Postal codes → Structure.
ONE_POSITION = {"Stockholm", "Göteborg", "Malmö"} ONE_POSITION = {"Stockholm", "Göteborg", "Malmö"}
# A tätort's floor: "minst 200 invånare", docs/research/research-geo-se.md, Ortnamn. # A tätort's floor: "minst 200 invånare", docs/research/research-geo-se.md, Lantmäteriet → Ortnamn.
UNMATCHED_POPULATION = 200 UNMATCHED_POPULATION = 200
@@ -135,8 +135,8 @@ class Nearest:
def street_delivery(name, codes): def street_delivery(name, codes):
"""The codes delivered to a street: the digit after the postort's own prefix is 0 or 1 for boxes and 8 for reply mail, """The codes delivered to a street: the digit after the postort's own prefix is 0 or 1 for boxes and 8 for reply mail
per docs/research/research-geo-se.md, postnummer Structure.""" outside ONE_POSITION's cities, per docs/research/research-geo-se.md, Postal codes → Structure."""
if name in ONE_POSITION: if name in ONE_POSITION:
return [c for c in codes if c[1] != "0"] return [c for c in codes if c[1] != "0"]
largest = collections.Counter(c[:3] for c in codes).most_common(1)[0][1] largest = collections.Counter(c[:3] for c in codes).most_common(1)[0][1]
+1
View File
@@ -18,6 +18,7 @@ type Template struct {
n node n node
} }
// Fake renders the template once, each {…} drawn afresh.
func (t *Template) Fake() string { func (t *Template) Fake() string {
t.g.mu.Lock() t.g.mu.Lock()
defer t.g.mu.Unlock() defer t.g.mu.Unlock()
+10 -9
View File
@@ -62,11 +62,12 @@ func rendersInside(nodes []node, t *template) bool {
return false return false
} }
// refuseSingleRead refuses b where it is read once, outside a repeat nested where it is bound, at a // refuseSingleRead refuses b when its one read sits in b's own scope, not in a repeat nested inside
// spot the bound spelling can stand: that spelling draws the same without the name, {/word} for // it, at a spot where the bound spelling could stand. That spelling draws the same without the
// {/word as w}{w}. A bound field stands in only where the reading template reaches the binder // name: write {/word} for {/word as w}{w}. A bound field can stand in only where the reading
// through fields, and a calc operand reads neither a reference nor a path. Where the spelling would // template reaches the binder through fields. A calc operand cannot read a reference or a path.
// be a CLI argument or tag of one reference alone, that entry point's own refusal names the bare path. // Where the spelling would be a whole CLI argument or a whole struct tag, that entry point refuses
// it and names the bare path.
func (b *nameBinding) refuseSingleRead(uses []nameUse) error { func (b *nameBinding) refuseSingleRead(uses []nameUse) error {
if len(uses) == 0 { if len(uses) == 0 {
panic(invariant.Broken("name %q has no read at resolve, though its compile found one", b.name)) panic(invariant.Broken("name %q has no read at resolve, though its compile found one", b.name))
@@ -120,10 +121,10 @@ func calcReads(spelling string) bool {
return err == nil && isVar && v.Name == spelling return err == nil && isVar && v.Name == spelling
} }
// refuseTwiceDrawn refuses read, a read of a name rendering n at key under its pick, where n renders // refuseTwiceDrawn refuses read, a read of a name landing on n at key under the name's pick, where n
// a field twice that another read of the name addresses: the pick keeps one draw of the field, so // renders a field twice and another read of the name addresses that field: the pick keeps one draw
// {n.w} beside {n} for a category {w}-{w} cannot say which it reads. addressed maps each level a // of the field, so beside {n} for a category {w}-{w}, {n.w} cannot say which draw it reads.
// read of the name addresses to that read. It walks into every addressed level n renders. // addressed maps each level a read of the name addresses to that read.
func refuseTwiceDrawn(addressed map[pickKey]string, read string, n node, key pickKey) error { func refuseTwiceDrawn(addressed map[pickKey]string, read string, n node, key pickKey) error {
switch n := n.(type) { switch n := n.(type) {
case *choice: case *choice:
+1
View File
@@ -30,6 +30,7 @@ type Record struct {
columns []Column columns []Column
} }
// Columns returns a copy of the record's columns, in name order.
func (r *Record) Columns() []Column { func (r *Record) Columns() []Column {
return append([]Column(nil), r.columns...) return append([]Column(nil), r.columns...)
} }
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"github.com/larvit/fejkdata/internal/grammar" "github.com/larvit/fejkdata/internal/grammar"
) )
// resolvedRef is what a reference resolves to: the head its category is held // resolvedRef is what a reference resolves to: the head its category is held under, a "/"
// under, its path from the root behind a "/", and the tail read into it. // and then the category's path from the root, and the tail read into it.
type resolvedRef struct { type resolvedRef struct {
head string head string
tail []string tail []string
+2 -3
View File
@@ -62,9 +62,8 @@ type resolvedNames struct {
} }
// resolveTemplates resolves ts in steps, each over every template before the next starts. The // resolveTemplates resolves ts in steps, each over every template before the next starts. The
// references, the compiled format and the column read are kept on each template. The names' // names' targets, keys and reads pass to later steps as arguments, and the bindings take their
// targets, keys and reads pass to later steps as arguments, and the bindings take their targets // targets and keys only once every check has passed.
// and keys only once every check has passed.
func resolveTemplates(ts []templateSite, root map[string]node) error { func resolveTemplates(ts []templateSite, root map[string]node) error {
for _, s := range ts { for _, s := range ts {
refs, err := s.t.resolveRefs(s.folder, s.label, s.category, root) refs, err := s.t.resolveRefs(s.folder, s.label, s.category, root)