number = @{ int ~ ("." ~ ASCII_DIGIT*)? }
int = { ("+" | "-")? ~ ASCII_DIGIT+ }
string_double_quote = ${ "\"" ~ str_inner_double ~ "\"" }
str_inner_double = @{ char_double* }
char_double = { !("\"") ~ ANY
| "\"" ~ ( "\"") }
string_single_quote = ${ "\'" ~ str_inner_single ~ "\'" }
str_inner_single = @{ char_single* }
char_single = { !("\'") ~ ANY }
string_constant = ${ str_inner_constant }
str_inner_constant = @{ char_constant* }
char_constant = { "\'" ~ ("=")
|!("=") ~ ANY }
operator = _{ arithmetic_operator | string_operator | logical_operator }
arithmetic_operator = _{ add | subtract | multiply | divide | power }
add = { "+" }
subtract = { "-" }
multiply = { "*" }
divide = { "/" }
power = { "^" }
string_operator = _{ concat }
concat = { "&" }
logical_operator = _{ equal | not_equal | greater_or_equal | greater
| less_or_equal | less }
equal = { "=" }
not_equal = { "<>"}
greater = { ">" }
less = { "<" }
greater_or_equal= { ">=" }
less_or_equal = { "<=" }
function = _{ abs | sum | product | average | negate | days | right | left | iff | isblank | custom_function }
abs = { "ABS" ~ "(" ~ expr ~ ")" }
sum = { "SUM" ~ function_param_with_atomic_expr}
product = { "PRODUCT" ~ function_param_with_atomic_expr}
average = { "AVERAGE" ~ function_param_with_atomic_expr}
negate = { "-" ~ (function_param | iterator | reference) }
days = { "DAYS" ~ function_param }
right = { "RIGHT" ~ function_param }
left = { "LEFT" ~ function_param }
iff = { "IF" ~ three_params }
isblank = { "ISBLANK" ~ function_param}
custom_function = { reference ~ (function_param | empty_param) }
logical_function = _{ or | and | xor | not }
or = { "OR" ~ function_param_with_atomic_expr }
and = { "AND" ~ function_param_with_atomic_expr }
xor = { "XOR" ~ function_param_with_atomic_expr }
not = { "NOT" ~ "(" ~ expr ~ ")" }
function_param = _{ "(" ~ expr ~ ("," ~ expr)*? ~ ")" }
empty_param = { "(" ~ ")" }
function_param_with_atomic_expr = _{ "(" ~ param_inner? ~ param_with_blank*? ~ ")" }
three_params = _{
"(" ~ ")" |
"(" ~ first_param ~ param ~ param ~ ")" }
atomic_expr = ${ expr }
param_inner = _{ atomic_expr | expr}
first_param = { param_inner? }
param = { ","? ~ param_inner? }
param_with_blank = _{ param1 | blank }
blank = {","}
param1 = {"," ~ param_inner}
boolean = _{ t | f }
t = { ( "T" | "t") ~ ( "R" | "r") ~ ( "U" | "u") ~ ( "E" | "e") }
f = { ( "F" | "f") ~ ( "A" | "a") ~ ( "L" | "l") ~ ( "S" | "s") ~ ( "E" | "e") }
reference = @{ (ASCII_ALPHA | "_" | "\\") ~ char_reference* }
char_reference = { ASCII_ALPHANUMERIC | "." | "_" }
iterator = { "{" ~ expr ~ ("," ~ expr)*? ~ "}" }
expr = { term ~ (operator ~ term)* }
term = _{ number | "(" ~ expr ~ ")" | string_double_quote
| string_single_quote | logical_function | function | boolean | reference | iterator }
term_constant = _{ string_constant }
formula = _{ SOI ~ "=" ~ expr ~ EOI | SOI ~ term_constant ~ EOI }
WHITESPACE = _{ " " }