Skip to main content

Operators and precedence

esque uses a Pratt parser with explicit precedence numbers. The following table is the canonical list, sorted from loosest to tightest binding. Higher number = tighter binding.

Infix table

PrecOperatorsAssociativityGroup
1|>leftpipeline
5||leftlogical or
6&&leftlogical and
10== != < <= > >=non-associativecomparison
15.. ..=non-associativerange
20+ - .+ .-leftadditive
30* / % .* ./ .%leftmultiplicative
35@leftmatrix multiply
40(function call, indexing, casts)leftpostfix

|> is the loosest infix operator — it binds looser than every arithmetic, logical, and comparison operator, so x + 1 |> f parses as (x + 1) |> f and x |> f && y parses as (x |> f) && y.

Prefix operators

OperatorEffect
-Numeric negation
!Logical not
+/Reduction by + (sum)
-/Reduction by - (left fold)
*/Reduction by * (product)
//Reduction by / (left fold)

<op>/ is read as the prefix reduction operator; the op part is any binary operator the element type defines. +/ and */ are commutative and may lower to a SIMD horizontal reduce; -/ and // are non-commutative, fold strictly left-to-right (-/[a,b,c] = (a - b) - c), and lower as scalar chains so that floating-point rounding matches the surface expression.

Because // is the divide-reduction operator, line comments use # (see Lexical structure).

Postfix forms

  • Function call: f(args)
  • Cast: e as T

There is no postfix ?, no postfix !, no field access (yet — no record types).

Examples by precedence

a + b * c # a + (b * c)
a .* b .+ c # (a .* b) .+ c
0..n + 1 # 0..(n + 1) (.. is precedence 15, + is 20)
a < b && c < d # (a < b) && (c < d)
x |> f |> g # g(f(x)) (left-assoc)
x as i32 + 1 # (x as i32) + 1

Notes on element-wise vs scalar

.+, .-, .*, ./, .% exist only as tensor element-wise operators. They cannot be used on scalars.

+, -, *, /, % exist only on scalars (and shape arithmetic inside type-position expressions).

The @ matrix-multiply operator is parsed but not yet codegened.