//! Grammar for the expression parser.
WHITESPACE = _{ " " | "\t" | NEWLINE }
COMMENT = _{ block_comment | line_comment }
block_comment = _{ "/*" ~ (!"*/" ~ ANY)* ~ "*/" } // TODO: nesting? PUSH/POP should handle it
line_comment = _{ "//" ~ (!NEWLINE ~ ANY)* }
input = _{ SOI ~ expr ~ EOI }
expr = { prefix_op* ~ term ~ postfix* ~ (infix_op ~ prefix_op* ~ term ~ postfix*)* }
//
// Operators
//
prefix_op = _{ neg | not }
neg = { "-" }
not = { "!" }
infix_op = _{ logic_op | cmp_op | arith_op }
logic_op = _{ and | or }
and = { "&&" }
or = { "||" }
cmp_op = _{ eq | not_eq | less | less_eq | greater | greater_eq }
eq = { "==" }
not_eq = { "!=" }
less = { "<" }
less_eq = { "<=" }
greater = { ">" }
greater_eq = { ">=" }
arith_op = _{ add | sub | mul | div | pow }
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
pow = { "^" }
//
// Term
//
term = _{ literal | ident | #glam = vector | "(" ~ expr ~ ")" } // order matters
literal = _{ bool | float | int | symbol } // order matters
bool = { true | false }
true = _{ "true" }
false = _{ "false" }
int = @{ (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT+ | ASCII_DIGIT) } // TODO: different bases
float = @{ int ~ (mantissa ~ exponent? | exponent) } // e.g. "1.2", "4.3e2", "5.", "6e3"
// TODO: consider disallowing "1.e12", even though Rust understand it as float, as it would
// allow member access to literal int values; but is there a use case for this?
mantissa = { "." ~ ASCII_DIGIT* }
exponent = { ^"e" ~ ("+"|"-")? ~ int }
symbol = ${ "@" ~ ident }
ident = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
vector = { "[" ~ expr? ~ ("," ~ expr)* ~ "]" }
//
// Suffixes
//
postfix = _{ call | subscript | access }
call = { "(" ~ (expr ~ ("," ~ expr)*)? ~ ")" }
subscript = { "[" ~ expr ~ "]" }
access = { "." ~ ident }