FS FormScript

Syntax

Every FormScript document has the same skeleton. Once you can read one, you can read all of them.

The version line

forms
form hello version = "1.0" {
  field name { type = string }
}

A document has exactly one form block, and it declares the version of the language it is written in. The version is not decoration: a runtime that does not implement that MAJOR version rejects the document with E-VER-01 rather than guessing what you meant. "1.0" is the version this specification describes.

Blocks

A block is a keyword, a name, and a body in braces:

form    hello  version = "1.0" { … }
field   name   { … }
group   applicant { … }
repeat  dependants { … }
choice  employment { … }
section identity { … }
page    "applicant" { … }

The keyword says what kind of thing it is, the name says which one it is, and the body says what it holds. A form holds fields; a group holds fields and other groups; a validate block holds constraints.

Properties

Inside a block, a line like type = string is a property: it says one thing about the thing being declared.

forms-fragment
field annual_income {
  type = string
  label = "Annual income"
  hint = "Before tax"
}

The name of the property is on the left, the value on the right. The value can be a literal ("Before tax"), an expression (name or 1 + 2), or another block.

Separators are optional. A newline ends a property. Where the layout gets tight, a semicolon does the same job:

forms-fragment
field address {
  type = string
  label = "Street"
}

is the same document as

forms-fragment
field address { type = string; label = "Street" }

The examples on this site use the first style, because it reads better.

Names

A name is letters, digits and underscores, and it starts with a letter or an underscore. Names are case-sensitive: email and Email are two names, and a form that uses both is a form with two different fields.

Names are also how you refer to things. A field's name is visible in the block that declares it and in the blocks inside it:

forms
form household version = "1.0" {
  group address {
    field street { type = string }
    field city   { type = string }
  }

  field label {
    type = string
    value = address.street + ", " + address.city
  }
}

address.street is a dotted path: it names the member street of the group address. The specification is precise about what a dotted path means (Spec-6.20): it names a field when the form has such a field, and is a member access on a value otherwise. In this document there is a field address.street, so the path is that field, and the value of the path is the answer to that field.

Strings

A string is in double quotes. There is no escape character other than the one you would expect: \" for a quote, \\ for a backslash, \n for a newline.

forms-fragment
field note {
  type = string
  label = "Note"
  default = "He said \"hello\""
}

Text that belongs to a person is a label, and it belongs in a text block rather than inline — that is section 14.

Comments

// runs to the end of the line.

forms
form hello version = "1.0" {
  // The only question.
  field name { type = string }
}

What a document can hold

Besides the form block, a document may hold:

  • namespace blocks — qualified names for one form's vocabulary;
  • text blocks — the labels and messages, in every language;
  • import and include directives — other documents;
  • source blocks — where remote data comes from;
  • action blocks — what the form does when it is submitted.

You will not need most of them for a first form. The next section is about the one thing every form needs: fields.