Grammar Overview
The jetro DSL is a small, expression-oriented language. There are no statements at the top level — every program is an expression that produces a value (or, in the case of patches, a rewritten document).
The grammar lives in
grammar.pest
and is parsed by pest.
Five things that make jetro different
- Method calls use dot syntax.
xs.map(f), notxs | map(f). - Pipe
|is value-flow.x | exprevaluatesexprwith@bound tox. @is the current value. Inside.filter(...)it's the row; at the top level it's the input.- Bare paths inside method args.
.filter(@.age > 18)is sugar for.filter(@.age > 18). - Writes are queries.
$.x.set(v)is parsed as a query that produces a patched document, not a mutation.
Categories of syntax
| Category | Forms | Chapter |
|---|---|---|
| Paths | $, @, .field, [idx], [*], [start:end:step], ..desc, {pred} | Paths |
| Operators | arithmetic, comparison, logical, pipe, coalesce, ternary, kind, cast | Operators |
| Methods | .name(args), lambdas (@, =>, lambda) | Lambdas |
| Literals | numbers, strings, f-strings, arrays, objects, regex | Literals |
| Control flow | match, ternary, try, comprehensions | Control Flow |
| Writes | patch $ {…}, chain-write terminals | Patch |
A handy precedence table sits at the end of this part.
A worked sample
$.users
.filter(u => u.active and u.age >= 18)
.map(u => { id: u.id, name: u.name, email: u.email })
.sort(@.name)
.take(10)
That's: root, field users, predicate filter (named lambda), object-mapping,
sort by name, take first 10.
Comments
There are no comments inside a query. Strip them client-side before calling jetro, or factor commentary into the surrounding host program.
Whitespace
Whitespace and newlines are insignificant between tokens. Keep queries on one line in CLIs; break across multiple lines in source.