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;