Expressions#
The top-level expression grammar is singleExpression. Operators are parsed by precedence, from low-precedence pipelines down to primary expressions.
Operator precedence#
From lower to higher precedence:
| Area | Syntax |
|---|---|
| Pipeline | value |> next |
| Raise expression | raise expr |
| Assignment | =, *=, +=, -=, /=, %= |
| Business operations | copy to, copy from, duplicate, transform, where, select, groupby, sort_by, take, skip, flat_map, find, fold, reduce, any, all, each |
| Conditional | condition ? yes : no |
| Cast | value as Type |
| Null coalescing | a ?? b |
| Logical | and, or, &&, || |
| Equality | ==, equal, equals, != |
| Null checks | is null, is not null, is null or empty |
| Relational | <, <=, >, >=, in, not in, contains, matches |
| Range | a..b, a...b |
| Arithmetic | +, -, *, /, %, ** |
| Prefix/postfix | not x, !x, await x, ++x, x++ |
Primary expressions#
Primary expressions include owner references, identifiers, literals, parenthesized expression sequences, object and array forms, lambdas, switch/when expressions, validation calls, HTTP requests, navigation calls, and query expressions.
this
state
(amount, currency)Object, array, and construction forms#
let vendor = new Vendor(vendor_id_param);
let draft = new Vendor { name: "Acme" };
let values = [1, 2, ...more_values];
let names = [item.name for item in items where item.active];
let payload = {
name: vendor.name,
["external-id"]: vendor.external_id,
...extra_payload
};Object literal properties can use qualified names, string literals, numeric literals, computed literal or identifier keys in [] or (), and ...identifier spreads. Typed object literals support qualified property names, [expression] computed keys, and ...expression spreads. Array comprehensions use [expr for name in source] with an optional where filter.
Member access and calls#
customer.name
customer?.address
items[0]
service.call(arg)
object.method<Customer>(value)Call arguments can be positional, labeled, spread with ...expr, or *.
Lambdas#
(x, y) -> x + y
x => x.total
function (x: integer) {
return x;
}Lambda bodies can be expressions or block statements.
Switch and when expressions#
let label = switch (status) {
case "open" -> "Open",
case "closed" -> "Closed",
default -> "Unknown"
};
let review = switch (status) {
case "held" when amount > 1000 -> "review",
default -> "normal"
};
let size = when {
amount > 1000 -> "large",
else -> "normal",
};Query expressions#
Business Language also supports LINQ-style query expressions:
let open_invoice_ids =
from invoice in invoices
where invoice.open_amount > 0
orderby invoice.due_date ascending
select invoice.invoice_id;Joins are supported:
let invoice_vendor_rows =
from invoice in invoices
join vendor in vendors on invoice.vendor_id == vendor.vendor_id
select new { invoice: invoice.invoice_id, vendor: vendor.vendor_name };Query expressions can use where, orderby, groupby, and join clauses. Query bodies can be combined with union, intersect, or except, each optionally followed by all. Parenthesized query subqueries may start with select or with.
let invoice_ids =
from invoice in open_invoices select invoice.invoice_id
union all
from invoice in held_invoices select invoice.invoice_id;Validation and HTTP expressions#
validate PostingPolicy(invoice)
get IntegrationClient "/vendors" {
company: company_code_param
}
post "/vendors" payloadHTTP expression methods are get, post, put, delete, patch, head, and options. The target service is optional when the path expression is provided directly.
Navigation expressions#
navigate VendorForm(vendor_id_param)Use navigation expressions for UI-driven transitions rather than encoding route strings in business logic.