xlformula_engine 0.1.18

A tool to parse and evaluate Excel formulas
Documentation
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 = _{ " "  }