reval 0.10.2

Simple Rust expression evaluator
Documentation
use crate::{expr::{Expr, Index}, parse::rule::RuleBuilder, value::Value, parse::helpers::*};
use std::str::FromStr;

grammar;

extern {
    type Error = RevalParseError;
}

match {
    "=" => OP_EQ1,
    "==" => OP_EQ2,
    "!=" => OP_NEQ,
    ">" => OP_GT,
    "<" => OP_LT,
    ">=" => OP_GTE,
    "<=" => OP_LTE,
    "+" => OP_ADD,
    "-" => OP_SUB,
    "*" => OP_MULT,
    "/" => OP_DIV,
    "%" => OP_REM,
    "!" => OP_NOT,
    "&" => OP_BIT_AND,
    "|" => OP_BIT_OR,
    "^" => OP_BIT_XOR,
    "@" => OP_META,
    "and" => KWD_AND,
    "or" => KWD_OR,
    "if" => KWD_IF,
    "then" => KWD_THEN,
    "else" => KWD_ELSE,
    "is_some" => KWD_IS_SOME,
    "is_none" => KWD_IS_NONE,
    "none" => KWD_NONE,
    "some" => KWD_SOME,
    "int" => KWD_INT,
    "float" => KWD_FLOAT,
    "dec" => KWD_DEC,
    "contains" => KWD_CONTAINS,
    "in" => KWD_IN,
    "date_time" => KWD_DATE_TIME,
    "datetime" => KWD_DATETIME,
    "duration" => KWD_DURATION,
    "to_upper" => KWD_TO_UPPER,
    "to_lower" => KWD_TO_LOWER,
    "uppercase" => KWD_UPPERCASE,
    "lowercase" => KWD_LOWERCASE,
    "trim" => KWD_TRIM,
    "round" => KWD_ROUND,
    "floor" => KWD_FLOOR,
    "fract" => KWD_FRACT,
    "year" => KWD_YEAR,
    "month" => KWD_MONTH,
    "week" => KWD_WEEK,
    "day" => KWD_DAY,
    "hour" => KWD_HOUR,
    "minute" => KWD_MINUTE,
    "second" => KWD_SECOND,
    "starts" => KWD_STARTS,
    "ends" => KWD_ENDS,
    "," => COMMA,
    ":" => COLON,
    ";" => SEMICOLON,
    "." => DOT,
    "(" => LPAREN,
    ")" => RPAREN,
    "[" => LBRACKET,
    "]" => RBRACKET,
    "{" => LBRACE,
    "}" => RBRACE,
    r#""[^"\\]*(?:\\.[^"\\]*)*""# => STRING,
    r"i[+-]?[0-9]+" => INT,
    r"0x[0-9a-fA-F]+" => HEX_INT,
    r"0o[0-8]+" => OCT_INT,
    r"0b[01]+" => BIN_INT,
    r"f[+-]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?" => FLOAT,
    r"d[+-]?[0-9]*\.?[0-9]+" => DECIMAL,
    "true" => TRUE,
    "false" => FALSE,

    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 Rule: RuleBuilder = <m:(<MetaItem>)*> <e: Expr> =>? Ok(RuleBuilder::parse(m, e)?);

MetaItem: (String, Expr) = OP_META <k:IDENT> COLON <e:Expr> SEMICOLON => (k.to_string(), e);

pub Expr: Expr = IfExpr;

IfExpr: Expr = {
    KWD_IF <iif:IfExpr> KWD_THEN <thn:IfExpr> KWD_ELSE <els:IfExpr> => Expr::iif(iif, thn, els),
    LogExpr
}

LogExpr: Expr = {
    <l:LogExpr> KWD_AND <r:EqExpr> => Expr::and(l, r),
    <l:LogExpr> KWD_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:BitExpr> => Expr::mult(l, r),
    <l:MultExpr> OP_DIV <r:BitExpr> => Expr::div(l, r),
    <l:MultExpr> OP_REM <r:BitExpr> => Expr::rem(l, r),
    BitExpr
}

BitExpr: Expr = {
    <l:BitExpr> OP_BIT_AND <r:SubStringExpr> => Expr::bitwise_and(l, r),
    <l:BitExpr> OP_BIT_OR <r:SubStringExpr> => Expr::bitwise_or(l, r),
    <l:BitExpr> OP_BIT_XOR <r:SubStringExpr> => Expr::bitwise_xor(l, r),
    SubStringExpr
}

SubStringExpr: Expr = {
    <l:IndexExpr> KWD_CONTAINS <r:IndexExpr> => Expr::contains(l, r),
    <l:IndexExpr> KWD_IN <r:IndexExpr> => Expr::contains(r, l),
    <l:IndexExpr> KWD_STARTS <r:IndexExpr> => Expr::starts(l, r),
    <l:IndexExpr> KWD_ENDS <r:IndexExpr> => Expr::ends(l, r),

    UnaryExpr
}

UnaryExpr: Expr = {
    OP_SUB <e:UnaryExpr> => Expr::neg(e),
    OP_NOT <e:UnaryExpr> => Expr::not(e),
    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,
    Symbol,
    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_DATE_TIME LPAREN <e:Expr> RPAREN => Expr::datetime(e),
    KWD_DATETIME LPAREN <e:Expr> RPAREN => Expr::datetime(e),
    KWD_DURATION LPAREN <e:Expr> RPAREN => Expr::duration(e),
    KWD_IS_SOME LPAREN <e:Expr> RPAREN => Expr::some(e),
    KWD_IS_NONE LPAREN <e:Expr> RPAREN => Expr::none(e),
    KWD_SOME LPAREN <e:Expr> RPAREN => Expr::some(e),
    KWD_NONE LPAREN <e:Expr> RPAREN => Expr::none(e),
    KWD_TO_UPPER LPAREN <e:Expr> RPAREN => Expr::uppercase(e),
    KWD_TO_LOWER LPAREN <e:Expr> RPAREN => Expr::lowercase(e),
    KWD_UPPERCASE LPAREN <e:Expr> RPAREN => Expr::uppercase(e),
    KWD_LOWERCASE LPAREN <e:Expr> RPAREN => Expr::lowercase(e),
    KWD_TRIM LPAREN <e:Expr> RPAREN => Expr::trim(e),
    KWD_ROUND LPAREN <e:Expr> RPAREN => Expr::round(e),
    KWD_FLOOR LPAREN <e:Expr> RPAREN => Expr::floor(e),
    KWD_FRACT LPAREN <e:Expr> RPAREN => Expr::fract(e),
    KWD_YEAR LPAREN <e:Expr> RPAREN => Expr::year(e),
    KWD_MONTH LPAREN <e:Expr> RPAREN => Expr::month(e),
    KWD_WEEK LPAREN <e:Expr> RPAREN => Expr::week(e),
    KWD_DAY LPAREN <e:Expr> RPAREN => Expr::day(e),
    KWD_HOUR LPAREN <e:Expr> RPAREN => Expr::hour(e),
    KWD_MINUTE LPAREN <e:Expr> RPAREN => Expr::minute(e),
    KWD_SECOND LPAREN <e:Expr> RPAREN => Expr::second(e),
    <f:IDENT> LPAREN <e:Expr> RPAREN => Expr::func(f, e),
}

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

Symbol: Expr = COLON <s:IDENT> => Expr::symbol(s);

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,
    HexIntValue,
    OctIntValue,
    BinIntValue,
    FloatValue,
    DecimalValue,
    BoolValue,
    NoneValue,
};

StringValue: Value = <s:STRING> =>? Ok(parse_string_literal(s)?);
IntValue: Value = <s:INT> =>? Ok(parse_int_value(s)?);
HexIntValue: Value = <s:HEX_INT> =>? Ok(parse_hex_int_value(s)?);
OctIntValue: Value = <s:OCT_INT> =>? Ok(parse_oct_int_value(s)?);
BinIntValue: Value = <s:BIN_INT> =>? Ok(parse_bin_int_value(s)?);
FloatValue: Value = <s:FLOAT> =>? Ok(parse_float_value(s)?);
DecimalValue: Value = <s:DECIMAL> =>? Ok(parse_decimal_value(s)?);
BoolValue: Value = {
    TRUE => Value::Bool(true),
    FALSE => Value::Bool(false)
};
NoneValue: Value = KWD_NONE => Value::None;