diff --git a/datatype.go b/datatype.go index b8f4610..028cb65 100644 --- a/datatype.go +++ b/datatype.go @@ -157,37 +157,27 @@ func columnItems(n node) (items []*template, nullable bool) { return items, nullable } -// disagreement names the fix for two items of one column holding different datatypes. +// disagreement names the fix for two items of one column holding different datatypes. The item to +// fix declares none, and is text where the other reads a typed column. func disagreement(a *template, da DataType, b *template, db DataType) error { - bare, typed, want := b, a, da - if da == DataTypeString { - bare, typed, want = a, b, db + fix, has, other, want := a, da, b, db + if da != DataTypeString && (a.datatype != DataTypeString || db == DataTypeString) { + fix, has, other, want = b, db, a, da } + proven := (&valueProof{}).proveColumnItem(fix).not[want] == "" switch { - case da != DataTypeString && db != DataTypeString: - return bothTyped(a, da, b, db) - case typed.datatype == DataTypeString && (&valueProof{}).proveColumnItem(bare).not[want] != "": - return fmt.Errorf(`item %q is not %s, the datatype item %q takes from the column it reads; to read that column as text, %s`, bare.format, dataTypeNouns[want], typed.format, asText(typed)) - case bare.fromString: // an object may carry a weight, which this spelling would drop - return fmt.Errorf(`item %q declares no datatype, and a column holds one; write it as {"format":%q,"datatype":%q}`, bare.format, bare.format, want) - } - return fmt.Errorf(`item %q declares no datatype beside one holding %s; a column holds one, so give it "datatype": %q`, bare.format, want, want) -} - -// bothTyped names the fix for two items holding different datatypes: the one taking its datatype -// from the column it reads is typed as the other where its values prove it, else read as text. -func bothTyped(a *template, da DataType, b *template, db DataType) error { - read, other := a, db - if a.datatype != DataTypeString { - read, other = b, da - } - switch { - case read.datatype != DataTypeString: + case fix.datatype != DataTypeString: return fmt.Errorf("its items hold %s and %s; a column holds one datatype", da, db) - case (&valueProof{}).proveColumnItem(read).not[other] == "": - return fmt.Errorf("its items hold %s and %s; a column holds one datatype, so %s", da, db, typedAs(read, other)) + case has != DataTypeString && proven: + return fmt.Errorf("its items hold %s and %s; a column holds one datatype, so %s", da, db, typedAs(fix, want)) + case has != DataTypeString: + return fmt.Errorf("its items hold %s and %s; a column holds one datatype, so to read %q as text, %s", da, db, fix.format, asText(fix)) + case other.datatype == DataTypeString && !proven: + return fmt.Errorf(`item %q is not %s, the datatype item %q takes from the column it reads; to read that column as text, %s`, fix.format, dataTypeNouns[want], other.format, asText(other)) + case fix.fromString: // an object may carry a weight, which this spelling would drop + return fmt.Errorf(`item %q declares no datatype, and a column holds one; write it as {"format":%q,"datatype":%q}`, fix.format, fix.format, want) } - return fmt.Errorf("its items hold %s and %s; a column holds one datatype, so to read %q as text, %s", da, db, read.format, asText(read)) + return fmt.Errorf(`item %q declares no datatype beside one holding %s; a column holds one, so give it "datatype": %q`, fix.format, want, want) } // typedAs names the spelling giving a column-read item datatype d, keeping the other keys an object diff --git a/todo.md b/todo.md index e9e2783..0a08c1e 100644 --- a/todo.md +++ b/todo.md @@ -21,8 +21,6 @@ Self-sufficiency 5.6), every seat capped by Locality, and all nine naming This round, in order: -- Make `disagreement` and `bothTyped` a table of cases: each swaps its operands and - runs a proof to pick an error's wording. - Derive a column's datatype in one place: `columnItems` yields nothing for a `tableColumn`, and six callers re-derive it from items. - Give `head`, `index`, `bound` and `draw` one meaning each, name `table.family`