GameBus expression language
Complete syntax reference for the GameBus expression language.
GameBus expression language is used for transforming data and evaluating conditions. It's designed to be readable by non-programmers while powerful enough for complex business logic.
GameBus expression language is a port of the GoRules ZEN expression language.
Two modes
GameBus operates in two modes depending on context:
| Mode | Used in | Example |
|---|---|---|
| Standard | Expression nodes, output columns | price * quantity * (1 - discount) |
| Unary test | Decision table input columns | >= 100, [1..10], 'US', 'CA' |
Standard mode
Full expressions that return values.
Literals
// Numbers
42
3.14
-17
1e6
// Strings
"hello world"
'single quotes work too'
`template with ${variables}`
// Booleans
true
false
// Null
null
// Arrays
[1, 2, 3]
["a", "b", "c"]
// Objects
{ name: "John", age: 30 }
{ [dynamicKey]: value }Operators
Arithmetic
| Operator | Description | Example |
|---|---|---|
+ | Addition | 5 + 3 → 8 |
- | Subtraction | 10 - 4 → 6 |
* | Multiplication | 6 * 7 → 42 |
/ | Division | 15 / 3 → 5 |
% | Modulo | 17 % 5 → 2 |
^ | Power | 2 ^ 10 → 1024 |
Comparison
| Operator | Description | Example |
|---|---|---|
== | Equal | x == 5 |
!= | Not equal | x != 0 |
> | Greater than | x > 10 |
< | Less than | x < 100 |
>= | Greater or equal | x >= 18 |
<= | Less or equal | x <= 65 |
Logical
| Operator | Description | Example |
|---|---|---|
and | Logical AND | a and b |
or | Logical OR | a or b |
not | Logical NOT | not a |
Ternary
condition ? valueIfTrue : valueIfFalse
score >= 70 ? "pass" : "fail"
age >= 18 ? "adult" : age >= 13 ? "teen" : "child"Null coalescing
Returns the first non-null value:
user.nickname ?? user.name ?? "Anonymous"Range check
// Inclusive range
x in [1..10] // true if 1 <= x <= 10
// Exclusive range
x in (0..100) // true if 0 < x < 100
// Mixed
x in [0..100) // true if 0 <= x < 100
x in (0..100] // true if 0 < x <= 100
// Negation
x not in [1..10]Property access
// Object properties
customer.name
customer.address.city
// Array indexing
items[0]
items[0].price
// Nested access
order.items[0].product.nameTemplate strings
`Hello, ${name}!`
`Total: ${sum(items)} items`
`Status: ${approved ? 'Approved' : 'Pending'}`String slicing
Extract substrings using [start:end] notation:
string[0:5] // Characters 0-4 (first 5)
string[7:12] // Characters 7-11
string[7:] // From index 7 to end
string[:5] // First 5 characters (0-4)| Expression | Input | Result |
|---|---|---|
string[0:5] | "sample_string" | "sampl" |
string[7:] | "sample_string" | "string" |
string[:6] | "sample_string" | "sample" |
Unary test mode
Shorthand syntax used in decision table input columns when a field name is defined. The value being tested is implicitly available, allowing you to write conditions without repeating the field name.
When an input column has no field name, standard expression mode is used instead.
Comparisons
> 100 // Greater than 100
< 50 // Less than 50
>= 18 // Greater or equal to 18
<= 65 // Less or equal to 65
== "active" // Equal to "active"
!= 0 // Not equal to 0Ranges
[1..100] // Between 1 and 100 (inclusive)
(0..100) // Between 0 and 100 (exclusive)
[18..65) // 18 to 64
(0..100] // 1 to 100Lists
'US', 'CA', 'GB' // Match any of these strings
1, 2, 3, 5, 8 // Match any of these numbers
"pending", "processing" // Match any of theseCombined conditions
> 0 and < 100 // Between 0 and 100
>= 18 and <= 65 // Working age
< 0 or > 100 // Outside 0-100Functions in unary mode
startsWith($, "PRE-") // String starts with prefix
contains($, "urgent") // String contains substring
len($) > 5 // Length greater than 5The $ symbol represents the value being tested.
Closures and iteration
The # symbol represents the current element when iterating:
map([1, 2, 3], # * 2) // [2, 4, 6]
map(items, #.price * #.quantity) // [totals...]
filter([1, 2, 3, 4, 5], # > 3) // [4, 5]
some([1, 2, 3], # > 2) // true
all([1, 2, 3], # > 0) // trueNamed aliases
For readability, use as to name the current element:
map(cart.items as item, item.price * item.quantity)
filter(users as user, user.isActive and user.age >= 18)
some(orders as order, order.status == 'pending')This is equivalent to using # but clearer when expressions are complex.
Assignment
Create values and build objects within expressions.
Basic assignment
a = 5 // {"a": 5}
name = 'John' // {"name": "John"}
items = [1, 2, 3] // {"items": [1, 2, 3]}
config = {debug: true} // {"config": {"debug": true}}Property assignment
Assign to nested paths — intermediate objects are created automatically:
user.name = 'Alice' // {"user": {"name": "Alice"}}
user.profile.bio = 'Developer' // {"user": {"profile": {"bio": "Developer"}}}
app.config.database.host = 'localhost' // Creates full nested structureMultiple assignments
Separate with semicolons:
a = 1; b = 2 // {"a": 1, "b": 2}
user.name = 'Charlie'; user.age = 35 // {"user": {"name": "Charlie", "age": 35}}Assignment with expressions
counter = counter + 1 // Increment existing value
total = price * quantity // Compute from input
fullName = firstName + ' ' + lastName // String concatenation
doubled = map(numbers, # * 2) // Array operations
status = score > 70 ? 'pass' : 'fail' // ConditionalReturning values
The last expression determines the return value:
a = 5; b = 10; a + b // Returns 15
user.name = 'Eve'; user.name // Returns "Eve"
config.debug = true; config // Returns {"debug": true}
config.debug = true; $root // Returns {"config": {"debug": true}}Use $root to return the entire context object.