reval 0.7.4

Simple Rust expression evaluator
Documentation
use crate::{expr::{Expr, Index}, value::Value};
use rust_decimal::Decimal; 
use std::str::FromStr;

grammar;

match {
    "=" => OP_EQ1,
    "==" => OP_EQ2,
    "!=" => OP_NEQ,
    ">" => OP_GT,
    "<" => OP_LT,
    ">=" => OP_GTE,
    "<=" => OP_LTE,
    "+" => OP_ADD,
    "-" => OP_SUB,
    "*" => OP_MULT,
    "/" => OP_DIV,
    "!" => OP_NOT,
    "and" => OP_AND,
    "or" => OP_OR,
    "if" => IF_KWD,
    "then" => THEN_KWD,
    "else" => ELSE_KWD,
    "is_some" => KWD_IS_SOME,
    "is_none" => KWD_IS_NONE,
    "int" => KWD_INT,
    "float" => KWD_FLOAT,
    "dec" => KWD_DEC,
    "contains" => KWD_CONTAINS,
    "to_upper" => KWD_TO_UPPER,
    "to_lower" => KWD_TO_LOWER,
    "in" => KWD_IN,
    "," => COMMA,
    ":" => COLON,
    "." => DOT,
    "(" => LPAREN,
    ")" => RPAREN,
    "[" => LBRACKET,
    "]" => RBRACKET,
    "{" => LBRACE,
    "}" => RBRACE,
    r#""[^"\\]*(?:\\.[^"\\]*)*""# => STRING,
    r"i[+-]?[0-9]+" => INT,
    r"f[+-]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?" => FLOAT,
    r"d[+-]?[0-9]*\.?[0-9]+" => DECIMAL,
    "true" => TRUE,
    "false" => FALSE,
    "none" => NONE,

    r"\s*" => { }, // The default whitespace skipping is disabled if an `ignore pattern` is specified
    r"//[^\n\r]*[\n\r]*" => { }, // Skip `// comments`
}
else {
    r"[a-zA-Z][_a-zA-Z0-9]*" => IDENT,
    r"[0-9]+" => INDEX,
}

pub Expr: Expr = IfExpr;

IfExpr: Expr = {
    IF_KWD <iif:LogExpr> THEN_KWD <thn:LogExpr> ELSE_KWD <els:LogExpr> => Expr::iif(iif, thn, els),
    LogExpr
}

LogExpr: Expr = {
    <l:LogExpr> OP_AND <r:EqExpr> => Expr::and(l, r),
    <l:LogExpr> OP_OR <r:EqExpr> => Expr::or(l, r),
    EqExpr
}

EqExpr: Expr = {
    <l:EqExpr> OP_EQ1 <r:AddExpr> => Expr::eq(l, r),
    <l:EqExpr> OP_EQ2 <r:AddExpr> => Expr::eq(l, r),
    <l:EqExpr> OP_NEQ <r:AddExpr> => Expr::neq(l, r),
    <l:EqExpr> OP_GT <r:AddExpr> => Expr::gt(l, r),
    <l:EqExpr> OP_LT <r:AddExpr> => Expr::lt(l, r),
    <l:EqExpr> OP_GTE <r:AddExpr> => Expr::gte(l, r),
    <l:EqExpr> OP_LTE <r:AddExpr> => Expr::lte(l, r),
    AddExpr
}

AddExpr: Expr = {
    <l:AddExpr> OP_ADD <r:MultExpr> => Expr::add(l, r),
    <l:AddExpr> OP_SUB <r:MultExpr> => Expr::sub(l, r),
    MultExpr
}

MultExpr: Expr = {
    <l:MultExpr> OP_MULT <r:ContainsExpr> => Expr::mult(l, r),
    <l:MultExpr> OP_DIV <r:ContainsExpr> => Expr::div(l, r),
    ContainsExpr
}

ContainsExpr: Expr = {
    <l:IndexExpr> KWD_CONTAINS <r:IndexExpr> => Expr::contains(l, r),
    <l:IndexExpr> KWD_IN <r:IndexExpr> => Expr::contains(r, l),
    IndexExpr
}

IndexExpr: Expr = {
    <l:IndexExpr> DOT <r:IDENT> => Expr::index(l, Index::from(r)),
    <l:IndexExpr> DOT <r:INDEX> => Expr::index(l, Index::from(usize::from_str(r).unwrap())),
    Term
}

Term: Expr = {
    Func,
    Ref,
    VecExpr,
    MapExpr,
    Value => Expr::Value(<>),
    LPAREN <Expr> RPAREN
};

Func: Expr = {
    KWD_INT LPAREN <e:Expr> RPAREN => Expr::int(e),
    KWD_FLOAT LPAREN <e:Expr> RPAREN => Expr::float(e),
    KWD_DEC LPAREN <e:Expr> RPAREN => Expr::dec(e),
    KWD_IS_SOME LPAREN <e:Expr> RPAREN => Expr::is_some(e),
    KWD_IS_NONE LPAREN <e:Expr> RPAREN => Expr::is_none(e),
    OP_SUB LPAREN <e:Expr> RPAREN => Expr::neg(e),
    OP_NOT LPAREN <e:Expr> RPAREN => Expr::not(e),
    KWD_TO_UPPER LPAREN <e:Expr> RPAREN => Expr::to_upper(e),
    KWD_TO_LOWER LPAREN <e:Expr> RPAREN => Expr::to_lower(e),
    <f:IDENT> LPAREN <e:Expr> RPAREN => Expr::func(f, e),
}

Ref: Expr = <s:IDENT> => Expr::reff(<>);

VecExpr: Expr = LBRACKET <e0:(<Expr> COMMA)*> <e1:Expr?> RBRACKET => Expr::Vec(e0.into_iter().chain(e1).collect());

MapExpr: Expr = LBRACE <kv0:(<MapItem> COMMA)*> <kv1:MapItem?> RBRACE => Expr::Map(kv0.into_iter().chain(kv1).collect());
MapItem: (String, Expr) = <k:IDENT> COLON <e:Expr> => (k.to_string(), e);

Value: Value = {
    StringValue,
    IntValue,
    FloatValue,
    DecimalValue,
    BoolValue,
    NoneValue,
};

StringValue: Value = <s:STRING> => Value::sanitize_string(s);
IntValue: Value = <s:INT> => Value::Int(i128::from_str(&s[1..]).unwrap());
FloatValue: Value = <s:FLOAT> => Value::Float(f64::from_str(&s[1..]).unwrap());
DecimalValue: Value = <s:DECIMAL> => Value::Decimal(Decimal::from_str(&s[1..]).unwrap());
BoolValue: Value = {
    TRUE => Value::Bool(true),
    FALSE => Value::Bool(false)
};


NoneValue: Value = NONE => Value::None;