Program = _{ SOI ~ Expression ~ EOF }
// Expressions
// An expression is a sequence of operands connected by unary or binary operators.
// The AST will only have expression groups for expressions that must be evaluated.
// Values and Variables are exposed directly.
// Binary operators can be chained, thus binary expressions can be arbitrarily long.
UnaryExpression = { UnaryOperator ~ UnaryOperand }
BinaryExpression = { (BinaryOperand ~ BinaryOperator)+ ~ BinaryOperand }
Expression = _{ BinaryExpression | UnaryExpression | UnaryOperand }
UnaryOperand = _{ Atom | "(" ~ Expression ~ ")" }
BinaryOperand = _{ UnaryExpression | UnaryOperand }
// Operators
UnaryOperator = _{ WhiteSpace? ~ (Not | Add | Sub) ~ WhiteSpace? }
BinaryOperator = _{ WhiteSpace? ~ (Add | Sub | Mul | Div | And | Or | Eq | Neq | Leq | Lt | Geq | Gt) ~ WhiteSpace? }
Not = { "not" }
Add = { "+" }
Sub = { "-" }
Mul = { "*" }
Div = { "/" }
And = { "and" }
Or = { "or" }
Eq = { "==" }
Neq = { "!=" }
Leq = { "<=" }
Lt = { "<" }
Geq = { ">=" }
Gt = { ">" }
// Strings
UnsafeStringChar = _{ "\"" | "(" | ")" | NEWLINE }
NonQuoteWhitespaceChar = _{ !(UnsafeStringChar | WhiteSpace) ~ ANY }
NonQuoteNewlineChar = _{ !UnsafeStringChar ~ ANY }
UnquotedString = { !UnaryOperator ~ NonQuoteWhitespaceChar+ }
String = @{ NonQuoteNewlineChar* }
QuotedString = { "\"" ~ String ~ "\"" }
// Values
Number = { (Add | Sub)? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? }
Bool = { "true" | "false" }
Value = _{ Number | Bool | QuotedString | UnquotedString }
// Variables
VariableRef = _{ "$" ~ Variable }
Variable = ${ UnquotedString }
Atom = _{ QuotedString | VariableRef | Value }
// Override builtins
WhiteSpace = _{ " " | "\t" }
EOF = _{ EOI | ";" }