Answer stability round 3, product-owner round 3 and prose round 1: a column reading a bound column takes its datatype and null, a column bound in part draws afresh, and plainer wording across the README, decisions, plan and errors
This commit is contained in:
@@ -63,7 +63,7 @@ In [docs/decisions.md](docs/decisions.md):
|
|||||||
- A record's column set is fixed before the first draw
|
- A record's column set is fixed before the first draw
|
||||||
- Null is a `null` item, not a rate
|
- Null is a `null` item, not a rate
|
||||||
- A typed column holds one value, not composed text
|
- A typed column holds one value, not composed text
|
||||||
- A column of one reference or name read alone is the column it reads
|
- A column that only reads one reference or name is the column it reads
|
||||||
- A typed column's calc is refused unless proven
|
- A typed column's calc is refused unless proven
|
||||||
- `Column` carries text, not a Go value
|
- `Column` carries text, not a Go value
|
||||||
- A unit takes the stem of what it is, and a file the stem of the units it holds
|
- A unit takes the stem of what it is, and a file the stem of the units it holds
|
||||||
@@ -74,7 +74,7 @@ In [docs/decisions.md](docs/decisions.md):
|
|||||||
- `parent` names the link column and the table alike
|
- `parent` names the link column and the table alike
|
||||||
- After a row, a path names a column or a linked table
|
- After a row, a path names a column or a linked table
|
||||||
- A selected row is fixed, not drawn
|
- A selected row is fixed, not drawn
|
||||||
- `..` steps up to the parent row, and a step down after it draws afresh, or once per pick
|
- `..` steps up to the parent row, and a step down after it draws afresh, or once per name's pick
|
||||||
- A table selects by one key column, a code, never a free-form name
|
- A table selects by one key column, a code, never a free-form name
|
||||||
- A parent row with no child row is a load error
|
- A parent row with no child row is a load error
|
||||||
- The choice-of-rows fence guards a data file's root, and requires string fields
|
- The choice-of-rows fence guards a data file's root, and requires string fields
|
||||||
@@ -111,4 +111,4 @@ In [docs/decisions.md](docs/decisions.md):
|
|||||||
- `List` advertises direct descents only
|
- `List` advertises direct descents only
|
||||||
- A path draws through its compiled steps
|
- A path draws through its compiled steps
|
||||||
- A name lives in the category binding it, or in the repeat binding it, and is drawn on its first read
|
- A name lives in the category binding it, or in the repeat binding it, and is drawn on its first read
|
||||||
- comprehension floor: every dimension and the overall at 7.0 or above; the draw restructure and item 90 ship with no scoring run, and item 5 scores them
|
- comprehension floor: every dimension and the overall at 7.0 or above; the change making every `{…}` draw afresh and item 90 ship with no scoring run, and item 5 scores them
|
||||||
|
|||||||
+8
-8
@@ -12,16 +12,16 @@ replacement, and each removed path, column or flag.
|
|||||||
`{/city[Oslo]..country.name}` renders `Norway`, and `.` after it steps down again,
|
`{/city[Oslo]..country.name}` renders `Norway`, and `.` after it steps down again,
|
||||||
drawing afresh. `New` refuses a `..` naming anything but the parent table, and a
|
drawing afresh. `New` refuses a `..` naming anything but the parent table, and a
|
||||||
selector after a `..`.
|
selector after a `..`.
|
||||||
- Names: `{/misc.territory as t}` binds one row of `misc.territory` to `t` and prints
|
|
||||||
nothing; `{t}`, `{t.capital}` and `{lowercase(t.name)}` read that one row. A name lives
|
|
||||||
in the category binding it, and a `repeat` binding it picks again on every iteration.
|
|
||||||
A name is a `{calc()}` operand: `{/misc.coordinate.lat as lat}{calc(lat * 60)}`. What
|
|
||||||
`New` refuses is listed under [Names](README.md#names).
|
|
||||||
- Every `{…}` draws afresh, and a name is the one way to keep a pick: `{p.a} {p.b}`,
|
- Every `{…}` draws afresh, and a name is the one way to keep a pick: `{p.a} {p.b}`,
|
||||||
`{w} {uppercase(w)}` and `{/person.first} {/person.last}` are two draws each, which
|
`{w} {uppercase(w)}` and `{/person.first} {/person.last}` are two draws each, which
|
||||||
`{p as q}{q.a} {q.b}` and `{/person as n}{n.first} {n.last}` make one. `{x as n}`
|
`{p as q}{q.a} {q.b}` and `{/person as n}{n.first} {n.last}` make one.
|
||||||
binds a sibling field as well as a reference, and a struct's tags share its names,
|
`{/misc.territory as t}` binds one row of `misc.territory` to `t` and prints nothing;
|
||||||
`{/sv_SE.person as p}{p.first}` beside `{p.sex}`.
|
`{t}`, `{t.capital}` and `{lowercase(t.name)}` read that one row. A name binds a
|
||||||
|
reference, a sibling field or a path into one, lives in the category binding it, and
|
||||||
|
picks again on every iteration of a `repeat` binding it. A struct's tags share its
|
||||||
|
names, `{/sv_SE.person as p}{p.first}` beside `{p.sex}`. A name is a `{calc()}`
|
||||||
|
operand: `{/misc.coordinate.lat as lat}{calc(lat * 60)}`. What `New` refuses is listed
|
||||||
|
under [Names](README.md#names).
|
||||||
- First release: the CLI, the library and the shipped data set.
|
- First release: the CLI, the library and the shipped data set.
|
||||||
- Table categories: a category JSON naming a `rows` TSV beside it, with the options
|
- Table categories: a category JSON naming a `rows` TSV beside it, with the options
|
||||||
`key`, `name`, `weight` and `parent`; a path selects a row by key or name,
|
`key`, `name`, `weight` and `parent`; a path selects a row by key or name,
|
||||||
|
|||||||
@@ -137,12 +137,14 @@ it as nothing.
|
|||||||
A record is one render, so its columns read one pick of each [name](#names) its category
|
A record is one render, so its columns read one pick of each [name](#names) its category
|
||||||
binds: `"code": "{/currency as c}{c.code}"` beside `"symbol": "{c.symbol}"` is one
|
binds: `"code": "{/currency as c}{c.code}"` beside `"symbol": "{c.symbol}"` is one
|
||||||
currency, while `{/currency.code}` and `{/currency.symbol}` in two columns may name two. A
|
currency, while `{/currency.code}` and `{/currency.symbol}` in two columns may name two. A
|
||||||
field the format binds whole, `{place as p}`, is a column holding that pick, so it agrees with
|
column the format binds to a name, as `{place as p}` binds `place`, holds that same pick, so it
|
||||||
the columns reading `p`.
|
agrees with the columns reading `p`; a column bound only in part, `{place.town as t}`, draws
|
||||||
|
afresh, so bind it whole and read `{p.town}`.
|
||||||
|
|
||||||
A category never references itself: `{/users.first}` or a bare `{/users}` inside `users`
|
A category never references itself: `{/users.first}` or a bare `{/users}` inside `users`
|
||||||
describes a draw other than the fields beside it. Read a sibling as a field, and put a
|
describes a draw other than the fields beside it. Read a sibling as a field, and put a
|
||||||
value two fields share in its own category, which each binds to a name
|
value two fields share in its own category, bind it to a name in one field, and read the
|
||||||
|
name in both
|
||||||
([Decisions](docs/decisions.md#a-category-never-references-itself-and-a-records-fences-run-at-load)).
|
([Decisions](docs/decisions.md#a-category-never-references-itself-and-a-records-fences-run-at-load)).
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
@@ -342,9 +344,8 @@ naming a kind that holds it. The tags are a record's columns, so they share its
|
|||||||
[names](#names): `First` tagged `{/sv_SE.person as p}{p.first}` and `Sex` tagged `{p.sex}`
|
[names](#names): `First` tagged `{/sv_SE.person as p}{p.first}` and `Sex` tagged `{p.sex}`
|
||||||
describe one person, while two path tags into `sv_SE.person` are two draws. The fields an
|
describe one person, while two path tags into `sv_SE.person` are two draws. The fields an
|
||||||
embedded struct promotes are columns of the same record; a named struct field, or a
|
embedded struct promotes are columns of the same record; a named struct field, or a
|
||||||
pointer to one, fills from its own tags as a record of its own, so it picks apart from its
|
pointer to one, fills from its own tags as a record of its own, so its names and picks are
|
||||||
parent. `fake:"-"` leaves a
|
its own. `fake:"-"` leaves a struct field, embedded or named, or a pointer to one, unfilled. Untagged fields keep
|
||||||
struct field, embedded or named, or a pointer to one, unfilled. Untagged fields keep
|
|
||||||
their values, and so does a pointer back to a struct already being filled; a type
|
their values, and so does a pointer back to a struct already being filled; a type
|
||||||
whose fields reach more than 1024 structs is refused, naming `fake:"-"` to cut it. The
|
whose fields reach more than 1024 structs is refused, naming `fake:"-"` to cut it. The
|
||||||
first call for a type compiles its tags and reports what they get wrong, with the same
|
first call for a type compiles its tags and reports what they get wrong, with the same
|
||||||
@@ -372,15 +373,15 @@ Every character is literal except a `{…}` token:
|
|||||||
| Token | Renders |
|
| Token | Renders |
|
||||||
|-------|---------|
|
|-------|---------|
|
||||||
| `{name}` | the sibling field `name`, or the pick bound to the name ([Names](#names)) |
|
| `{name}` | the sibling field `name`, or the pick bound to the name ([Names](#names)) |
|
||||||
| `{x as name}` | nothing: binds one pick of `x`, a reference or a path into a sibling field, to `name` ([Names](#names)) |
|
| `{x as name}` | nothing: binds one pick of `x`, a reference, a sibling field or a path into one, to `name` ([Names](#names)) |
|
||||||
| `{name.field}` | `field` of a fresh draw of the sibling `name`, or of the pick bound to it ([Correlated fields](#correlated-fields)) |
|
| `{name.field}` | `field` of a fresh draw of the sibling `name`, or of the pick bound to it ([Correlated fields](#correlated-fields)) |
|
||||||
| `{a\|b}` | one of the named fields, even odds |
|
| `{a\|b}` | one of the named fields, even odds |
|
||||||
| `{fn(args)}` | a builtin ([Functions](#functions)) |
|
| `{fn(args)}` | a builtin ([Functions](#functions)) |
|
||||||
| `{/path}`, `{.path}`, `{..path}` | a node reached from the data root, this file's folder, or the folder above ([References](#references)) |
|
| `{/path}`, `{.path}`, `{..path}` | a node reached from the data root, this file's folder, or the folder above ([References](#references)) |
|
||||||
| `{{`, `}}` | a literal `{` or `}` |
|
| `{{`, `}}` | a literal `{` or `}` |
|
||||||
|
|
||||||
Each `{…}` makes a new pick, so `{w} {w}`, `{p.a} {p.b}` and `{/person.first}
|
Each `{…}` draws afresh, so `{w} {w}`, `{p.a} {p.b}` and `{/person.first} {/person.last}`
|
||||||
{/person.last}` are two draws each. A [name](#names) keeps one pick for every read of it.
|
are two draws each. Only a [name](#names) keeps one pick for every read of it.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"100 Main St, Apt {int(1,9)}{upper(1)} — tel {digits(3)}-{digits(4)}"
|
"100 Main St, Apt {int(1,9)}{upper(1)} — tel {digits(3)}-{digits(4)}"
|
||||||
@@ -448,7 +449,7 @@ order.id: datatype integer: {digits(3)} prints text, not an integer
|
|||||||
order.id: datatype integer: "1{digits(2)}" is not one value; write one literal or one {float()}, {int()}, {seq()} or {calc()}, or read one
|
order.id: datatype integer: "1{digits(2)}" is not one value; write one literal or one {float()}, {int()}, {seq()} or {calc()}, or read one
|
||||||
```
|
```
|
||||||
|
|
||||||
A column of one reference or name read alone to another record's column —
|
A column whose format is one read of another record's column and nothing else —
|
||||||
`"score": "{/src.score}"`, or `"score": "{s.score}"` with `s` bound to `/src` — is that column: it takes the column's datatype and is null where the column is, and
|
`"score": "{/src.score}"`, or `"score": "{s.score}"` with `s` bound to `/src` — is that column: it takes the column's datatype and is null where the column is, and
|
||||||
a struct field tagged `src.score` is nil there. A `datatype` of its own types the
|
a struct field tagged `src.score` is nil there. A `datatype` of its own types the
|
||||||
column's values where they prove it, and one restating the datatype it takes is refused.
|
column's values where they prove it, and one restating the datatype it takes is refused.
|
||||||
@@ -569,7 +570,7 @@ country by its weights, then a city inside it by theirs. Two paths are two draws
|
|||||||
[name](#names) agree instead, and the table it binds decides whose weights govern:
|
[name](#names) agree instead, and the table it binds decides whose weights govern:
|
||||||
`{/city as c}` draws a city by city weight and `{c..country.name}` is its country, while
|
`{/city as c}` draws a city by city weight and `{c..country.name}` is its country, while
|
||||||
`{/country as k}` draws a country by country weight and `{k.city.name}` a city inside it.
|
`{/country as k}` draws a country by country weight and `{k.city.name}` a city inside it.
|
||||||
A name keeps every row its reads pin, so `{k.city.name}` and `{k.city.population}` describe
|
A name keeps every row its reads draw, so `{k.city.name}` and `{k.city.population}` describe
|
||||||
one city, and `{k.name}` its country.
|
one city, and `{k.name}` its country.
|
||||||
|
|
||||||
`New` refuses a link cell that is no key of the parent, a parent row no child links to, a
|
`New` refuses a link cell that is no key of the parent, a parent row no child links to, a
|
||||||
@@ -717,8 +718,8 @@ without naming `sv_SE`:
|
|||||||
"Hej, {/en_US.person}!"
|
"Hej, {/en_US.person}!"
|
||||||
```
|
```
|
||||||
|
|
||||||
Renders e.g. `Hej, Pat Smith!`. `{.person.first} {.person.last}` may name two people, as
|
Renders e.g. `Hej, Pat Smith!`. Each reference draws afresh ([Format string](#format-string)),
|
||||||
`{/misc.uuid} {/misc.uuid}` is two draws ([Format string](#format-string)). Bind the person to a [name](#names) to read one: `{.person as p}{p.first}
|
so `{.person.first} {.person.last}` may name two people. Bind the person to a [name](#names) to read one: `{.person as p}{p.first}
|
||||||
{p.last}`. Rejected at `New`: a path that is
|
{p.last}`. Rejected at `New`: a path that is
|
||||||
unknown, names a folder, has no folder above, reads a field not every variant
|
unknown, names a folder, has no folder above, reads a field not every variant
|
||||||
of a choice carries, or names the category the reference sits in, and a reference
|
of a choice carries, or names the category the reference sits in, and a reference
|
||||||
@@ -726,8 +727,8 @@ that leads back to its own value, directly, mutually or through a chain.
|
|||||||
|
|
||||||
### Names
|
### Names
|
||||||
|
|
||||||
`{x as n}` binds one pick of `x`, a reference or a path into a sibling field, to the name `n`
|
`{x as n}` binds one pick of `x`, a reference, a sibling field or a path into one, to the name
|
||||||
and prints nothing. `{n}` then
|
`n` and prints nothing. `{n}` then
|
||||||
prints that pick, and `{n.path}` reads a path through it, so every read of `n` describes one
|
prints that pick, and `{n.path}` reads a path through it, so every read of `n` describes one
|
||||||
row:
|
row:
|
||||||
|
|
||||||
@@ -739,7 +740,7 @@ Renders e.g. `🇳🇴 Norway: capital Oslo, calling code +47`. A name keeps wha
|
|||||||
lands on and every level it passes, so `{n}` and `{n.path}` agree, and so does a
|
lands on and every level it passes, so `{n}` and `{n.path}` agree, and so does a
|
||||||
[transform](#transforms) of `n.path`. Everything else under the name draws as it would
|
[transform](#transforms) of `n.path`. Everything else under the name draws as it would
|
||||||
anywhere: if `n`'s category has the format `{w}-{w}`, it draws `w` twice, and `{n.w}` beside
|
anywhere: if `n`'s category has the format `{w}-{w}`, it draws `w` twice, and `{n.w}` beside
|
||||||
`{n}` is refused, since it could read either draw. A field binds the same way, so
|
`{n}` is refused, since it could read either draw. A sibling field is bound the same way, so
|
||||||
`{place as p}{p.postal-code} {p.locality}` reads one place ([Correlated fields](#correlated-fields)).
|
`{place as p}{p.postal-code} {p.locality}` reads one place ([Correlated fields](#correlated-fields)).
|
||||||
|
|
||||||
A name is a pick of its own: `{t.name}` and `{/misc.territory.name}` beside it are two draws,
|
A name is a pick of its own: `{t.name}` and `{/misc.territory.name}` beside it are two draws,
|
||||||
@@ -756,12 +757,12 @@ Refused at `New`, each error naming what to write instead:
|
|||||||
and outside it;
|
and outside it;
|
||||||
- a name that is a field or an option;
|
- a name that is a field or an option;
|
||||||
- a binding of anything but a reference or a path into a field of the template binding it;
|
- a binding of anything but a reference or a path into a field of the template binding it;
|
||||||
- a read of a name inside the field it binds: read it outside the field;
|
- a read of a name inside the field bound to it: read it outside that field;
|
||||||
- a binding in a choice's item, which every other item would leave unbound;
|
- a binding in a choice's item, which every other item would leave unbound;
|
||||||
- a binding nothing reads, or one read once outside a `repeat` nested where it is bound,
|
- a binding nothing reads, or one read only once, unless that read sits in a `repeat`
|
||||||
which the spelling it binds draws the same way: `{/word as w}{w}` is `{/word}`, and
|
nested where it is bound: write what it binds there instead, `{/word}` for
|
||||||
`{/region as r}{r.name}` is `{/region.name}`; a calc reads neither a reference nor a
|
`{/word as w}{w}` and `{/region.name}` for `{/region as r}{r.name}`; a calc cannot read a
|
||||||
path, so there one read is not refused;
|
reference or a path, so a calc's one read of a name bound to either is not refused;
|
||||||
- a path through a name that selects a row;
|
- a path through a name that selects a row;
|
||||||
- `{n}` beside `{n.w}` where `n`'s category reads `w` twice, as in `{w}-{w}` or
|
- `{n}` beside `{n.w}` where `n`'s category reads `w` twice, as in `{w}-{w}` or
|
||||||
`{w.a} {w.b}`;
|
`{w.a} {w.b}`;
|
||||||
|
|||||||
+1
-1
@@ -76,7 +76,7 @@ func checkColumns(s nodeScope) error {
|
|||||||
checked[column] = true
|
checked[column] = true
|
||||||
items, _ := columnItems(column)
|
items, _ := columnItems(column)
|
||||||
for _, it := range items {
|
for _, it := range items {
|
||||||
if r := it.link.readsColumn; r != nil {
|
if r := it.link.readsColumn; r != nil && r.category != "" {
|
||||||
if err := check(r.category, r.field, r.column); err != nil {
|
if err := check(r.category, r.field, r.column); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-17
@@ -128,19 +128,18 @@ Works against goal 2.3 until `todo.md` item 77 ends it.
|
|||||||
|
|
||||||
## Every `{…}` draws afresh, and only a name keeps a pick
|
## Every `{…}` draws afresh, and only a name keeps a pick
|
||||||
|
|
||||||
2026-10-05, larv-review on the draw restructure the maintainer planned on 2026-10-03.
|
2026-10-05, larv-review on the change the maintainer planned on 2026-10-03.
|
||||||
Serves goals 5.2 and 4.1: each `{…}` makes a new pick, and values that belong together come
|
Serves goals 5.2 and 4.1: each `{…}` makes a new pick, and values that belong together come
|
||||||
from the one pick a name keeps.
|
from the one pick a name keeps.
|
||||||
|
|
||||||
- `{p.a} {p.b}`, `{w} {uppercase(w)}`, `{/p.first} {/p.last}` and `{/p} {/p}` are two draws
|
- `{p.a} {p.b}`, `{w} {uppercase(w)}`, `{/p.first} {/p.last}` and `{/p} {/p}` are two draws
|
||||||
each, and `{p as q}{q.a} {q.b}` is one. Nothing is held per format or per render, so no
|
each, and `{p as q}{q.a} {q.b}` is one. Nothing is kept per format or per render, so the
|
||||||
fence guards a hold: the load checks on draws are names, paths through names, cycles and
|
only load checks on draws are names, paths through names, cycles and the repeat cap.
|
||||||
the repeat cap.
|
- A name binds a reference, or a field of the template binding it or a path into one, `{place as
|
||||||
- A name binds a reference or a path into a field of the template binding it, `{place as
|
|
||||||
p}`: an inline template, and a choice of rows inside one category, have no reference to
|
p}`: an inline template, and a choice of rows inside one category, have no reference to
|
||||||
bind, and goal 4.1 holds there too.
|
bind, and goal 4.1 holds there too.
|
||||||
- A name read once is refused where the spelling it binds stands in, and the error names
|
- A name read once is refused where writing what it binds in its place draws the same, and
|
||||||
that spelling (goal 5.7): `{/x as n}{n.y}` is `{/x.y}`. A calc reads no reference or
|
the error names that spelling (goal 5.7): `{/x as n}{n.y}` is `{/x.y}`. A calc reads no reference or
|
||||||
path, and a read inside a nested repeat keeps one pick on every line, so neither is
|
path, and a read inside a nested repeat keeps one pick on every line, so neither is
|
||||||
refused.
|
refused.
|
||||||
|
|
||||||
@@ -299,9 +298,11 @@ not agree on one among themselves; each must only hold that type.
|
|||||||
The fields an embedded struct promotes are the struct's own — `e.First`, as
|
The fields an embedded struct promotes are the struct's own — `e.First`, as
|
||||||
`encoding/json` and SQL mappers read them — so they are columns of its record and share
|
`encoding/json` and SQL mappers read them — so they are columns of its record and share
|
||||||
its names: one tag may bind `{/person as p}{p.first}` and another read `{p.sex}` (goal 4.1),
|
its names: one tag may bind `{/person as p}{p.first}` and another read `{p.sex}` (goal 4.1),
|
||||||
while a path tag draws afresh as `{/path}` does (goal 5.2). A tag binding a name only an
|
while a path tag draws afresh as `{/path}` does (goal 5.2).
|
||||||
embedding type reads is refused on the embedded type alone, as any name read once is, so the
|
|
||||||
embedder binds it in a tag of its own; a tagged field that another field hides is refused, not dropped. A named
|
A tag binding a name only an embedding type reads is refused on the embedded type alone, as
|
||||||
|
any name read once is, so the embedder binds it in a tag of its own. A tagged field that
|
||||||
|
another field hides is refused, not dropped. A named
|
||||||
struct field is another entity and a record of its own. `fake:"-"` leaves a struct
|
struct field is another entity and a record of its own. `fake:"-"` leaves a struct
|
||||||
field, embedded or named, unfilled, so no name may be `-`; a pointer back to a struct
|
field, embedded or named, unfilled, so no name may be `-`; a pointer back to a struct
|
||||||
already being filled is left alone, since filling it would never end. `New` cannot see a
|
already being filled is left alone, since filling it would never end. `New` cannot see a
|
||||||
@@ -316,7 +317,7 @@ handle is needed, as the cache already compiles once.
|
|||||||
A category is one unit: a reference back into it — `{/users.first}` inside `users` —
|
A category is one unit: a reference back into it — `{/users.first}` inside `users` —
|
||||||
describes a draw other than the fields beside it, so `New` refuses it and the sibling
|
describes a draw other than the fields beside it, so `New` refuses it and the sibling
|
||||||
field stays the one spelling for a field of one's own. A value two fields share goes in its
|
field stays the one spelling for a field of one's own. A value two fields share goes in its
|
||||||
own category, which each binds to a name (goal 4.1). That settled, a record's column fences
|
own category, which one field binds to a name and both read (goal 4.1). That settled, a record's column fences
|
||||||
run at `New` too, so a category that loads renders as a value and as a record alike.
|
run at `New` too, so a category that loads renders as a value and as a record alike.
|
||||||
|
|
||||||
## A record's column set is fixed before the first draw
|
## A record's column set is fixed before the first draw
|
||||||
@@ -345,7 +346,7 @@ Its bounds come from a literal or a call's arguments, so a load error names a re
|
|||||||
value, a range check is one comparison, and `1{digits(2)}` is a second spelling of
|
value, a range check is one comparison, and `1{digits(2)}` is a second spelling of
|
||||||
`{int(100,199)}`.
|
`{int(100,199)}`.
|
||||||
|
|
||||||
## A column of one reference or name read alone is the column it reads
|
## A column that only reads one reference or name is the column it reads
|
||||||
|
|
||||||
2026-09-15, Lilleman auf Larv.
|
2026-09-15, Lilleman auf Larv.
|
||||||
|
|
||||||
@@ -435,10 +436,10 @@ accepted one changes, so the door stays open for the address records the plan de
|
|||||||
Decided 2026-09-27 by the maintainer, for goals 4 and 5; valid while a selector names
|
Decided 2026-09-27 by the maintainer, for goals 4 and 5; valid while a selector names
|
||||||
exactly one row.
|
exactly one row.
|
||||||
|
|
||||||
Selected rows never conflict: `{/misc.territory[SE].capital} / {/misc.territory[FI].capital}`
|
Each selector reads the row it names: `{/misc.territory[SE].capital} / {/misc.territory[FI].capital}`
|
||||||
renders `Stockholm / Helsinki`, and two items of one choice may select different rows.
|
renders `Stockholm / Helsinki`, and two items of one choice may select different rows.
|
||||||
|
|
||||||
## `..` steps up to the parent row, and a step down after it draws afresh, or once per pick
|
## `..` steps up to the parent row, and a step down after it draws afresh, or once per name's pick
|
||||||
|
|
||||||
2026-10-05, larv-review in PR #158. Serves goal 5.4, which has `..` go up one level, and goal
|
2026-10-05, larv-review in PR #158. Serves goal 5.4, which has `..` go up one level, and goal
|
||||||
5.2, which has each `{…}` make a new pick.
|
5.2, which has each `{…}` make a new pick.
|
||||||
@@ -810,7 +811,7 @@ it.
|
|||||||
|
|
||||||
The scope is lexical. A read entering a category, by a reference, through a name or from
|
The scope is lexical. A read entering a category, by a reference, through a name or from
|
||||||
`Fake`, sees no frame (one render of a scope's picks) opened above it, so a category renders
|
`Fake`, sees no frame (one render of a scope's picks) opened above it, so a category renders
|
||||||
the same whoever references it. It opens the frames around where it lands: a read through a
|
the same whoever references it. Such a read opens the frames around where it lands: a read through a
|
||||||
name from its pick's memo, so `{n}` and `{n.path}` read one pick of each name inside, and a
|
name from its pick's memo, so `{n}` and `{n.path}` read one pick of each name inside, and a
|
||||||
reference or `Fake` fresh ones.
|
reference or `Fake` fresh ones.
|
||||||
|
|
||||||
@@ -820,6 +821,6 @@ category's frames, since the field sits inside it.
|
|||||||
|
|
||||||
Valid while names are read only inside the category binding them.
|
Valid while names are read only inside the category binding them.
|
||||||
|
|
||||||
## comprehension floor: every dimension and the overall at 7.0 or above; the draw restructure and item 90 ship with no scoring run, and item 5 scores them
|
## comprehension floor: every dimension and the overall at 7.0 or above; the change making every `{…}` draw afresh and item 90 ship with no scoring run, and item 5 scores them
|
||||||
|
|
||||||
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, and the hardest units were the draw fences the restructure deleted. The draw restructure, shipped 2026-10-05, and `todo.md` item 90 delete or move what the earlier chunks of the below-floor round touched, so a scoring run before item 90 merges would score code about to go; the calc change accepting a name as an operand shipped unscored on 2026-10-05 for that reason. The two finish the round `AGENTS.md`'s comprehension rule lets merge below the floor, a restructure the maintainer approved. 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, and the hardest units were the draw fences that change deleted. The change making every `{…}` draw afresh and `todo.md` item 90 delete or move what the earlier chunks of the below-floor round touched, so a scoring run before item 90 merges would score code about to go; the calc change accepting a name as an operand shipped unscored on 2026-10-05 for that reason. The two finish the round `AGENTS.md`'s comprehension rule lets merge below the floor, a restructure the maintainer approved. 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.
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ func checkBound(ref string, fields map[string]node) error {
|
|||||||
}
|
}
|
||||||
missing, err := checkArm(ref, fields, false)
|
missing, err := checkArm(ref, fields, false)
|
||||||
if missing {
|
if missing {
|
||||||
return fmt.Errorf("%w; a name binds a pick of a field, or of a reference, which starts with /, . or ..", err)
|
return fmt.Errorf("%w; a binding names a field, or a reference, which starts with /, . or ..", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ func (t *template) isName(head string) bool {
|
|||||||
return !isRef(head) && t.fields[head] == nil && t.nameScope.lookup(head) != nil
|
return !isRef(head) && t.fields[head] == nil && t.nameScope.lookup(head) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// linkBindings gives each binding t's tokens make the head and tail what it binds resolved to.
|
// linkBindings resolves what each of t's bindings binds to a head node and a tail path.
|
||||||
func linkBindings(t *template) {
|
func linkBindings(t *template) {
|
||||||
for _, tok := range t.tokens {
|
for _, tok := range t.tokens {
|
||||||
if tok.kind != nameBind {
|
if tok.kind != nameBind {
|
||||||
@@ -255,8 +255,8 @@ func namedReads(t *template, fn func(o *op, a *arm) error) error {
|
|||||||
// starts: a pass reads what the one before filled in.
|
// starts: a pass reads what the one before filled in.
|
||||||
var linkPasses = []func(path string, t *template) error{linkNames, linkColumnRead, checkNameReads, checkCalcNames}
|
var linkPasses = []func(path string, t *template) error{linkNames, linkColumnRead, checkNameReads, checkCalcNames}
|
||||||
|
|
||||||
// linkNames compiles t's reads of a name as paths from the head its binding's reference names, once
|
// linkNames compiles t's reads of a name as paths from the head its binding resolved to, once every
|
||||||
// every template is linked, so each binder has resolved that reference.
|
// template is linked, so each binder has resolved what it binds.
|
||||||
func linkNames(path string, t *template) error {
|
func linkNames(path string, t *template) error {
|
||||||
return namedReads(t, func(o *op, a *arm) error {
|
return namedReads(t, func(o *op, a *arm) error {
|
||||||
if err := linkName(t, a); err != nil {
|
if err := linkName(t, a); err != nil {
|
||||||
|
|||||||
+3
-3
@@ -185,7 +185,7 @@ func TestNameErrors(t *testing.T) {
|
|||||||
{"an option", map[string]string{"word": `["a","b"]`, "card": `"{/word as format}{format}"`},
|
{"an option", map[string]string{"word": `["a","b"]`, "card": `"{/word as format}{format}"`},
|
||||||
`"format" is an option and can never be a name`},
|
`"format" is an option and can never be a name`},
|
||||||
{"no reference or field", map[string]string{"card": `{"format":"{word as w}{w}{w}","words":["a","b"]}`},
|
{"no reference or field", map[string]string{"card": `{"format":"{word as w}{w}{w}","words":["a","b"]}`},
|
||||||
`no field "word"; a name binds a pick of a field, or of a reference`},
|
`no field "word"; a binding names a field, or a reference`},
|
||||||
{"read once through a field", map[string]string{"card": `{"format":"{place as p}{p.x}","place":{"format":"{x}","x":["a","b"]}}`},
|
{"read once through a field", map[string]string{"card": `{"format":"{place as p}{p.x}","place":{"format":"{x}","x":["a","b"]}}`},
|
||||||
`name "p" is read once, so it keeps no pick for another read; write {place.x} where it is read`},
|
`name "p" is read once, so it keeps no pick for another read; write {place.x} where it is read`},
|
||||||
{"read by nothing", map[string]string{"word": `["a","b"]`, "card": `"{/word as w}"`},
|
{"read by nothing", map[string]string{"word": `["a","b"]`, "card": `"{/word as w}"`},
|
||||||
@@ -380,8 +380,8 @@ func TestOneRenderReadsOneNameAcrossNestedTemplates(t *testing.T) {
|
|||||||
func TestAFieldBindingReadInsideItsFieldIsRefused(t *testing.T) {
|
func TestAFieldBindingReadInsideItsFieldIsRefused(t *testing.T) {
|
||||||
f := engine(1)
|
f := engine(1)
|
||||||
for src, want := range map[string]string{
|
for src, want := range map[string]string{
|
||||||
`{"format":"{x as n}{n}{n}","x":"{n}"}`: `name "n" is read inside "x", the field it binds`,
|
`{"format":"{x as n}{n}{n}","x":"{n}"}`: `name "n" is read inside "x", the field bound to it`,
|
||||||
`{"format":"{x as n}{n.a}{n.a}","x":{"format":"{a}","a":"{n}"}}`: `name "n" is read inside "x", the field it binds`,
|
`{"format":"{x as n}{n.a}{n.a}","x":{"format":"{a}","a":"{n}"}}`: `name "n" is read inside "x", the field bound to it`,
|
||||||
`{"format":"{x as n}{y as m}{n}{n}{m}{m}","x":"{m}","y":"{n}"}`: "cycle",
|
`{"format":"{x as n}{y as m}{n}{n}{m}{m}","x":"{m}","y":"{n}"}`: "cycle",
|
||||||
} {
|
} {
|
||||||
if _, err := f.NewTemplate(src); err == nil || !strings.Contains(err.Error(), want) {
|
if _, err := f.NewTemplate(src); err == nil || !strings.Contains(err.Error(), want) {
|
||||||
|
|||||||
+6
-5
@@ -6,8 +6,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// checkNameReads refuses each binding of t that checkUses refuses, and a read such as {n} whose
|
// checkNameReads refuses each binding of t that checkUses refuses, a read of a name inside the
|
||||||
// pick renders twice a field another read, {n.w}, reads once: the pick keeps one draw of it.
|
// field bound to it, and a read {n} beside {n.w} where n's pick renders w twice: the pick keeps one
|
||||||
|
// draw of w.
|
||||||
func checkNameReads(path string, t *template) error {
|
func checkNameReads(path string, t *template) error {
|
||||||
for _, tok := range t.tokens {
|
for _, tok := range t.tokens {
|
||||||
if tok.kind != nameBind {
|
if tok.kind != nameBind {
|
||||||
@@ -19,7 +20,7 @@ func checkNameReads(path string, t *template) error {
|
|||||||
}
|
}
|
||||||
return namedReads(t, func(o *op, a *arm) error {
|
return namedReads(t, func(o *op, a *arm) error {
|
||||||
if a.named.bindsField() && rendersInside(compilePath(a.named.head, a.named.tail).leaves, t) {
|
if a.named.bindsField() && rendersInside(compilePath(a.named.head, a.named.tail).leaves, t) {
|
||||||
return fmt.Errorf("%s: token {%s}: name %q is read inside %q, the field it binds; read the name outside that field", t.site.label(path), o.body, a.named.name, a.named.ref)
|
return fmt.Errorf("%s: token {%s}: name %q is read inside %q, the field bound to it; read the name outside that field", t.site.label(path), o.body, a.named.name, a.named.ref)
|
||||||
}
|
}
|
||||||
for _, leaf := range a.leaves {
|
for _, leaf := range a.leaves {
|
||||||
if err := a.named.checkOnce(a.spelling, leaf, a.path); err != nil {
|
if err := a.named.checkOnce(a.spelling, leaf, a.path); err != nil {
|
||||||
@@ -58,8 +59,8 @@ func rendersInside(nodes []node, t *template) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checkUses refuses a binding read once at a spot the bound spelling can stand: that spelling
|
// checkUses refuses a binding read once at a spot the bound spelling can stand: that spelling
|
||||||
// draws the same way without the name. A field stands where the reading template reaches the
|
// draws the same way without the name. A bound field can stand in only where the reading template
|
||||||
// binder through fields. Where the spelling would be a CLI argument or tag of one reference alone,
|
// reaches the binder through fields. Where the spelling would be a CLI argument or tag of one reference alone,
|
||||||
// that entry point's own refusal then names the bare path.
|
// that entry point's own refusal then names the bare path.
|
||||||
func (b *nameBinding) checkUses() error {
|
func (b *nameBinding) checkUses() error {
|
||||||
r := b.uses[0]
|
r := b.uses[0]
|
||||||
|
|||||||
@@ -183,8 +183,8 @@ func readUnder(s *generatorState, t *template, sc renderScope, a arm) readValue
|
|||||||
return p.renderAt(s, leaf, pins, key, sc)
|
return p.renderAt(s, leaf, pins, key, sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// underKey is the key of path under the pick key prefix. It never returns prefix itself, which a
|
// underKey is the key of path under the pick key prefix. It never returns prefix itself: prefix is
|
||||||
// memo would keep: anything a renderScope holds reaching the heap moves every render's scope there.
|
// sc.pickKey, and a memo keeping it would move every render's scope to the heap.
|
||||||
func underKey(prefix, path string) string {
|
func underKey(prefix, path string) string {
|
||||||
if prefix == "" {
|
if prefix == "" {
|
||||||
return path
|
return path
|
||||||
|
|||||||
@@ -307,3 +307,28 @@ func TestAFieldBoundWholeIsItsPickAsAColumn(t *testing.T) {
|
|||||||
t.Errorf("place drew only %v in 100 records, want both", seen)
|
t.Errorf("place drew only %v in 100 records, want both", seen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAColumnReadingABoundColumnIsThatColumn(t *testing.T) {
|
||||||
|
f := newGenerator(t, writeData(t, map[string]string{
|
||||||
|
"row": `{"format":"{place as p}","place":[null,{"format":"{int(1,9)}","datatype":"integer"}],"a":"{p}","z":"{p}"}`,
|
||||||
|
}), WithSeed(1))
|
||||||
|
nulls := 0
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
r, err := f.FakeRecord("row")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
c := r.Columns()
|
||||||
|
for _, col := range c {
|
||||||
|
if col.DataType != DataTypeInteger || col.Null != c[0].Null || col.Value != c[0].Value {
|
||||||
|
t.Fatalf("%s: want a, place and z one integer pick, null alike", r.JSON())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c[0].Null {
|
||||||
|
nulls++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nulls == 0 || nulls == 100 {
|
||||||
|
t.Errorf("the pick was null %d times in 100 records, want both outcomes", nulls)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ func renderRecord(s *generatorState, t *template, columns []Column, sc renderSco
|
|||||||
field := t.fields[r.columns[i].Name]
|
field := t.fields[r.columns[i].Name]
|
||||||
var column readValue
|
var column readValue
|
||||||
if b := bindingOfWhole(t, field); b != nil {
|
if b := bindingOfWhole(t, field); b != nil {
|
||||||
column = readName(s, sc, arm{kind: namedRead, named: b, levels: []string{""}})
|
column = readName(s, sc, arm{kind: namedRead, named: b, levels: wholeLevels})
|
||||||
} else {
|
} else {
|
||||||
column = renderLeaf(s, field, sc)
|
column = renderLeaf(s, field, sc)
|
||||||
}
|
}
|
||||||
@@ -278,6 +278,9 @@ func renderRecord(s *generatorState, t *template, columns []Column, sc renderSco
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wholeLevels is the levels of a read of a whole name, as linkName compiles {n}.
|
||||||
|
var wholeLevels = []string{""}
|
||||||
|
|
||||||
// bindingOfWhole is the name t binds to the whole of field, whose pick the field's column renders
|
// bindingOfWhole is the name t binds to the whole of field, whose pick the field's column renders
|
||||||
// so the row agrees with the columns reading the name; nil where none does.
|
// so the row agrees with the columns reading the name; nil where none does.
|
||||||
func bindingOfWhole(t *template, field node) *nameBinding {
|
func bindingOfWhole(t *template, field node) *nameBinding {
|
||||||
|
|||||||
+13
-8
@@ -155,7 +155,9 @@ func (t *template) resolveLink(folder []string, path, category string, root map[
|
|||||||
}
|
}
|
||||||
|
|
||||||
// columnRead is a record's column read by a format of that one reference or name read alone,
|
// columnRead is a record's column read by a format of that one reference or name read alone,
|
||||||
// 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
|
||||||
|
// on its own.
|
||||||
type columnRead struct {
|
type columnRead struct {
|
||||||
a arm
|
a arm
|
||||||
category, field string
|
category, field string
|
||||||
@@ -170,18 +172,21 @@ func linkColumnRead(_ string, t *template) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
a := ops[0].arms[0]
|
a := ops[0].arms[0]
|
||||||
head, category, tail := t.head(a.head), a.head, a.tail
|
head, category, tail := t.head(a.head), a.head[min(1, len(a.head)):], a.tail
|
||||||
switch {
|
switch b := a.named; {
|
||||||
case a.kind == namedRead && !a.named.bindsField():
|
case a.kind == namedRead && b.bindsField():
|
||||||
ref := a.named.binder.link.refs[a.named.ref]
|
head, category = b.binder, ""
|
||||||
head, category = a.named.head, ref.head
|
tail = append(append([]string{splitArm(b.ref, nil).head}, b.tail...), a.tail...)
|
||||||
|
case a.kind == namedRead:
|
||||||
|
ref := b.binder.link.refs[b.ref]
|
||||||
|
head, category = b.head, ref.head[1:]
|
||||||
tail = append(ref.tail[:len(ref.tail):len(ref.tail)], a.tail...)
|
tail = append(ref.tail[:len(ref.tail):len(ref.tail)], a.tail...)
|
||||||
case a.kind == namedRead || !isRef(a.head):
|
case !isRef(a.head):
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
target, isTemplate := head.(*template)
|
target, isTemplate := head.(*template)
|
||||||
if isTemplate && target.isRecord && len(tail) == 1 {
|
if isTemplate && target.isRecord && len(tail) == 1 {
|
||||||
t.link.readsColumn = &columnRead{a: a, category: category[1:], field: tail[0], column: target.fields[tail[0]]}
|
t.link.readsColumn = &columnRead{a: a, category: category, field: tail[0], column: target.fields[tail[0]]}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ func readField(s *generatorState, t *template, sc renderScope, a arm) readValue
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// renderLeaf draws and renders what a read lands on: null on a null item, or on a column of one
|
// renderLeaf draws and renders what a read lands on: null on a null item, or on a column that only
|
||||||
// reference alone whose read drew null.
|
// reads one reference or name whose read drew null.
|
||||||
func renderLeaf(s *generatorState, n node, sc renderScope) readValue {
|
func renderLeaf(s *generatorState, n node, sc renderScope) readValue {
|
||||||
n = resolveChoice(s, n)
|
n = resolveChoice(s, n)
|
||||||
switch leaf := n.(type) {
|
switch leaf := n.(type) {
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ type renderedRow struct {
|
|||||||
index int
|
index int
|
||||||
}
|
}
|
||||||
|
|
||||||
// at is the scope n, the leaf of a path that pinned its rows in pins, renders in: where n is a
|
// at returns the scope n renders in, n being the leaf of a path whose rows sit in pins; where n
|
||||||
// table's row or column, at the row pins holds for that table.
|
// is a table's row or column, the scope carries the row pins holds for that table.
|
||||||
func (sc renderScope) at(n node, pins *pinSet) renderScope {
|
func (sc renderScope) at(n node, pins *pinSet) renderScope {
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *tableRow:
|
case *tableRow:
|
||||||
|
|||||||
@@ -72,8 +72,8 @@
|
|||||||
| 15 | 0.1.0 | | **Add the remaining `misc` tables and templates, one row of its detail's table per chunk.** | 3 | 9 | 8 | 8 | 2, 15, 14 | 25.9 |
|
| 15 | 0.1.0 | | **Add the remaining `misc` tables and templates, one row of its detail's table per chunk.** | 3 | 9 | 8 | 8 | 2, 15, 14 | 25.9 |
|
||||||
| 57 | 0.1.0 | | **Rewrite `CHANGELOG.md`'s `[Unreleased]` as what v0.1.0 holds.** | 1 | 2 | 6 | 6 | 1.1 | 22.5 |
|
| 57 | 0.1.0 | | **Rewrite `CHANGELOG.md`'s `[Unreleased]` as what v0.1.0 holds.** | 1 | 2 | 6 | 6 | 1.1 | 22.5 |
|
||||||
| 34 | 0.1.0 | | **Add `{isin()}`, `{cusip()}`, `{aba()}` and `{vin()}`.** | 2 | 4 | 6 | 7 | 4 | 20.9 |
|
| 34 | 0.1.0 | | **Add `{isin()}`, `{cusip()}`, `{aba()}` and `{vin()}`.** | 2 | 4 | 6 | 7 | 4 | 20.9 |
|
||||||
| 96 | 0.1.0 | question | **Refuse two reads of one sibling, one category or one struct category by different spellings, `{place.postal-code} {place.locality}`, showing the spelling for one pick and the one for two.** | 4 | 4 | 7 | 7 | 5.6, 4 | 20.9 |
|
| 96 | 0.1.0 | question | **Refuse two reads into one sibling, category or struct category that no name joins, `{place.postal-code} {place.locality}`, showing the spelling for one pick and the one for two.** | 4 | 4 | 7 | 7 | 5.6, 4 | 20.9 |
|
||||||
| 5 | 0.1.0 | decision | **Run the nine-seat comprehension panel after the draw restructure, and file what it names.** | 1 | 3 | 3 | 9 | 3 | 20.4 |
|
| 5 | 0.1.0 | decision | **Run the nine-seat comprehension panel after every `{…}` draws afresh and the code is restructured, and file what it names.** | 1 | 3 | 3 | 9 | 3 | 20.4 |
|
||||||
| 91 | 0.1.0 | | **Accept a path through a name as a `calc` operand, so `{/misc.coordinate as c}{c}: {calc(c.lat * 60)}` computes from the coordinate `{c}` prints.** | 3 | 4 | 6 | 7 | 4.1, 5.3 | 19.9 |
|
| 91 | 0.1.0 | | **Accept a path through a name as a `calc` operand, so `{/misc.coordinate as c}{c}: {calc(c.lat * 60)}` computes from the coordinate `{c}` prints.** | 3 | 4 | 6 | 7 | 4.1, 5.3 | 19.9 |
|
||||||
| 89 | 0.1.0 | | **Fail `New` without `WithSeed`, naming the option, and seed the CLI from the system.** | 3 | 3 | 6 | 7 | 10.1 | 16.0 |
|
| 89 | 0.1.0 | | **Fail `New` without `WithSeed`, naming the option, and seed the CLI from the system.** | 3 | 3 | 6 | 7 | 10.1 | 16.0 |
|
||||||
| 90 | 0.1.0 | decision | **Restructure the code into folders named for what they hold: the public API stays in the root package, and the implementation moves into `internal/` packages.** | 6 | 9 | 3 | 9 | 3.2, 3.4 | 13.9 |
|
| 90 | 0.1.0 | decision | **Restructure the code into folders named for what they hold: the public API stays in the root package, and the implementation moves into `internal/` packages.** | 6 | 9 | 3 | 9 | 3.2, 3.4 | 13.9 |
|
||||||
@@ -234,13 +234,13 @@ Nothing has shipped, so "no longer paths", "where it used to fail" and "where it
|
|||||||
|
|
||||||
`isin`: Luhn over letters expanded to digits. `aba`: 3-7-1 weights. `vin`: position 9 over the whole; a sample taking the WMI, since the check sits mid-string.
|
`isin`: Luhn over letters expanded to digits. `aba`: 3-7-1 weights. `vin`: position 9 over the whole; a sample taking the WMI, since the check sits mid-string.
|
||||||
|
|
||||||
### 96. Refuse two reads of one sibling, one category or one struct category by different spellings, `{place.postal-code} {place.locality}`, showing the spelling for one pick and the one for two.
|
### 96. Refuse two reads into one sibling, category or struct category that no name joins, `{place.postal-code} {place.locality}`, showing the spelling for one pick and the one for two.
|
||||||
|
|
||||||
Asked of the maintainer by the product-owner pass of item 4's chunk. Since every `{…}` draws afresh, `{net} x {qty} = {calc(net * qty, 2)}`, `{place.postal-code} {place.locality}` and struct tags `sv_SE.address.street` beside `sv_SE.address.postal-code` load and may render a pair that disagrees, and nothing tells the author to bind a name (goal 4.1). Goal 5.6 asks such a template to fail, showing `{place as p}{p.postal-code} {p.locality}` for one place and two names for two. Item 4 planned the draw checks as names, paths through names, cycles and the repeat cap, so the fence would revise the decision "Every `{…}` draws afresh, and only a name keeps a pick". `{w} {w}`, one spelling twice, stays two draws. Open: whether reads across categories, `{/city.name}, {/country.name}`, count.
|
Asked of the maintainer by the product-owner pass of the chunk that made every `{…}` draw afresh. Since every `{…}` draws afresh, `{net} x {qty} = {calc(net * qty, 2)}`, `{place.postal-code} {place.locality}` and struct tags `sv_SE.address.street` beside `sv_SE.address.postal-code` load and may render a pair that disagrees, and nothing tells the author to bind a name (goal 4.1). Goal 5.6 asks such a template to fail, showing `{place as p}{p.postal-code} {p.locality}` for one place and two names for two. The decision "Every `{…}` draws afresh, and only a name keeps a pick" lists the draw checks as names, paths through names, cycles and the repeat cap, so this fence revises it. `{w} {w}`, one spelling twice, stays two draws. Open: whether reads across categories, `{/city.name}, {/country.name}`, count.
|
||||||
|
|
||||||
### 5. Run the nine-seat comprehension panel after the draw restructure, and file what it names.
|
### 5. Run the nine-seat comprehension panel after every `{…}` draws afresh and the code is restructured, and file what it names.
|
||||||
|
|
||||||
Needs item 90. The decision "comprehension floor: every dimension and the overall at 7.0 or above; the draw restructure and item 90 ship with no scoring run, and item 5 scores them" suspends every scoring run and panel until then.
|
Needs item 90. The decision "comprehension floor: every dimension and the overall at 7.0 or above; the change making every `{…}` draw afresh and item 90 ship with no scoring run, and item 5 scores them" suspends every scoring run and panel until then.
|
||||||
|
|
||||||
### 91. Accept a path through a name as a `calc` operand, so `{/misc.coordinate as c}{c}: {calc(c.lat * 60)}` computes from the coordinate `{c}` prints.
|
### 91. Accept a path through a name as a `calc` operand, so `{/misc.coordinate as c}{c}: {calc(c.lat * 60)}` computes from the coordinate `{c}` prints.
|
||||||
|
|
||||||
@@ -301,7 +301,7 @@ With several `--data-path` layers the author has to work out which directory won
|
|||||||
|
|
||||||
### 28. Accept a middle name, and draw a `personnummer` whose sex matches a sex selected through a named pick.
|
### 28. Accept a middle name, and draw a `personnummer` whose sex matches a sex selected through a named pick.
|
||||||
|
|
||||||
Today `personnummer` draws its own sex, so a person bound to `{/sv_SE.sex[f] as s}` needs the template the README's Data section shows to agree with a number.
|
Today `personnummer` draws its own sex, so a name and a number agree only through the README Data section's template, which reads both through one bound `sex`.
|
||||||
|
|
||||||
### 24. Stop `misc.territory[EH].tld` rendering `.eh`, the one shipped TLD `misc.tld` does not hold.
|
### 24. Stop `misc.territory[EH].tld` rendering `.eh`, the one shipped TLD `misc.tld` does not hold.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ type valueProof struct {
|
|||||||
|
|
||||||
// checkDatatype rejects a typed column item some render of which is not text of its datatype,
|
// checkDatatype rejects a typed column item some render of which is not text of its datatype,
|
||||||
// and one restating the datatype of the column it is.
|
// and one restating the datatype of the column it is.
|
||||||
// docs/decisions.md#a-column-of-one-reference-alone-is-the-column-it-reads
|
// docs/decisions.md#a-column-that-only-reads-one-reference-or-name-is-the-column-it-reads
|
||||||
func (p *valueProof) checkDatatype(path string, n node) error {
|
func (p *valueProof) checkDatatype(path string, n node) error {
|
||||||
t, ok := n.(*template)
|
t, ok := n.(*template)
|
||||||
if !ok || t.datatype == DataTypeString {
|
if !ok || t.datatype == DataTypeString {
|
||||||
|
|||||||
Reference in New Issue
Block a user