FS FormScript

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".

text
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:

bash
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:

  1. lexical
  2. syntactic
  3. semantic
  4. static type
  5. 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:

forms-invalid
// 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.

forms-invalid
// 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

bash
npm run formscript -- lint form.forms

lint exits non-zero when a document has errors, so it drops straight into a CI pipeline:

bash
npm run formscript -- lint forms/*.forms || exit 1

To see everything rather than only the earliest stage:

bash
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.