Rename arm.key to head, give renderScope.row its own type, and value.go to valueproof.go
This commit is contained in:
@@ -896,7 +896,7 @@ checksum.go the check characters a derivation appends, and the IBAN they sit
|
||||
transform.go the builtins that rewrite an operand's value, and the ASCII folding
|
||||
calc.go the {calc()} arithmetic evaluator: parser, eval, validation
|
||||
datatype.go column datatypes: DataType, where datatype and null may sit, a column's datatype
|
||||
value.go the value proof: what a typed column or calc operand holds, checked at load
|
||||
valueproof.go the value proof: what a typed column or calc operand holds, checked at load
|
||||
data.go the load path: fs.FS folders/files -> merged namespace tree, and the bind pipeline every entry point runs
|
||||
cmd/fejkdata/ the fejkdata CLI
|
||||
data/ shipped data (JSON, and a TSV per table), embedded at build: locale folders, geo, misc
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ func checkColumns(s nodeScope) error {
|
||||
items, _ := columnItems(column)
|
||||
for _, it := range items {
|
||||
if r := it.link.readsColumn; r != nil {
|
||||
if err := check(r.a.key[1:], r.a.tail[0], r.column); err != nil {
|
||||
if err := check(r.a.head[1:], r.a.tail[0], r.column); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -90,7 +90,7 @@ func checkOwnFamily(t *template) error {
|
||||
seen[n] = true
|
||||
for _, e := range renderEdges(n) {
|
||||
if e.readsRef() {
|
||||
if head, isTable := n.(*template).head(e.read.key).(*table); isTable && head.familyRoot() == own.familyRoot() {
|
||||
if head, isTable := n.(*template).head(e.read.head).(*table); isTable && head.familyRoot() == own.familyRoot() {
|
||||
return e, head, true
|
||||
}
|
||||
}
|
||||
@@ -183,7 +183,7 @@ func readsTable(n node, a arm) bool {
|
||||
if !isTemplate {
|
||||
return false
|
||||
}
|
||||
_, isTable := t.head(a.key).(*table)
|
||||
_, isTable := t.head(a.head).(*table)
|
||||
return isTable
|
||||
}
|
||||
|
||||
|
||||
@@ -246,25 +246,25 @@ func checkArm(name string, fields map[string]node, wholeToken bool) error {
|
||||
if err := checkSegments(a); err != nil {
|
||||
return err
|
||||
}
|
||||
field, ok := fields[a.key]
|
||||
field, ok := fields[a.head]
|
||||
if !ok {
|
||||
if a.key == "" {
|
||||
if a.head == "" {
|
||||
return fmt.Errorf("a name is never empty, so this token can name no field")
|
||||
}
|
||||
if isOption(a.key) {
|
||||
return fmt.Errorf("%q is an option and can never be a field", a.key)
|
||||
if isOption(a.head) {
|
||||
return fmt.Errorf("%q is an option and can never be a field", a.head)
|
||||
}
|
||||
if len(fields) == 0 {
|
||||
hint := ""
|
||||
if wholeToken && hintableRef(name) {
|
||||
hint = fmt.Sprintf(" — write {/%s} to reference the data", name)
|
||||
}
|
||||
return fmt.Errorf("no field %q; a token names a sibling field, and this template has none%s", a.key, hint)
|
||||
return fmt.Errorf("no field %q; a token names a sibling field, and this template has none%s", a.head, hint)
|
||||
}
|
||||
return fmt.Errorf("no field %q", a.key)
|
||||
return fmt.Errorf("no field %q", a.head)
|
||||
}
|
||||
if err := checkPath(field, a.tail, a.key); err != nil {
|
||||
return fmt.Errorf("field %q: %w", a.key, err)
|
||||
if err := checkPath(field, a.tail, a.head); err != nil {
|
||||
return fmt.Errorf("field %q: %w", a.head, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -302,45 +302,45 @@ func checkNoRepeatedArm(body string, names []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// arm is one alternative of a {a|b} token or one operand, split into the key
|
||||
// arm is one alternative of a {a|b} token or one operand, split into the head
|
||||
// `template.head` resolves and the tail of a dotted path into it. A non-empty tail
|
||||
// is what makes the arm a held draw: its head is drawn once per expansion (see
|
||||
// compileOps).
|
||||
type arm struct {
|
||||
spelling string // as written, for messages
|
||||
key string
|
||||
head string
|
||||
tail []string
|
||||
levels []string // the key at each level the tail passes through, the arm's key first
|
||||
path string // key and tail, the one path every way of writing this read shares
|
||||
levels []string // the path at each level the tail passes through, the head first
|
||||
path string // head and tail, the one path every way of writing this read shares
|
||||
}
|
||||
|
||||
// splitArm splits one name into key and tail. refs maps a reference to what
|
||||
// splitArm splits one name into head and tail. refs maps a reference to what
|
||||
// linkRefs resolved it to; before linking, a reference is whole.
|
||||
func splitArm(name string, refs map[string]refBinding) arm {
|
||||
if isRef(name) {
|
||||
b, linked := refs[name]
|
||||
if !linked || len(b.tail) == 0 {
|
||||
key := name
|
||||
head := name
|
||||
if linked {
|
||||
key = b.key
|
||||
head = b.key
|
||||
}
|
||||
return arm{spelling: name, key: key, path: key}
|
||||
return arm{spelling: name, head: head, path: head}
|
||||
}
|
||||
return pathArm(name, b.key, b.tail)
|
||||
}
|
||||
segs, err := splitPath(name)
|
||||
if err != nil || len(segs) == 1 {
|
||||
return arm{spelling: name, key: name, path: name}
|
||||
return arm{spelling: name, head: name, path: name}
|
||||
}
|
||||
return pathArm(name, segs[0], segs[1:])
|
||||
}
|
||||
|
||||
func pathArm(name, key string, segs []string) arm {
|
||||
levels := []string{key}
|
||||
func pathArm(name, head string, segs []string) arm {
|
||||
levels := []string{head}
|
||||
for i := 0; i < len(segs)-1; i++ {
|
||||
levels = append(levels, key+"."+strings.Join(segs[:i+1], "."))
|
||||
levels = append(levels, head+"."+strings.Join(segs[:i+1], "."))
|
||||
}
|
||||
return arm{spelling: name, key: key, tail: segs, levels: levels, path: key + "." + strings.Join(segs, ".")}
|
||||
return arm{spelling: name, head: head, tail: segs, levels: levels, path: head + "." + strings.Join(segs, ".")}
|
||||
}
|
||||
|
||||
// checkSegments rejects an unfinished path: "{a.}" and "{a..b}" each have a
|
||||
@@ -350,7 +350,7 @@ func checkSegments(a arm) error {
|
||||
if len(a.tail) == 0 {
|
||||
return nil
|
||||
}
|
||||
if a.key == "" {
|
||||
if a.head == "" {
|
||||
return fmt.Errorf("path has an empty segment")
|
||||
}
|
||||
for _, seg := range a.tail {
|
||||
@@ -379,13 +379,13 @@ type op struct {
|
||||
}
|
||||
|
||||
// formatOps is a compiled format: its ops, the size of its literal text, and the
|
||||
// names it holds. pathKeys maps each key a path starts from to the first such path;
|
||||
// held is every such key plus the fields an operand reads; holder maps each held
|
||||
// names it holds. pathHeads maps each head a path starts from to the first such path;
|
||||
// held is every such head plus the fields an operand reads; holder maps each held
|
||||
// name to the first reader holding it, for error messages.
|
||||
type formatOps struct {
|
||||
ops []op
|
||||
grow int
|
||||
pathKeys map[string]string
|
||||
pathHeads map[string]string
|
||||
held map[string]bool
|
||||
holder map[string]string
|
||||
heldLocal bool // some held name is not a reference path, so expand makes a hold
|
||||
@@ -396,19 +396,19 @@ func (c *formatOps) holdName(a arm, label string) {
|
||||
c.held = map[string]bool{}
|
||||
c.holder = map[string]string{}
|
||||
}
|
||||
c.held[a.key] = true
|
||||
if !isRef(a.key) || len(a.tail) == 0 {
|
||||
c.held[a.head] = true
|
||||
if !isRef(a.head) || len(a.tail) == 0 {
|
||||
c.heldLocal = true
|
||||
}
|
||||
if _, named := c.holder[a.key]; !named {
|
||||
c.holder[a.key] = label
|
||||
if _, named := c.holder[a.head]; !named {
|
||||
c.holder[a.head] = label
|
||||
}
|
||||
if len(a.tail) > 0 {
|
||||
if c.pathKeys == nil {
|
||||
c.pathKeys = map[string]string{}
|
||||
if c.pathHeads == nil {
|
||||
c.pathHeads = map[string]string{}
|
||||
}
|
||||
if _, named := c.pathKeys[a.key]; !named {
|
||||
c.pathKeys[a.key] = a.spelling
|
||||
if _, named := c.pathHeads[a.head]; !named {
|
||||
c.pathHeads[a.head] = a.spelling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ type renderEdge struct {
|
||||
operand string
|
||||
}
|
||||
|
||||
func (e renderEdge) readsRef() bool { return isRef(e.read.key) }
|
||||
func (e renderEdge) readsRef() bool { return isRef(e.read.head) }
|
||||
|
||||
// reached names an edge as the author spelled it.
|
||||
func (e renderEdge) reached() string {
|
||||
@@ -133,7 +133,7 @@ func renderEdges(n node) []renderEdge {
|
||||
case *template:
|
||||
var es []renderEdge
|
||||
add := func(a arm, operand string) {
|
||||
c := n.head(a.key)
|
||||
c := n.head(a.head)
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -41,7 +41,12 @@ type holdSet struct {
|
||||
type renderScope struct {
|
||||
set *holdSet
|
||||
group string
|
||||
row tablePin
|
||||
row renderedRow
|
||||
}
|
||||
|
||||
type renderedRow struct {
|
||||
t *table
|
||||
index int
|
||||
}
|
||||
|
||||
// in is the scope t renders in: its draw group where it names one, else its caller's.
|
||||
@@ -57,9 +62,9 @@ func (sc renderScope) in(t *template) renderScope {
|
||||
func (sc renderScope) at(n node, pins *pinSet) renderScope {
|
||||
switch n := n.(type) {
|
||||
case *tableRow:
|
||||
sc.row = tablePin{n.t, pins.mustRow(n.t)}
|
||||
sc.row = renderedRow{n.t, pins.mustRow(n.t)}
|
||||
case *tableColumn:
|
||||
sc.row = tablePin{n.t, pins.mustRow(n.t)}
|
||||
sc.row = renderedRow{n.t, pins.mustRow(n.t)}
|
||||
}
|
||||
return sc
|
||||
}
|
||||
@@ -69,7 +74,7 @@ func (sc renderScope) rowOf(t *table) int {
|
||||
if sc.row.t != t {
|
||||
panic(internalError("a column of %s renders in a scope holding no row of it", t.segment))
|
||||
}
|
||||
return sc.row.row
|
||||
return sc.row.index
|
||||
}
|
||||
|
||||
func (sc renderScope) groupHold() *groupHold {
|
||||
|
||||
+1
-1
@@ -761,7 +761,7 @@ func TestRepeatedBareTokenOfAHeldNameIsRejected(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReadFieldPanicsOnAPathItCannotHold(t *testing.T) {
|
||||
a := arm{spelling: "w.x", key: "w", tail: []string{"x"}, path: "w.x"}
|
||||
a := arm{spelling: "w.x", head: "w", tail: []string{"x"}, path: "w.x"}
|
||||
for name, format := range map[string]string{
|
||||
"unheld arm with a path": `{"format":"{w}","w":{"format":"{x}","x":"1"}}`,
|
||||
"held arm with no hold": `{"format":"{w.x}","w":{"format":"{x}","x":"1"}}`,
|
||||
|
||||
+19
-19
@@ -15,9 +15,9 @@ func heldCheck(path string, n node) error {
|
||||
if !ok || len(t.compiled.held) == 0 {
|
||||
return nil
|
||||
}
|
||||
readers := pathKeyReaders(t.compiled.ops, t.compiled.pathKeys)
|
||||
readers := pathHeadReaders(t.compiled.ops, t.compiled.pathHeads)
|
||||
for _, name := range heldNames(t) {
|
||||
if _, isPath := t.compiled.pathKeys[name]; isPath && isRef(name) {
|
||||
if _, isPath := t.compiled.pathHeads[name]; isPath && isRef(name) {
|
||||
continue // held for the render: drawFence compares every read of it, by path, across the render and its groups
|
||||
}
|
||||
if err := checkNameHeld(t, name, readers); err != nil {
|
||||
@@ -36,8 +36,8 @@ func heldNames(t *template) []string {
|
||||
names = append(names, name)
|
||||
}
|
||||
sort.Slice(names, func(i, j int) bool {
|
||||
_, pi := t.compiled.pathKeys[names[i]]
|
||||
_, pj := t.compiled.pathKeys[names[j]]
|
||||
_, pi := t.compiled.pathHeads[names[i]]
|
||||
_, pj := t.compiled.pathHeads[names[j]]
|
||||
if pi != pj {
|
||||
return !pi
|
||||
}
|
||||
@@ -51,12 +51,12 @@ func heldNames(t *template) []string {
|
||||
// produces.
|
||||
func heldNodes(t *template, name string, readers []reader) map[node]bool {
|
||||
held := map[node]bool{}
|
||||
if _, isPath := t.compiled.pathKeys[name]; !isPath {
|
||||
if _, isPath := t.compiled.pathHeads[name]; !isPath {
|
||||
operandDraw(t.head(name), held)
|
||||
return held
|
||||
}
|
||||
for _, r := range readers {
|
||||
if r.a.key == name {
|
||||
if r.a.head == name {
|
||||
coverPath(t.head(name), r.a.tail, held)
|
||||
}
|
||||
}
|
||||
@@ -71,10 +71,10 @@ func checkNameHeld(t *template, name string, readers []reader) error {
|
||||
if len(held) == 0 {
|
||||
return nil // a fixed head holds nothing to reach
|
||||
}
|
||||
reader, isPath := t.compiled.pathKeys[name]
|
||||
reader, isPath := t.compiled.pathHeads[name]
|
||||
seen := map[node]bool{}
|
||||
for _, e := range renderEdges(t) {
|
||||
if e.read.key == name || !renders(e.to, held, seen) {
|
||||
if e.read.head == name || !renders(e.to, held, seen) {
|
||||
continue
|
||||
}
|
||||
if isPath {
|
||||
@@ -89,7 +89,7 @@ func checkNameHeld(t *template, name string, readers []reader) error {
|
||||
func operandReader(t *template, name string) string {
|
||||
for _, o := range t.compiled.ops {
|
||||
for _, a := range o.operands {
|
||||
if a.key == name {
|
||||
if a.head == name {
|
||||
return o.fn
|
||||
}
|
||||
}
|
||||
@@ -175,8 +175,8 @@ func renders(n node, want, seen map[node]bool) bool {
|
||||
// disagree. Reads are compared in sorted order, so which pair is reported does not
|
||||
// depend on where the tokens sit.
|
||||
// docs/decisions.md#a-bare-reference-draws-each-time-a-reference-path-is-held
|
||||
func checkNoOverlap(ops []op, pathKeys map[string]string) error {
|
||||
names := pathKeyReaders(ops, pathKeys)
|
||||
func checkNoOverlap(ops []op, pathHeads map[string]string) error {
|
||||
names := pathHeadReaders(ops, pathHeads)
|
||||
// Stable over one format-order scan, so two readers of one name (a token and a
|
||||
// calc operand both naming "p") are reported as the format writes them.
|
||||
sort.SliceStable(names, func(i, j int) bool { return names[i].a.path < names[j].a.path })
|
||||
@@ -190,25 +190,25 @@ func checkNoOverlap(ops []op, pathKeys map[string]string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// reader is one way a format reaches a path key, and how to name it.
|
||||
// reader is one way a format reaches a path head, and how to name it.
|
||||
type reader struct {
|
||||
a arm
|
||||
label string
|
||||
}
|
||||
|
||||
// pathKeyReaders lists every way a format reaches a sibling path key, in the order the
|
||||
// pathHeadReaders lists every way a format reaches a sibling path head, in the order the
|
||||
// format writes them. An operand renders its field, so it names a level exactly
|
||||
// as a token does; one scan finds both, which is what puts them in one order.
|
||||
func pathKeyReaders(ops []op, pathKeys map[string]string) []reader {
|
||||
func pathHeadReaders(ops []op, pathHeads map[string]string) []reader {
|
||||
var names []reader
|
||||
for _, o := range ops {
|
||||
for _, a := range o.operands {
|
||||
if _, isPathKey := pathKeys[a.key]; isPathKey && !isRef(a.key) {
|
||||
if _, isPathHead := pathHeads[a.head]; isPathHead && !isRef(a.head) {
|
||||
names = append(names, reader{a, fmt.Sprintf("%s operand %q", o.fn, a.spelling)})
|
||||
}
|
||||
}
|
||||
for _, a := range o.arms {
|
||||
if _, isPathKey := pathKeys[a.key]; isPathKey && !isRef(a.key) {
|
||||
if _, isPathHead := pathHeads[a.head]; isPathHead && !isRef(a.head) {
|
||||
names = append(names, reader{a, "token {" + a.spelling + "}"})
|
||||
}
|
||||
}
|
||||
@@ -224,11 +224,11 @@ func checkNoRepeatedRead(c formatOps) error {
|
||||
count := map[string]int{}
|
||||
for _, o := range c.ops {
|
||||
for _, a := range o.arms {
|
||||
if len(a.tail) > 0 || !c.held[a.key] {
|
||||
if len(a.tail) > 0 || !c.held[a.head] {
|
||||
continue
|
||||
}
|
||||
if count[a.key]++; count[a.key] > 1 {
|
||||
return fmt.Errorf("token {%s} is repeated, and %s holds %q to one draw per expansion; write {%s} once", a.spelling, c.holder[a.key], a.key, a.spelling)
|
||||
if count[a.head]++; count[a.head] > 1 {
|
||||
return fmt.Errorf("token {%s} is repeated, and %s holds %q to one draw per expansion; write {%s} once", a.spelling, c.holder[a.head], a.head, a.spelling)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,12 +81,12 @@ type templateLink struct {
|
||||
|
||||
func (*template) isNode() {}
|
||||
|
||||
// head is the node an arm's key names: a sibling field, or a reference's category.
|
||||
func (t *template) head(key string) node {
|
||||
if isRef(key) {
|
||||
return t.link.refHeads[key]
|
||||
// head is the node an arm's head names: a sibling field, or a reference's category.
|
||||
func (t *template) head(name string) node {
|
||||
if isRef(name) {
|
||||
return t.link.refHeads[name]
|
||||
}
|
||||
return t.fields[key]
|
||||
return t.fields[name]
|
||||
}
|
||||
|
||||
// compile converts parsed JSON — a category or an inline template — into a node tree,
|
||||
@@ -229,7 +229,7 @@ func (t *template) fixedText() (string, bool) {
|
||||
// compiled reads.
|
||||
func compileFormat(toks []formatToken, refs map[string]refBinding) (formatOps, error) {
|
||||
c := compileOps(toks, refs)
|
||||
if err := checkNoOverlap(c.ops, c.pathKeys); err != nil {
|
||||
if err := checkNoOverlap(c.ops, c.pathHeads); err != nil {
|
||||
return c, err
|
||||
}
|
||||
return c, checkNoRepeatedRead(c)
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@ func (s *readSurvey) walk(n node, at surveyAt) {
|
||||
func (s *readSurvey) edge(from node, e renderEdge, at surveyAt) {
|
||||
if e.readsRef() {
|
||||
a := e.read
|
||||
tr := tableReadOf(from.(*template).head(a.key), a, e.to)
|
||||
tr := tableReadOf(from.(*template).head(a.head), a, e.to)
|
||||
if k := (readKey{at.group, a.path, s.pinsID(&at.pins), s.pinsID(&at.wholePins)}); !s.read[k] {
|
||||
s.read[k] = true
|
||||
s.reads = append(s.reads, pathRead{at, a, tr})
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ func wantGathered(t *testing.T, tables map[string]*table, label string, gathered
|
||||
}
|
||||
seen := map[traceKey]bool{}
|
||||
trace := func(group, table string, row int, a arm) {
|
||||
if !isRef(a.key) {
|
||||
if !isRef(a.head) {
|
||||
return
|
||||
}
|
||||
r := pathRead{at: surveyAt{group: group}, a: a}
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ func columnReadOf(t *template, link templateLink) *columnRead {
|
||||
return nil
|
||||
}
|
||||
a := splitArm(name, link.refs)
|
||||
target, isTemplate := link.refHeads[a.key].(*template)
|
||||
target, isTemplate := link.refHeads[a.head].(*template)
|
||||
if !isTemplate || !target.isRecord || len(a.tail) != 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func render(s *session, n node, sc renderScope) string {
|
||||
case *nullItem:
|
||||
return ""
|
||||
case *table:
|
||||
sc.row = tablePin{n, n.drawRow(s)}
|
||||
sc.row = renderedRow{n, n.drawRow(s)}
|
||||
return expand(s, n.formatTemplate, sc)
|
||||
case *tableRow:
|
||||
return expand(s, n.t.formatTemplate, sc)
|
||||
@@ -159,17 +159,17 @@ func expand(s *session, t *template, sc renderScope) string {
|
||||
// read one row, either read twice gives one value, and a shown operand is the operand
|
||||
// computed. Every other name is drawn afresh, so {word} {word} still draws twice.
|
||||
func readField(s *session, t *template, held *hold, sc renderScope, a arm) readValue {
|
||||
if isRef(a.key) && len(a.tail) > 0 {
|
||||
if isRef(a.head) && len(a.tail) > 0 {
|
||||
return readReference(s, t, sc, a)
|
||||
}
|
||||
if sc.set.trace != nil {
|
||||
traceRead(sc.set.trace, t, sc, a)
|
||||
}
|
||||
if !t.compiled.held[a.key] {
|
||||
if !t.compiled.held[a.head] {
|
||||
if len(a.tail) > 0 {
|
||||
panic(internalError("%q reads a path into %q, which the expansion does not hold", a.spelling, a.key))
|
||||
panic(internalError("%q reads a path into %q, which the expansion does not hold", a.spelling, a.head))
|
||||
}
|
||||
return readValue{text: render(s, t.head(a.key), sc)}
|
||||
return readValue{text: render(s, t.head(a.head), sc)}
|
||||
}
|
||||
if held == nil {
|
||||
panic(internalError("%q reads a name the expansion holds, with no hold to keep it in", a.spelling))
|
||||
@@ -191,7 +191,7 @@ func readHeld(s *session, t *template, held *hold, pins *pinSet, sc renderScope,
|
||||
if r, done := held.value[a.path]; done {
|
||||
return r
|
||||
}
|
||||
leaf := drawPath(t.head(a.key), a.tail, a.key, &pathDraw{s: s, held: held, pins: pins, a: &a})
|
||||
leaf := drawPath(t.head(a.head), a.tail, a.head, &pathDraw{s: s, held: held, pins: pins, a: &a})
|
||||
if pins != nil {
|
||||
sc = sc.at(leaf, pins)
|
||||
}
|
||||
|
||||
@@ -330,8 +330,8 @@ func (t *table) compileRowFormat(format string) error {
|
||||
}
|
||||
for _, name := range tok.names {
|
||||
a := splitArm(name, nil)
|
||||
if _, ok := t.col[a.key]; !ok && !isRef(a.key) && a.key != "" {
|
||||
return fmt.Errorf("format names no column %q of %s; the columns are %v", a.key, t.file, t.header)
|
||||
if _, ok := t.col[a.head]; !ok && !isRef(a.head) && a.head != "" {
|
||||
return fmt.Errorf("format names no column %q of %s; the columns are %v", a.head, t.file, t.header)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1063,7 +1063,7 @@ func TestProbeReportsTheTablesADrawPins(t *testing.T) {
|
||||
{"region[12].name", "region=region[12]"},
|
||||
} {
|
||||
a := splitArm(c.path, nil)
|
||||
head := f.root.children[a.key].(*table)
|
||||
head := f.root.children[a.head].(*table)
|
||||
tr := tableReadOf(head, a, nil)
|
||||
var sels []string
|
||||
for _, s := range tr.sels {
|
||||
@@ -1075,7 +1075,7 @@ func TestProbeReportsTheTablesADrawPins(t *testing.T) {
|
||||
probed, drawn := tr.pins, tr.drawn
|
||||
for i := 0; i < 20; i++ {
|
||||
var pins pinSet
|
||||
drawPath(head, a.tail, a.key, &pathDraw{s: f.rand, pins: &pins})
|
||||
drawPath(head, a.tail, a.head, &pathDraw{s: f.rand, pins: &pins})
|
||||
want := map[*table]bool{}
|
||||
pins.each(func(tbl *table, _ int) {
|
||||
if _, selected := probed.pinned(tbl); !selected {
|
||||
|
||||
@@ -28,9 +28,6 @@ ranking `readSurvey.walk` hardest and all seven the unit they would least modify
|
||||
|
||||
This round, in order:
|
||||
|
||||
- Rename `arm.key` to `head`, as `template.head` reads it, leaving `key` the table's key
|
||||
column; give `renderScope.row` a type that is not `tablePin`, since it pins nothing;
|
||||
and name `value.go` by the `valueProof` it holds.
|
||||
- Delete the prose the seats found empty: "kept whole on purpose"
|
||||
(`format.go`, `calc.go`), the second copy of the concrete-session rationale
|
||||
(`table.drawRow`, `pick`), the doc comments restating `isSelector`, `selectorOf`,
|
||||
|
||||
@@ -164,7 +164,7 @@ func (p *valueProof) proveTemplate(t *template) proven {
|
||||
case o.kind == nameRead:
|
||||
var leaves []node
|
||||
for _, a := range o.arms {
|
||||
leaves = append(leaves, pathLeaves(t.head(a.key), a.tail)...)
|
||||
leaves = append(leaves, pathLeaves(t.head(a.head), a.tail)...)
|
||||
}
|
||||
return p.proveUnion(leaves)
|
||||
case name == "calc":
|
||||
Reference in New Issue
Block a user