Precedence Table

Lowest precedence at the top. Operators on the same row associate left unless noted.

LevelOperatorsAssociativityNotes
1if … else …, try … else …rightTernary, try-else
2|, |>leftPipe (value-flow)
3??, ?|rightCoalesce
4orleftLogical OR (short-circuit)
5andleftLogical AND (short-circuit)
6notn/aLogical NOT (prefix)
7is, kind, is notn/aKind test
8hasleftMembership operator (no in — use .includes(v))
9==, !=, <, <=, >, >=, ~=leftComparison
10+, -leftAdditive (and string/array concat)
11*, /, %leftMultiplicative
12asleftCast
13- (unary)n/aNegation
14.field, .method(), [idx], {cond}, ?, !leftPostfix steps
15$, @, literal, (...), lambda, let, match, patch, compn/aPrimary

Common pitfalls

Pipe vs method call.

$.x | upper           # ✗ — interprets `upper` as a name to pipe into
$.x.upper()           # ✓ — method call

Comparison chains.

1 < x < 10            # ✗ — parses as `(1 < x) < 10`
1 < x and x < 10      # ✓

Ternary mid-chain.

$.x.upper() if cond else $.x   # parses fine — the ternary wraps the whole
                                # left expression

Negation tightness.

not a == b            # parses as `(not a) == b` — surprising!
not (a == b)          # parens are clearer
a != b                # cleanest

Coalesce + comparison.

$.x ?? 0 > 5          # parses as `($.x ?? 0) > 5` (low-precedence coalesce)

Try captures errors only.

try $.x.parse_int() else 0

try does not catch falsy-as-error — only actual evaluation errors (missing field, bad cast, regex failure, etc.).