Expressions
An expression reads values and produces a value. That is all it does.
form loan version = "1.0" {
field amount { type = number }
field term { type = integer }
field monthly { type = number value = pmt(0.05 / 12, term, amount) }
field interest { type = number value = amount * 0.05 }
field label { type = string value = "Repay " + toString(monthly) + " a month" }
}
Every expression returns a value
This is the single most important fact about expressions in FormScript, and it is different from most languages. There are no exceptions.
field a { type = number value = 1 / 0 }
field b { type = string value = "abc" + 1 }
field c { type = string value = substring("hello", -1) }
None of those three is an error in the program. Each of them produces a value — the specification calls it the error value — and the field that holds it is invalid. The document still runs; the transaction simply does not commit.
So there is no try, no catch, and no way to write a program that stops
halfway. A form that cannot be answered is a form that says so.
The operators
| Operator | What it does |
|---|---|
+ |
adds numbers, or joins strings |
- * / % |
arithmetic; / always gives a number |
== != |
equality |
< <= > >= |
ordering |
and or ! |
logic, and it is three-valued |
in |
is this value in that list |
notIn |
is this value not in that list |
matches |
does this string match that pattern |
is between |
is this value between those two |
?? |
the first operand that is not absent |
? : |
a conditional |
Arithmetic
field total { type = number value = price * quantity }
field share { type = number value = total / count }
field remainder{ type = integer value = total % 3 }
/ always produces a number, even when both operands are integers: 6 / 2
is 3.0, a number, not an integer. That is deliberate — division that
sometimes gives an integer and sometimes a decimal is a bug waiting to happen.
Strings
+ joins strings. It does not convert anything:
field greeting { type = string value = "Hello, " + name }
field count { type = string value = "You have " + toString(len(items)) + " items" }
"Hello, " + 36 is an error value, because a string and a number do not
agree. You ask for the conversion: toString(36).
Comparison and logic
field adult { type = boolean value = age >= 18 }
field affordable{ type = boolean value = income > 10000 and credit == "good" }
field missing { type = boolean value = not (first_name == "") }
and, or and ! are three-valued, which is the next
section.
Lists and patterns
field in_gb { type = boolean value = country in ["GB", "IE", "FR"] }
field adult { type = boolean value = age is between 18 and 65 }
field looks_ok{ type = boolean value = postcode matches "^[A-Z]{2}[0-9]{2}$" }
is between is sugar for age >= 18 and age <= 65.
Choosing
field band { type = string value = income > 100000 ? "high" : "standard" }
? : is a conditional expression: if the condition is true, the first
branch; if it is false, the second. What if it is unknown? Then the
condition is not true and not false, and the specification says exactly
what happens — section 6 covers it.
Falling back
field name_or_blank { type = string value = name ?? "" }
?? yields its left operand unless that operand is absent, in which case it
yields the right one. It is the one operator that treats absence as a thing
you can ask about.
Reading an expression
The reference is a path: a name, or a name and a path into it.
field a { type = string value = name }
field b { type = string value = address.street }
field c { type = string value = applicant.address.city }
The rules for a dotted path are in the specification (Spec-6.20): a dotted
path names a field when the form has such a field, and is a member access on
the value it starts at otherwise. In a document with a field
address.street, the path address.street is that field.
There are also the $ names, which come from outside the form:
| The name | What it is |
|---|---|
$form.output |
the output document |
$form.valid |
whether the form is valid |
$now |
the timestamp of the current transaction |
$this |
the current element inside a comprehension |
$env |
the environment the runtime was given |
$this is the one you will meet in section 8.