# Expression Language
Elex expressions are strings that combine literals, variables, operators, and
function calls. This page describes the language syntax and semantics.
## Literals
### Numbers
Decimal numbers use standard notation. Unary minus is supported:
```elixir
Elex.evaluate("42", context) # #Decimal<42>
Elex.evaluate("3.14", context) # #Decimal<3.14>
Elex.evaluate("-5.5", context) # #Decimal<-5.5>
Elex.evaluate("-(1 + 2)", context) # #Decimal<-3>
```
All arithmetic is performed with `Decimal` for precision.
### Booleans
```elixir
Elex.evaluate("true", context)
Elex.evaluate("false", context)
Elex.evaluate("yes", context) # alias for true
Elex.evaluate("no", context) # alias for false
```
### Strings
Strings are double-quoted. Use `\"` to escape a quote inside a string:
```elixir
Elex.evaluate(~s["hello"], context)
Elex.evaluate(~s["say \"hi\""], context)
```
### Null
The `null` literal represents an empty or missing value:
```elixir
Elex.evaluate("null", context) # nil
```
`null` compares equal only to `null` or `nil` variables. It cannot be compared
to numbers, booleans, or strings with `<`, `>`, etc.
## Variables
Variable names start with a lowercase letter and may contain letters, digits, and
underscores (`price`, `tax_rate`, `item2`).
The words `and`, `or`, `not`, `null`, `true`, `false`, `yes`, and `no` are
reserved and cannot be used as variable names.
Variables must be present in the evaluation context (with a known type) before
an expression can be validated or evaluated.
## Operators
### Precedence (lowest to highest)
| Level | Operators |
|-------|-----------|
| 1 | `or` |
| 2 | `and` |
| 3 | `==`, `!=`, `<`, `>`, `<=`, `>=` |
| 4 | `+`, `-` (binary) |
| 5 | `*`, `/`, `%` |
| 6 | `not` (unary) |
| 7 | `-` (unary minus) |
Parentheses override precedence: `(1 + 2) * 3`.
### Arithmetic
`+`, `-`, `*`, `/`, and `%` require decimal operands and return a decimal.
The `%` operator is remainder (sign follows the dividend), same as `rem(a, b)`.
For floored modulo, use the `mod(a, b)` function instead.
### Comparisons
Comparison operators return a boolean. Operands must have the same type:
- **Decimals** — numeric ordering
- **Strings** — lexicographic ordering
- **Booleans** — `true`/`false` ordering
- **Null** — equality (`==`, `!=`) only
```elixir
{:ok, true} = Elex.evaluate("10 > 5", context)
{:ok, true} = Elex.evaluate(~s["a" < "b"], context)
{:ok, true} = Elex.evaluate("null == null", context)
```
### Logical operators
`and`, `or`, and `not` require boolean operands and return a boolean.
`and`, `or`, and `if(condition, a, b)` use **short-circuit evaluation**: the
right-hand operand (or unselected branch) is skipped when it cannot change the
result. This prevents errors in guard-style expressions:
```elixir
{:ok, false} = Elex.evaluate("false and (1 / 0 > 0)", context)
{:ok, true} = Elex.evaluate("true or (1 / 0 > 0)", context)
{:ok, result} = Elex.evaluate("if(false, 1 / 0, 2)", context) # #Decimal<2>
```
## Type system
Elex performs static type checking during parsing (by default). Each sub-expression
has a type; operators and functions enforce compatibility before evaluation.
| Type | Description | Example values |
|------|-------------|----------------|
| `:decimal` | Numbers | `#Decimal<3.14>` |
| `:boolean` | True/false | `true`, `false` |
| `:string` | Text | `"hello"` |
| `nil` | Null | `null`, nil variables |
Type errors are reported as human-readable strings, for example:
```
'+' operator can not be used on number and text
```
## Function calls
Functions use familiar call syntax: `name(arg1, arg2)`. See the
[Functions](functions.md) reference for the full list.
`min`, `max`, and `coalesce` are variadic — they accept two or more arguments.
`pi()` takes no arguments.
## Limits
- **Nesting depth** — By default, parenthesis/function-call nesting deeper than
16 levels is rejected. Override with the `:max_depth` option on
`Elex.Parser.parse/3`.
- **Reserved words** — `and`, `or`, `not`, `null`, `true`, `false`, `yes`, and
`no` cannot be variable names.
## Further reading
- [Functions](functions.md) — built-in function reference
- [Advanced Topics](advanced.md) — working with the AST directly