Errors and diagnostics
A diagnostic in FormScript has a code, a severity and a place. The codes are stable, so a tool can be written against them, and a document that fails does not fail with "something went wrong".
E-TYPE-02 form.forms:4:18 the value of "amount" is a string, and the field declares a number
The code groups
| The code | What it means |
|---|---|
E-LEX |
lexical — the text itself |
E-SYN |
syntactic — the grammar |
E-SEM |
semantic — the meaning |
E-TYPE |
types |
E-BOUND |
bounds — a range that cannot be satisfied |
E-REF |
references — a name that does not resolve |
E-CONFLICT |
contradictions |
E-BLOCK |
block structure |
E-VAL |
values |
E-REL |
relations |
E-CYCLE |
cycles |
E-IO |
input and output |
E-VER |
the version |
E-EXT |
extensions |
E-EVAL |
evaluation |
E-STATE |
state |
Warnings start with W- instead of E-. The whole catalogue is in
the specification and on the command line:
npm run formscript -- errors
The order they come in
Diagnostics are reported in stage order, and only the earliest stage that produced any errors is reported at all:
- lexical
- syntactic
- semantic
- static type
- constraint
So a document with a typo in a name does not also report every downstream consequence of that typo. The lexical error comes first, it is the only one you see, and the semantic errors are suppressed — not discarded — so they appear once the first one is fixed.
Within one stage, errors come in document order.
Warnings are never suppressed. A warning is reported whenever it is produced, alongside the errors of whatever stage they are in.
Why this order
Because a person reading a diagnostic list wants the first thing that is wrong, not the last thing that is wrong. A form with a missing brace does not need to be told that six names are unresolved as well.
Reading a diagnostic
The reference implementation shows three things: the code, the place, and the sentence. The code is the part to write down in a tool; the place is the line and the column; the sentence says what is wrong in words.
The codes are worth learning by their group rather than one at a time:
E-LEX-*— the text is not text the language can read.E-SYN-*— the text is readable but not a valid document.E-SEM-*— the document is well-formed but means something impossible.E-TYPE-*— a type is wrong.E-REF-*— a name does not resolve, or two declarations collide.E-CONFLICT-*— two properties say contradictory things.E-BOUND-*— a range cannot be satisfied.E-VAL-*— a value is wrong at runtime.
Two errors worth meeting early
A duplicate declaration. Two things in the same scope with the same name:
// E-REF-02: two declarations of "draft" in one scope.
form applicant version = "1.0" {
field name { type = string }
state draft { page = "a" }
state draft { page = "b" }
}
The second draft is E-REF-02: two declarations in one scope.
A type that does not match.
// E-TYPE-02: the value is a string and the field declares a number.
form applicant version = "1.0" {
field amount { type = number value = "twelve" }
}
That is E-TYPE-02: the value of the field is a string, and the field
declares a number. The error names the property (value) and the declared
type.
Checking a document
npm run formscript -- lint form.forms
lint exits non-zero when a document has errors, so it drops straight into a
CI pipeline:
npm run formscript -- lint forms/*.forms || exit 1
To see everything rather than only the earliest stage:
npm run formscript -- lint --all form.forms
Errors at runtime
Some things can only be found when the form is filled in: a custom constraint that fails, a division by zero. Those are reported as validation failures and as the error value, not as diagnostics — the document is fine, the answers are not.
That is the difference between the two halves of the model:
- a diagnostic says the document is wrong;
- a validation failure says the answers are wrong.
The catalogue is normative
The catalogue of §14 is itself normative: an error code that is defined but never cited in the prose is still a code a runtime may report, and the specification lint says so — as a note, not as an error.
Every code is listed in the specification reference and on the command line. Nothing is hidden.