Supported expr-lang syntax#
Expressions support the full expr-lang feature set, including:
| Category | Examples |
|---|
| Arithmetic | +, -, *, /, %, ** |
| Array functions | filter(), map(), reduce(), sort(), sortBy(), reverse(), first(), last(), take(), flatten(), uniq(), concat(), join(), find(), findIndex(), findLast(), findLastIndex(), all(), any(), one(), none(), groupBy() |
| Bitwise | bitand(), bitor(), bitxor(), bitnand(), bitnot(), bitshl(), bitshr(), bitushr() |
| Comparison & logic | ==, !=, <, >, and, or, not |
| Conditionals | args[0] > 10 ? 'yes' : 'no', args[0] ?? 0 (nil coalescing), if/else |
| Language | let bindings, # predicates (current element in closures), len(), get() |
| Map functions | keys(), values() |
| Math functions | abs(), ceil(), floor(), round(), mean(), median() |
| Operators | | (pipe), in (membership), .. (range), [:] (slice), ?. (optional chaining) |
| String functions | upper(), lower(), trim(), trimPrefix(), trimSuffix(), split(), splitAfter(), replace(), repeat(), indexOf(), lastIndexOf(), hasPrefix(), hasSuffix() |
| String operators | contains, startsWith, endsWith, matches (regex) |
| Type conversion | int(), float(), string(), type(), toJSON(), fromJSON(), toBase64(), fromBase64(), toPairs(), fromPairs() |
Reference data#
These examples show expr-lang expressions used with edg’s reference data. Each expression can appear anywhere an edg expression is accepted (e.g. in args:, expressions:, or inline globals). Visit the Expressions example for a complete runnable demonstration.
The examples below assume the following in-memory reference data:
ref products [
{name: "Widget", category: "electronics", price: 29.99, stock: 150, active: true}
{name: "Gadget", category: "electronics", price: 49.99, stock: 80, active: true}
{name: "Notebook", category: "stationery", price: 4.99, stock: 500, active: true}
{name: "Pen", category: "stationery", price: 1.99, stock: 1000, active: true}
{name: "Cable", category: "electronics", price: 9.99, stock: 0, active: false}
]
ref regions [
{code: "us-east", zone: "us", cities: ["new_york", "boston", "miami"]}
{code: "eu-west", zone: "eu", cities: ["london", "paris", "dublin"]}
{code: "ap-south", zone: "ap", cities: ["mumbai", "singapore", "tokyo"]}
]
Arithmetic#
| Expression | Example output |
|---|
10 % 3
ref('products').stock % 7 | 1 -> 3 |
2 ** 8
len(ref_same('regions').cities) ** 3 | 256 -> 27 |
3 + 4 * 2
ref('products').price + ref('products').stock * 2 | 11 -> 329.99 |
Comparison & logic#
| Expression | Example output |
|---|
not (ref('products').category == 'stationery') | true |
ref('products').stock > 0 and ref('products').active | true |
Conditionals#
| Expression | Example output |
|---|
nil ?? 'unknown'
ref('products')?.description ?? 'none' | unknown -> none |
ref('products').stock > 0 ? 'in_stock' : 'sold_out' | in_stock |
Operators#
| Expression | Example output |
|---|
1..5
1..len(ref_same('regions').cities) + 1 | [1, 2, 3, 4] -> [1, 2, 3] |
ref('products')?.name | Widget |
ref('products').price | int | 29 |
ref_same('regions').cities[0:2] | [new_york, boston] |
ref_same('regions').zone in ['us', 'eu', 'ap'] | true |
Array functions#
| Expression | Example output |
|---|
all(ref_same('regions').cities, {len(#) > 3}) | true |
any(ref_same('regions').cities, {# == 'miami'}) | true |
concat(ref_same('regions').cities, ['london', 'paris']) | [new_york, boston, miami, london, paris] |
filter(ref_same('regions').cities, {# startsWith 'b'}) | [boston] |
find(ref_same('regions').cities, {# startsWith 'b'}) | boston |
findIndex(ref_same('regions').cities, {# startsWith 'b'}) | 1 |
findLast(ref_same('regions').cities, {# endsWith 'i'}) | miami |
findLastIndex(ref_same('regions').cities, {# endsWith 'i'}) | 2 |
first(ref_same('regions').cities) | new_york |
flatten([['new_york', 'boston'], ['london', 'paris']]) | [new_york, boston, london, paris] |
groupBy(ref_same('regions').cities, {len(#) > 5}) | {false: [miami, boston], true: [new_york]} |
join(ref_same('regions').cities, ', ') | new_york, boston, miami |
last(ref_same('regions').cities) | miami |
len(ref_same('regions').cities) | 3 |
map(ref_same('regions').cities, {upper(#)}) | [NEW_YORK, BOSTON, MIAMI] |
none(ref_same('regions').cities, {# == 'tokyo'}) | true |
one(ref_same('regions').cities, {# == 'miami'}) | true |
reduce([29.99, 49.99, 4.99, 1.99, 9.99], {#acc + #}, 0)
reduce(ref_same('regions').cities, {#acc + len(#)}, 0) | 96.95 -> 19 |
reverse(ref_same('regions').cities) | [miami, boston, new_york] |
sort(ref_same('regions').cities) | [boston, miami, new_york] |
sortBy(['Pen', 'Widget', 'Cable'], {len(#)})
sortBy(ref_same('regions').cities, {len(#)}) | [Pen, Cable, Widget]
[miami, boston, new_york] |
take(ref_same('regions').cities, 2) | [new_york, boston] |
uniq(['electronics', 'stationery', 'electronics'])
uniq(concat(ref_same('regions').cities, ref_same('regions').cities)) | [electronics, stationery] -> [new_york, boston, miami] |
Map functions#
| Expression | Example output |
|---|
keys(ref('products')) | [name, category, price, stock, active] |
values(ref('products')) | [Widget, electronics, 29.99, 150, true] |
Math functions#
| Expression | Example output |
|---|
abs(-7)
abs(ref('products').stock - 200) | 7 -> 50 |
ceil(3.2)
ceil(ref('products').price) | 4 -> 30 |
floor(ref('products').price) | 29 |
mean([29.99, 49.99, 4.99, 1.99, 9.99])
mean(map(ref_same('regions').cities, {len(#)})) | 19.39 -> 6.33 |
median([1.99, 4.99, 9.99, 29.99, 49.99])
median(map(ref_same('regions').cities, {len(#)})) | 9.99 -> 6 |
round(ref('products').price) | 30 |
Bitwise#
| Expression | Example output |
|---|
bitand(0b1100, 0b1010)
bitand(ref('products').stock, 0xFF) | 8 -> 150 |
bitnot(0b1100)
bitnot(ref('products').stock) | -13 -> -151 |
bitor(0b1100, 0b1010)
bitor(ref('products').stock, 1) | 14 -> 151 |
bitshl(1, 4)
bitshl(1, len(ref_same('regions').cities)) | 16 -> 8 |
bitshr(16, 4)
bitshr(ref('products').stock, 1) | 1 -> 75 |
bitxor(0b1100, 0b1010)
bitxor(ref('products').stock, 0xFF) | 6 -> 105 |
String functions#
| Expression | Example output |
|---|
hasPrefix(ref_same('regions').code, 'us') | true |
hasSuffix(ref_same('regions').code, 'east') | true |
indexOf('london', 'on')
indexOf(ref('products').category, 'c') | 1 -> 3 |
lastIndexOf('london', 'on')
lastIndexOf(ref('products').category, 'c') | 4 -> 9 |
lower(ref('products').category) | electronics |
repeat('*', 5)
repeat(ref_same('regions').zone, 3) | ***** -> ususus |
replace(ref_same('regions').code, '-', '_') | us_east |
split('new_york,boston,miami', ',')
split(ref_same('regions').code, '-') | [new_york, boston, miami] -> [us, east] |
splitAfter('us,eu,ap', ',')
splitAfter(ref_same('regions').code, '-') | [us,, eu,, ap] -> [us-, east] |
trim(' gadget ')
trim(ref('products').name) | gadget -> Widget |
trimPrefix(ref_same('regions').code, ref_same('regions').zone + '-') | east |
trimSuffix(ref_same('regions').code,
'-' + trimPrefix(ref_same('regions').code, ref_same('regions').zone + '-')) | us |
upper(ref('products').name) | WIDGET |
String operators#
| Expression | Example output |
|---|
ref('products').category contains 'electron' | true |
ref_same('regions').code endsWith 'east' | true |
ref_same('regions').code matches '[a-z]+-[a-z]+' | true |
ref_same('regions').code startsWith 'us' | true |
Type conversion#
| Expression | Example output |
|---|
float(ref('products').stock) | 150.0 |
fromBase64('V2lkZ2V0')
fromBase64(toBase64(ref('products').name)) | Widget -> Widget |
fromJSON('{"code":"us-east","zone":"us"}')
fromJSON('{"id":' + string(ref('products').stock) + '}') | {code: us-east, zone: us} -> {id: 150} |
fromPairs([['name', 'Widget'], ['price', 29.99]])
fromPairs([['product', ref('products').name],
['zone', ref_same('regions').zone]]) | {name: Widget, price: 29.99} -> {product: Widget, zone: us} |
int('42')
int(ref('products').price) | 42 -> 29 |
string(ref('products').price) | 29.99 |
toBase64(ref('products').name) | V2lkZ2V0 |
toJSON(ref('products')) | {"active":true,"category":"electronics","name":"Widget","price":29.99,"stock":150} |
toPairs({name: 'Widget', price: 29.99})
toPairs(ref('products')) | [[name, Widget], [price, 29.99]] -> [[active, true], [category, electronics], [name, Widget], [price, 29.99], [stock, 150]] |
type(ref('products').price) | float |
Advanced expressions#
These combine multiple functions and reference lookups for more complex use cases.
| Description | Expression | Example output |
|---|
| Chained array ops | join(take(sort(map(ref_same('regions').cities, {upper(#)})), 2), ', ') | BOSTON, MIAMI |
| Conditional formatting | let p = ref('products'); p.stock > 100 ? upper(p.name) : lower(p.name) | WIDGET |
| Conditional string ops | let r = ref_same('regions'); hasPrefix(r.code, 'us') ? upper(first(r.cities)) : lower(last(r.cities)) | NEW_YORK |
| Derived metric | let p = ref('products'); int(ceil(p.price * float(p.stock) / 100)) | 45 |
| Derived slug | let p = ref('products'); replace(lower(p.name + '_' + p.category), ' ', '_') | widget_electronics |
| Discount pricing | let p = ref('products'); p.active ? round(p.price * 0.9) : 0 | 27 |
| Filtered count | len(filter(ref_same('regions').cities, {len(#) > 5})) | 2 |
| JSON from refs | toJSON(fromPairs([['product', ref('products').name], ['zone', ref_same('regions').zone]])) | {"product":"Widget","zone":"us"} |
| Multi-condition classification | let p = ref('products'); p.price > 10 and p.stock > 0 ? 'premium' : (p.active ? 'basic' : 'discontinued') | premium |
| Reduce mapped values | reduce(map(ref_same('regions').cities, {len(#)}), {#acc + #}, 0) | 19 |
| Switch on env var | {'fra': 'eu-central-1', 'sin': 'ap-southeast-1', 'iad': 'us-east-1'}[env('FLY_REGION')] ?? fail('unknown FLY_REGION') | eu-central-1 |