Syntax¶
This section captures common syntactic forms in FuncScript’s JSON-superset language. Each construct can be combined with others so long as the overall value remains JSON-compatible.
Infix expressions¶
Operators support infix usage, including arithmetic and logical comparisons:
{ total: 42 + 8; isLarge: total > 40 }
Keyword helpers such as in, or, and and behave like symbolic infix operators, so expressions
like value in [1, 2, 3] or flag1 and flag2 read naturally. Negation uses the unary - operator,
for example -balance.
List expression¶
Lists use JSON square-bracket syntax and can embed expressions for elements:
{ values: [1, 2, 1 + 3] }
Key value collection expression¶
Records are written with braces. Values can be literals or expressions. When the entire expression is just a record, the outer braces are optional; the parser treats the top-level bindings as part of the same key/value collection either way:
{ gross: 5200; rate: 0.13; net: gross * (1 - rate) }
Equivalent to:
gross: 5200;
rate: 0.13;
net: gross * (1 - rate)
Strings & Templates¶
Triple-quoted strings keep verbatim newlines and quotes, which is convenient for large blocks of text:
{
prose: """
Dear team,
The build succeeded.
Thanks!
"""
}
Note that the line break after the opening """ and before the closing """ are ignored. The example expression evaluates as:
Dear team,
The build succeeded.
Thanks!
Standard 'single' and "double" literals remain available, and string templates still use the f"..." prefix to embed expressions.
Function expressions¶
Lambda-style functions use the (parameters) => body syntax. They can appear anywhere a value is expected, including inside key/value pairs:
{
f: (x) => x * x + 2;
helper: (y) => f(y) + 4;
result: helper(3);
}
Functions are values themselves—store them in a variable, pass them to higher‑order helpers, or return them from other functions. Use key/value collections (see next section) when you need the block itself to evaluate to a different expression.
Key value collection with eval expression¶
Key/value collections normally evaluate to an object containing every binding. Marking one binding with eval turns the entire block into a special form that evaluates to that expression instead of the surrounding record. The eval directive can appear anywhere in the block—the evaluation engine starts from that expression, resolves only the referenced bindings (regardless of order), and ignores irrelevant ones. The older return keyword still works for backwards compatibility but is slated for deprecation, so prefer eval in new code:
{
eval net;
gross: 5200;
rate: 0.13;
net: gross * (1 - rate);
}
Evaluating the block above produces:
4524
because execution stops at the returned expression and only the bindings required to compute net are evaluated.
Record Selection¶
Selectors can also project a subset of keys from a record. List the fields you want inside braces immediately after the record value:
{
person: { name: "Ada"; age: 42; city: "London" };
summary: person { name; city }
}
In the example above, summary evaluates to { name: "Ada", city: "London" }.
Comments¶
Use either // inline or /* multi-line */ comments anywhere whitespace is permitted:
{
subtotal: 42;
total: subtotal + 8; // sales tax
final: total /* currency already normalized */
}
If expression¶
Conditional logic uses explicit keywords:
{
discount: 0.1;
total: 1250;
final: if discount > 0 then total * (1 - discount) else total;
}
Case expression¶
Use the case keyword with condition: value pairs. Commas or semicolons separate additional arms.
{
day: "mon";
label: case day = "mon": "start", day = "fri": "finish", true: "midweek";
}
Switch expression¶
Switches evaluate condition: value arms in order. Provide a true: value branch for the default.
{
status: "processing";
message: switch status,
"new": "Queued",
"processing": "Working",
true: "Unknown";
}