From 1419673b96c71bc3259a01761337440d5c79c0fa Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Wed, 7 Oct 2026 01:15:50 +0200 Subject: [PATCH] Answer prose round 1 and product-owner round 1: plainer resolvedRef, checkCalcFields and name-fence docs, geo-se.py's pointers name their headings, Fake and Columns keep a godoc line, and arm.go's Layout line names what an arm is --- README.md | 2 +- calc.go | 4 ++-- data-import/geo-se.py | 8 ++++---- inline.go | 1 + namefence.go | 19 ++++++++++--------- record.go | 1 + reference.go | 4 ++-- resolve.go | 5 ++--- 8 files changed, 23 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 0106845..6280999 100644 --- a/README.md +++ b/README.md @@ -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 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 -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 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 diff --git a/calc.go b/calc.go index e61c9f7..934685d 100644 --- a/calc.go +++ b/calc.go @@ -11,8 +11,8 @@ import ( "github.com/larvit/fejkdata/internal/invariant" ) -// checkCalcFields leaves an operand no field holds for a name, which checkCalcNames checks once -// names resolve. +// checkCalcFields checks each calc operand a field holds; an operand no field holds is a name, +// which checkCalcNames checks once names resolve. func checkCalcFields(args []string, fields map[string]node) error { return checkOperands(args[0], builtinfunc.ParsedCalc(args[0]), func(name string) []node { if n, ok := fields[name]; ok { diff --git a/data-import/geo-se.py b/data-import/geo-se.py index 34e6141..0b3a7c5 100644 --- a/data-import/geo-se.py +++ b/data-import/geo-se.py @@ -37,9 +37,9 @@ NVDB_PAGE = 50000 OUT = Path(__file__).resolve().parent.parent / "data" / "geo" / "SE" CACHE = Path(__file__).resolve().parent / "cache" 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ö"} -# 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 @@ -135,8 +135,8 @@ class Nearest: 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, - per docs/research/research-geo-se.md, postnummer Structure.""" + """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 + outside ONE_POSITION's cities, per docs/research/research-geo-se.md, Postal codes → Structure.""" if name in ONE_POSITION: return [c for c in codes if c[1] != "0"] largest = collections.Counter(c[:3] for c in codes).most_common(1)[0][1] diff --git a/inline.go b/inline.go index b84e27f..dbf69f5 100644 --- a/inline.go +++ b/inline.go @@ -18,6 +18,7 @@ type Template struct { n node } +// Fake renders the template once, each {…} drawn afresh. func (t *Template) Fake() string { t.g.mu.Lock() defer t.g.mu.Unlock() diff --git a/namefence.go b/namefence.go index 357a380..ffe4f20 100644 --- a/namefence.go +++ b/namefence.go @@ -62,11 +62,12 @@ func rendersInside(nodes []node, t *template) bool { return false } -// refuseSingleRead refuses b where it is read once, outside a repeat nested where it is bound, at a -// spot the bound spelling can stand: that spelling draws the same without the name, {/word} for -// {/word as w}{w}. A bound field stands in only where the reading template reaches the binder -// through fields, and a calc operand reads neither a reference nor a path. Where the spelling would -// be a CLI argument or tag of one reference alone, that entry point's own refusal names the bare path. +// refuseSingleRead refuses b when its one read sits in b's own scope, not in a repeat nested inside +// it, at a spot where the bound spelling could stand. That spelling draws the same without the +// name: write {/word} for {/word as w}{w}. A bound field can stand in only where the reading +// template reaches the binder through fields. A calc operand cannot read a reference or a 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 { if len(uses) == 0 { 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 } -// refuseTwiceDrawn refuses read, a read of a name rendering n at key under its pick, where n renders -// a field twice that another read of the name addresses: the pick keeps one draw of the field, so -// {n.w} beside {n} for a category {w}-{w} cannot say which it reads. addressed maps each level a -// read of the name addresses to that read. It walks into every addressed level n renders. +// refuseTwiceDrawn refuses read, a read of a name landing on n at key under the name's pick, where n +// renders a field twice and another read of the name addresses that field: the pick keeps one draw +// of the field, so beside {n} for a category {w}-{w}, {n.w} cannot say which draw it reads. +// 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 { switch n := n.(type) { case *choice: diff --git a/record.go b/record.go index 8979f8e..0524b59 100644 --- a/record.go +++ b/record.go @@ -30,6 +30,7 @@ type Record struct { columns []Column } +// Columns returns a copy of the record's columns, in name order. func (r *Record) Columns() []Column { return append([]Column(nil), r.columns...) } diff --git a/reference.go b/reference.go index d5959e8..3b107de 100644 --- a/reference.go +++ b/reference.go @@ -7,8 +7,8 @@ import ( "github.com/larvit/fejkdata/internal/grammar" ) -// resolvedRef is what a reference resolves to: the head its category is held -// under, its path from the root behind a "/", and the tail read into it. +// resolvedRef is what a reference resolves to: the head its category is held under, a "/" +// and then the category's path from the root, and the tail read into it. type resolvedRef struct { head string tail []string diff --git a/resolve.go b/resolve.go index 0ec8927..24b7023 100644 --- a/resolve.go +++ b/resolve.go @@ -62,9 +62,8 @@ type resolvedNames struct { } // 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' -// targets, keys and reads pass to later steps as arguments, and the bindings take their targets -// and keys only once every check has passed. +// names' targets, keys and reads pass to later steps as arguments, and the bindings take their +// targets and keys only once every check has passed. func resolveTemplates(ts []templateSite, root map[string]node) error { for _, s := range ts { refs, err := s.t.resolveRefs(s.folder, s.label, s.category, root)