FS FormScript

FormScript

A form is a program that asks questions. FormScript is the language those programs are written in — and, unusually, the language is defined by a document precise enough that an implementation can be checked against it rather than admired.

forms
form loan_application version = "1.0" {
  text {
    "loan.title": "Loan application"
    "loan.monthly": { "default": "Monthly payment", "ar": "القسط الشهري" }
  }

  field annual_income {
    type = number
    label = t("loan.income")
    validate { min = 0 }
  }

  field term {
    type = integer
    label = t("loan.term")
    value = 60
  }

  field monthly {
    type = number
    label = t("loan.monthly")
    value = pmt(0.05 / 12, term, annual_income)
  }

  output {
    annual_income: number
    term: integer
    monthly: number
  }
}

What the specification says, and what follows from it

Every decision in the reference implementation traces to a numbered statement in the specification. There are 312 of them, and each one is listed with its normative text in the specification reference.

That discipline has teeth. Five defects in the specification were found by building the implementation, and each was repaired in the document itself, with the repair recorded in the specification's own revision history — now 26 rows. Two examples:

  • The canonical decimal form was defined for a number only, so an integer had no defined text on the wire. Two conforming runtimes could have serialised 36 as 36 or "36". The specification now says which.
  • A choice was defined as "a field whose type is enum" while the property table separately listed options and optionsFrom for it — so a choice could declare a string type, and there were two overlapping ways to state a choice set. The specification now has one.

The language in one paragraph

A form is a form block. It holds fields, groups, repeats, choices, sections and pages. A field declares a type — string, number, integer, boolean, date, datetime, duration, enum, array, object — and may declare a value, a default, a label, constraints under validate, and a guard under when. A section and a page are presentation only: they introduce neither a scope nor a data level, so a field inside section address is addressed as address.

Expressions are total. There is no undefined and no exception: an operation that cannot succeed returns the error value, and a field that has never been answered holds unknown. Logic is three-valued — true, false, and unknown — so a question whose answer is not yet known does not silently become a "no".

The numbers

Packages 21, one concern each, no cycles
Specification statements 312, all listed in the reference
Unit tests 776 over 21 files
Conformance rows executed 101, all five sections of §18
Error codes 78, every one with a stable identity
Builtins 67, checked against §6.4 at build time
Conformance level 3 of 5 — the declaration, and its evidence

Everything runs in your browser

This site is not a mock-up. The playground loads the reference implementation itself — the same lexer, parser, analyser and engine that the conformance suite runs — compiled from this repository to JavaScript and loaded as a native ES module. Type a form, and it is lexed, parsed, analysed and executed in the page.

What you see is what the specification prescribes: the diagnostics carry their codes, the stage order of §2.5 decides which of them you are shown, and the output document is the one §4.33 describes.

Where to go next