Answer architecture round 3: walk a table's row node in the cycle check, record where the read-once spelling meets an inline refusal, and cite goal 5.2 for a path tag drawing afresh
This commit is contained in:
+2
-2
@@ -298,8 +298,8 @@ 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
|
||||
`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}`, while a
|
||||
path tag draws afresh as `{/path}` does (goal 4.1); a tagged field that another field hides is refused, not dropped. A named
|
||||
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 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
|
||||
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
|
||||
|
||||
@@ -174,6 +174,9 @@ func checkNoCycles(s nodeScope) error {
|
||||
inScope := map[node]bool{}
|
||||
_ = s(func(_ string, n node) error {
|
||||
inScope[n] = true
|
||||
if t, isTable := n.(*table); isTable {
|
||||
inScope[t.rowNode] = true // a selector lands on it, and contained lists it nowhere
|
||||
}
|
||||
return nil
|
||||
})
|
||||
color := map[node]int{}
|
||||
|
||||
+3
-1
@@ -58,7 +58,9 @@ func rendersInside(nodes []node, t *template) bool {
|
||||
}
|
||||
|
||||
// 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 only beside its binding.
|
||||
// draws the same way without the name. A field stands only beside its binding. 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.
|
||||
func (b *nameBinding) checkUses() error {
|
||||
r := b.uses[0]
|
||||
if len(b.uses) > 1 || r.nested || b.bindsField() && r.in != b.binder {
|
||||
|
||||
@@ -339,3 +339,14 @@ func TestSlashAfterAReferenceSigilIsRejected(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestACycleThroughASelectedRowIsRefused(t *testing.T) {
|
||||
_, err := New(WithoutShippedData(), WithDataPath(writeFiles(t, map[string]string{
|
||||
"x.json": `{"format":"{v} {/y}","rows":"x.tsv","key":"code"}`,
|
||||
"x.tsv": "code\tv\n1\ta\n2\tb\n",
|
||||
"y.json": `"{/x[1]}"`,
|
||||
})))
|
||||
if err == nil || !strings.Contains(err.Error(), "cycle") {
|
||||
t.Fatalf("New = %v, want the cycle through x[1] refused", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user