Answer prose round 1: plainer linkTemplates, ownScope, resolveReads, compileArm and settleRecords docs, recordOf naming its three entry points, a plainer engine decision, and item 117 read as a path's last step
This commit is contained in:
+4
-4
@@ -827,16 +827,16 @@ Valid while names are read only inside the category binding them.
|
|||||||
|
|
||||||
## comprehension floor: every dimension and the overall at 7.0 or above; item 5 scores the restructure, which ships unscored: every `{…}` drawing afresh, the moves into `internal/`, cutting a template's pointer to its table, the move of a table's rows into `internal/rows`, and linking in steps that each return what they build
|
## comprehension floor: every dimension and the overall at 7.0 or above; item 5 scores the restructure, which ships unscored: every `{…}` drawing afresh, the moves into `internal/`, cutting a template's pointer to its table, the move of a table's rows into `internal/rows`, and linking in steps that each return what they build
|
||||||
|
|
||||||
2026-10-04, Lilleman auf Larv. Serves goal 3. The nine-seat panels in `todo.md`'s git history, 2026-09-22 to 2026-09-30, held the score between 5.2 and 6.1, with Locality lowest at every seat. The hardest units were the draw fences, which the change making every `{…}` draw afresh deleted. The restructure deletes or moves what the earlier chunks of the below-floor round touched. It is three things: the change making every `{…}` draw afresh; the moves of the draw state, the grammar, `DataType`, what a proof knows of a value, the builtins and the reading of data files into `internal/`; and the untangling of the engine's own structs, which is the change cutting a template's pointer to its table, the move of a table's rows into `internal/rows`, and linking in steps that each return what they build, with a name scope created beside its owner and each record's columns settled at load. The maintainer approved these three, and `AGENTS.md`'s comprehension rule lets them merge below the floor. A scoring run before the link restructure merged would have scored code about to go; for that reason the calc change accepting a name as an operand shipped unscored on 2026-10-05. No scoring run or panel runs until item 5, which runs the nine-seat panel and larv-review's scoring run. The scoring run writes this entry's first scores. Valid until `todo.md` item 5 runs.
|
2026-10-04, Lilleman auf Larv. Serves goal 3. The nine-seat panels in `todo.md`'s git history, 2026-09-22 to 2026-09-30, held the score between 5.2 and 6.1, with Locality lowest at every seat. The hardest units were the draw fences, which the change making every `{…}` draw afresh deleted. The restructure deletes or moves what the earlier chunks of the below-floor round touched. It is three things: the change making every `{…}` draw afresh; the moves of the draw state, the grammar, `DataType`, what a proof knows of a value, the builtins and the reading of data files into `internal/`; and the untangling of the engine's own structs, which is the change cutting a template's pointer to its table, the move of a table's rows into `internal/rows`, and linking in steps that each return what they build, with a name scope created beside its owner and each record's columns settled at load. The maintainer approved these three, and `AGENTS.md`'s comprehension rule lets them merge below the floor. A scoring run before linking in steps merged would have scored code about to go; for that reason the calc change accepting a name as an operand shipped unscored on 2026-10-05. No scoring run or panel runs until item 5, which runs the nine-seat panel and larv-review's scoring run. The scoring run writes this entry's first scores. Valid until `todo.md` item 5 runs.
|
||||||
|
|
||||||
## The template engine stays the root package until item 107; what reads no engine type, a table's rows included, sits in `internal/`
|
## The template engine stays the root package until item 107; what reads no engine type, a table's rows included, sits in `internal/`
|
||||||
|
|
||||||
2026-10-05, Lilleman auf Larv. Serves goals 3.2 and 3.4. Two architect reviews found the
|
2026-10-05, Lilleman auf Larv. Serves goals 3.2 and 3.4. Two architect reviews found the
|
||||||
engine's types, `template`, `table`, `arm`, `op` and `nameBinding`, bound in one cycle
|
engine's types, `template`, `table`, `arm`, `op` and `nameBinding`, bound in one cycle
|
||||||
because several passes each write part of the same structs; the template language's
|
because several passes each write part of the same structs; the template language's
|
||||||
recursion reads few of those types. Moving the engine before the link gave each value
|
recursion reads few of those types. Moving the engine while several link passes still
|
||||||
one writer would have spread that knot across packages, behind forwarding calls from every
|
wrote each value would have spread that knot across packages, behind forwarding calls from
|
||||||
public method. The draw state, the grammar, `DataType`, what a proof knows of a
|
every public method. The draw state, the grammar, `DataType`, what a proof knows of a
|
||||||
value, the builtins, the reading of data files and a table's rows read no engine type, so
|
value, the builtins, the reading of data files and a table's rows read no engine type, so
|
||||||
each sits in a package under `internal/`, behind the import list `imports_test.go` checks.
|
each sits in a package under `internal/`, behind the import list `imports_test.go` checks.
|
||||||
A rows table holds the engine table owning it as a value of a type parameter, so
|
A rows table holds the engine table owning it as a value of a type parameter, so
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func checkReads(t grammar.Token, fields map[string]node, operands bool) ([]unbou
|
|||||||
if _, _, err := grammar.RefShape(name); err != nil {
|
if _, _, err := grammar.RefShape(name); err != nil {
|
||||||
return nil, fmt.Errorf("token {%s}: %w", t.Body, err)
|
return nil, fmt.Errorf("token {%s}: %w", t.Body, err)
|
||||||
}
|
}
|
||||||
continue // its target is checked at New (see linkCategories)
|
continue // resolveLink checks its target once the tree is assembled
|
||||||
}
|
}
|
||||||
missing, err := checkArm(name, fields, !operands && len(names) == 1)
|
missing, err := checkArm(name, fields, !operands && len(names) == 1)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -316,8 +316,8 @@ func (t *template) compileArms(names []string, targets map[*nameBinding]nameTarg
|
|||||||
return arms, nil
|
return arms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// compileArm compiles one read: a path from the head it names, or from what the name it reads
|
// compileArm compiles one read into a path: from the head it names, or, for a read through a
|
||||||
// through binds.
|
// name, from what that name binds.
|
||||||
func (t *template) compileArm(name string, targets map[*nameBinding]nameTarget) (arm, error) {
|
func (t *template) compileArm(name string, targets map[*nameBinding]nameTarget) (arm, error) {
|
||||||
a := splitArm(name, t.link.refs)
|
a := splitArm(name, t.link.refs)
|
||||||
if !t.isName(a.head) {
|
if !t.isName(a.head) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/larvit/fejkdata/internal/grammar"
|
"github.com/larvit/fejkdata/internal/grammar"
|
||||||
)
|
)
|
||||||
|
|
||||||
// linkSite is a template to link, with the folder and category it sits in, "" for an inline
|
// linkSite is a template to link, with its folder and category, both empty for an inline
|
||||||
// template, and eachNode's label for it.
|
// template, and eachNode's label for it.
|
||||||
type linkSite struct {
|
type linkSite struct {
|
||||||
t *template
|
t *template
|
||||||
@@ -61,10 +61,10 @@ type linkedNames struct {
|
|||||||
uses map[*nameBinding][]nameUse
|
uses map[*nameBinding][]nameUse
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkTemplates links ts in steps, each over every template before the next starts, each
|
// linkTemplates links ts in steps, each over every template before the next starts. Each step
|
||||||
// returning what it builds: the references and the compiled formats, kept on each template, the
|
// returns what it builds. The references, the compiled format and the column read are kept on each
|
||||||
// names' targets, keys and reads, passed to the steps after as arguments, and the column each
|
// template. The names' targets, keys and reads pass to later steps as arguments, and the bindings
|
||||||
// format reads. The bindings take their targets and keys once every check has passed.
|
// take their targets and keys only once every check has passed.
|
||||||
func linkTemplates(ts []linkSite, root map[string]node) error {
|
func linkTemplates(ts []linkSite, root map[string]node) error {
|
||||||
for _, s := range ts {
|
for _, s := range ts {
|
||||||
link, err := s.t.resolveLink(s.folder, s.label, s.category, root)
|
link, err := s.t.resolveLink(s.folder, s.label, s.category, root)
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ func (sc *nameScope) spelled() string {
|
|||||||
return "in one repeat"
|
return "in one repeat"
|
||||||
}
|
}
|
||||||
|
|
||||||
// ownScope is the scope t renders a frame of, nil where that scope binds no name: a category's,
|
// ownScope is the scope t renders a frame of: a category's, once per render of its root, or a
|
||||||
// on its root, or a repeat's, per iteration.
|
// repeat's, once per iteration. It is nil where t owns no scope, or its scope binds no name.
|
||||||
func (t *template) ownScope() *nameScope {
|
func (t *template) ownScope() *nameScope {
|
||||||
if sc := t.nameScope; sc != nil && sc.owner == node(t) && len(sc.order) > 0 {
|
if sc := t.nameScope; sc != nil && sc.owner == node(t) && len(sc.order) > 0 {
|
||||||
return sc
|
return sc
|
||||||
@@ -165,10 +165,10 @@ func eachContained(n node, where string, fn func(c node, where string) error) er
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveReads answers each unbound read under root with a name its template sees, fields before
|
// resolveReads answers each unbound read under root with a name its template sees, and returns
|
||||||
// the format as compile reports them, returning every binding read, and refuses a field spelling a
|
// the set of bindings some read answers to. It refuses a field spelling a name, fields before the
|
||||||
// name. scopes are every scope of the category, which a refusal searches for a name bound where
|
// format, as compile reports them. A refusal searches scopes, every scope of the category, for a
|
||||||
// the read cannot see it.
|
// name bound where the read cannot see it.
|
||||||
func resolveReads(root node, scopes []*nameScope) (map[*nameBinding]bool, error) {
|
func resolveReads(root node, scopes []*nameScope) (map[*nameBinding]bool, error) {
|
||||||
read := map[*nameBinding]bool{}
|
read := map[*nameBinding]bool{}
|
||||||
var resolve func(n node, where string) error
|
var resolve func(n node, where string) error
|
||||||
|
|||||||
+3
-3
@@ -64,9 +64,9 @@ func rendersInside(nodes []node, t *template) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checkUses refuses a binding whose uses read it once at a spot the bound spelling can stand:
|
// checkUses refuses a binding whose uses read it once at a spot the bound spelling can stand:
|
||||||
// that spelling draws the same way without the name. A bound field can stand in only where the reading
|
// that spelling draws the same way without the name. A bound field can stand in only where the
|
||||||
// template reaches the binder through fields. Where the spelling would be a CLI argument or tag
|
// reading template reaches the binder through fields. Where the spelling would be a CLI argument
|
||||||
// of one reference alone, that entry point's own refusal then names the bare path.
|
// or tag of one reference alone, that entry point's own refusal then names the bare path.
|
||||||
func (b *nameBinding) checkUses(uses []nameUse) error {
|
func (b *nameBinding) checkUses(uses []nameUse) error {
|
||||||
if len(uses) == 0 {
|
if len(uses) == 0 {
|
||||||
panic(invariant.Broken("name %q has no read at link, though its compile found one", b.name))
|
panic(invariant.Broken("name %q has no read at link, though its compile found one", b.name))
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ type template struct {
|
|||||||
// Filled by `linkTemplates`, from the assembled tree:
|
// Filled by `linkTemplates`, from the assembled tree:
|
||||||
link templateLink
|
link templateLink
|
||||||
compiled formatOps
|
compiled formatOps
|
||||||
readsColumn *columnRead // set when the format is one reference or name read alone reading a record's column
|
readsColumn *columnRead // set when the format only reads one reference or name, and that read is a record's column
|
||||||
|
|
||||||
// Filled by `settleRecords`, once the load refused every cycle:
|
// Filled by `settleRecords`, once the load refused every cycle:
|
||||||
columns []recordColumn // a record's, where it has fields, in name order
|
columns []recordColumn // a record's, where it has fields, in name order
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ func (f *Generator) FakeRecordTemplate(input string) (*Record, error) {
|
|||||||
// the record to write instead.
|
// the record to write instead.
|
||||||
var ErrNoColumns = errors.New("has no fields, so no columns")
|
var ErrNoColumns = errors.New("has no fields, so no columns")
|
||||||
|
|
||||||
// recordOf is the fence both record entry points pass: the record template n is, whose columns
|
// recordOf is the record template n is, the fence FakeRecord, NewRecordTemplate and FakeStruct
|
||||||
// settleRecords fixed at load for every draw.
|
// pass; settleRecords fixed its columns at load.
|
||||||
func recordOf(n node) (*template, error) {
|
func recordOf(n node) (*template, error) {
|
||||||
if tb, isTable := n.(*table); isTable {
|
if tb, isTable := n.(*table); isTable {
|
||||||
n = tb.formatTemplate
|
n = tb.formatTemplate
|
||||||
@@ -246,8 +246,8 @@ type recordColumn struct {
|
|||||||
boundWhole *nameBinding
|
boundWhole *nameBinding
|
||||||
}
|
}
|
||||||
|
|
||||||
// settleRecords fixes the columns of every record in scope, whose datatypes a cycle would walk
|
// settleRecords fixes the columns of every record in scope. bind runs it after checkNoCycles: a
|
||||||
// forever, so bind refuses the scope's cycles first.
|
// column's datatype walks the column, and a cycle would walk forever.
|
||||||
func settleRecords(scope nodeScope) {
|
func settleRecords(scope nodeScope) {
|
||||||
_ = scope(func(_ string, n node) error {
|
_ = scope(func(_ string, n node) error {
|
||||||
if t, isTemplate := n.(*template); isTemplate {
|
if t, isTemplate := n.(*template); isTemplate {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@
|
|||||||
| 88 | 0.2.0 | | **Add a 12-digit `YYYYMMDDNNNC` form of `sv_SE.personnummer` and `sv_SE.samordningsnummer`, the form Skatteverket's testpersonnummer series and many systems store.** | 2 | 3 | 6 | 6 | 4 | 19.4 |
|
| 88 | 0.2.0 | | **Add a 12-digit `YYYYMMDDNNNC` form of `sv_SE.personnummer` and `sv_SE.samordningsnummer`, the form Skatteverket's testpersonnummer series and many systems store.** | 2 | 3 | 6 | 6 | 4 | 19.4 |
|
||||||
| 41 | 0.2.0 | decision | **Key every table by one key column, as the decision "A table selects by one key column, a code, never a free-form name" states.** | 6 | 7 | 7 | 8 | 5.5 | 19.1 |
|
| 41 | 0.2.0 | decision | **Key every table by one key column, as the decision "A table selects by one key column, a code, never a free-form name" states.** | 6 | 7 | 7 | 8 | 5.5 | 19.1 |
|
||||||
| 52 | 0.2.0 | | **Name the file a link error comes from beside its category path, `sub.x (/d/a/sub/x.json): …`.** | 1 | 2 | 5 | 7 | 6 | 19.0 |
|
| 52 | 0.2.0 | | **Name the file a link error comes from beside its category path, `sub.x (/d/a/sub/x.json): …`.** | 1 | 2 | 5 | 7 | 6 | 19.0 |
|
||||||
| 117 | 0.2.0 | | **List the fields a category has when a path names one it lacks: `{/word as a}{a.zz}` reports `no field "zz"; word has w`.** | 1 | 2 | 5 | 7 | 6 | 19.0 |
|
| 117 | 0.2.0 | | **List the fields a path's last step reached when it names one that step lacks: `{/word as a}{a.zz}` reports `no field "zz"; word has w`.** | 1 | 2 | 5 | 7 | 6 | 19.0 |
|
||||||
| 28 | 0.2.0 | decision | **Accept a middle name, and draw a `personnummer` whose sex matches a sex selected through a named pick.** | 4 | 4 | 6 | 7 | 4.1 | 18.9 |
|
| 28 | 0.2.0 | decision | **Accept a middle name, and draw a `personnummer` whose sex matches a sex selected through a named pick.** | 4 | 4 | 6 | 7 | 4.1 | 18.9 |
|
||||||
| 24 | 0.2.0 | defect | **Stop `misc.territory[EH].tld` rendering `.eh`, the one shipped TLD `misc.tld` does not hold.** | 1 | 1 | 4 | 7 | 4 | 18.6 |
|
| 24 | 0.2.0 | defect | **Stop `misc.territory[EH].tld` rendering `.eh`, the one shipped TLD `misc.tld` does not hold.** | 1 | 1 | 4 | 7 | 4 | 18.6 |
|
||||||
| 92 | 0.2.0 | | **Name the hyphenated field in a `calc`'s refusal, and say to rename it: today `{calc(postal-code * 2)}` reports `no field "postal"`.** | 1 | 2 | 5 | 6 | 6 | 17.5 |
|
| 92 | 0.2.0 | | **Name the hyphenated field in a `calc`'s refusal, and say to rename it: today `{calc(postal-code * 2)}` reports `no field "postal"`.** | 1 | 2 | 5 | 6 | 6 | 17.5 |
|
||||||
@@ -304,7 +304,7 @@ A system that stores the 12-digit form never meets the `+`, so it needs a fixtur
|
|||||||
|
|
||||||
With several `--data-path` layers the author has to work out which directory won, while a parse error on the same file names it.
|
With several `--data-path` layers the author has to work out which directory won, while a parse error on the same file names it.
|
||||||
|
|
||||||
### 117. List the fields a category has when a path names one it lacks: `{/word as a}{a.zz}` reports `no field "zz"; word has w`.
|
### 117. List the fields a path's last step reached when it names one that step lacks: `{/word as a}{a.zz}` reports `no field "zz"; word has w`.
|
||||||
|
|
||||||
Today the refusal names only the missing field, so a data author fixing a typo opens the category to find the spelling. Item 92 covers the hyphenated `calc` operand only.
|
Today the refusal names only the missing field, so a data author fixing a typo opens the category to find the spelling. Item 92 covers the hyphenated `calc` operand only.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user