// Config
WHITESPACE = _{ " " }
// Literals
true_lit = { "true" }
false_lit = { "false" }
bool = _{ true_lit | false_lit }
null = { "null" }
underscore = { "_" }
// Numbers
digit = _{ '0'..'9' }
positive_int = _{ digit ~ (digit | "_")* }
int = @{ positive_int }
plus = { "+" }
minus = { "-" }
exp = _{ ^"e" ~ (plus | minus)? ~ int }
float = @{ int ~ "." ~ positive_int? ~ exp? | int ~ exp }
// Strings
raw_single_quoted_string = { (!("\\" | "'") ~ ANY)+ }
raw_double_quoted_string = { (!("\\" | "\"") ~ ANY)+ }
// hex = { '0'..'9' | 'a'..'f' | 'A'..'F' }
// unicode_hex = { hex{1, 6} }
predefined = { "n" | "r" | "t" | "\\" | "\"" | "'" }
// byte = { "x" ~ hex{2} }
// unicode = { "u" ~ "{" ~ unicode_hex ~ "}" }
escape = { "\\" ~ predefined }
single_quoted_string = _{ "'" ~ (raw_single_quoted_string | escape)* ~ "'" }
double_quoted_string = _{ "\"" ~ (raw_double_quoted_string | escape | " ")* ~ "\"" }
string = ${ single_quoted_string | double_quoted_string }
// Regexes
raw_regex_string = { (!("\\" | "/") ~ ANY)+ }
escape_regex = { "\\" ~ ANY }
regex_flag = { "i" }
regex = { "/" ~ (raw_regex_string | escape_regex)* ~ "/" ~ (regex_flag)* }
// Identifiers
ident_char = _{ 'a'..'z' | 'A'..'Z' | '0'..'9' | "_" }
ident = @{ ASCII_ALPHA ~ ident_char* | "_" ~ ident_char+ }
// Operators
// NOTE: order IS important
binary_operator = _{
add
| sub
| pow
| mul
| idiv
| div
| rem
| num_eq
| num_ne
| num_le
| num_lt
| num_ge
| num_gt
| str_eq
| str_ne
| str_le
| str_lt
| str_ge
| str_gt
| concat
| in_op
| not_in
| and
| or
| pipe
}
num_eq = { "==" }
num_ne = { "!=" }
num_lt = { "<" }
num_le = { "<=" }
num_gt = { ">" }
num_ge = { ">=" }
str_eq = { "eq" }
str_ne = { "ne" }
str_lt = { "lt" }
str_le = { "le" }
str_gt = { "gt" }
str_ge = { "ge" }
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
idiv = { "//" }
rem = { "%" }
pow = { "**" }
concat = { "." }
pipe = { "|" }
and = { "&&" | "and" }
or = { "||" | "or" }
in_op = { "in" }
not_in = { "not in" }
unary_operator = _{ not | neg }
not = { "!" }
neg = { "-" }
// Functions
func = { ident ~ "(" ~ (expr ~ ","?)* ~ ")" }
// Expressions
expr = { unary_operator* ~ term ~ (binary_operator ~ term)* }
term = _{
func
| bool
| null
| regex
| string
| float
| int
| ident
| underscore
| "(" ~ expr ~ ")"
}
// End-chain parsers
full_expr = _{ SOI ~ expr ~ EOI }
expr_name = { ident | string }
named_expr = { expr ~ "as" ~ expr_name }
opt_named_expr = _{ named_expr | expr }
named_exprs = _{ SOI ~ opt_named_expr ~ ("," ~ opt_named_expr)* ~ EOI }
named_func = { func ~ "as" ~ expr_name }
opt_named_func = _{ named_func | func }
named_aggs = _{ SOI ~ opt_named_func ~ ("," ~ opt_named_func)* ~ EOI }
pipeline = _{ SOI ~ expr ~ ("|" ~ expr)* ~ EOI }