use super::*;
use std::str::FromStr;
use trylog::macros::*;
grammar;
Delimiter<T, D>: Vec<T> = {
<mut v:(<T> D)*> <e:T?> => match e {
None => v,
Some(e) => {
v.push(e);
v
}
}
};
pub Program: Program = Delimiter<Expr, ";"> => Program(<>);
Exprs: Vec<Expr> = Delimiter<Expr, ",">;
FuncName: (String, String) = {
<i:Id> => (String::default(), i),
<ns:Id> "." <name:Id> => (ns, name),
}
UnaryOp: UnaryOp = {
"+" => UnaryOp::Positive,
"-" => UnaryOp::Negative,
"!" => UnaryOp::Not,
}
// To make sure the full expr in parens.
FullExpr: Expr = Expr;
pub Expr: Expr = {
#[precedence(level="1")]
<r:Ref> => Expr::Ref(r),
<c:Const> => Expr::Const(c),
"(" <e:FullExpr> ")" => e,
<i:FuncName> "(" <a:Exprs> ")" => Expr::Call(i.0, i.1, a),
<o:UnaryOp> <e:Expr> => Expr::Unary(o, Box::new(e)),
#[precedence(level="2")]
#[assoc(side="left")]
<le:Expr> "*" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Mul), Box::new(re)),
#[assoc(side="left")]
<le:Expr> "/" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Div), Box::new(re)),
#[assoc(side="left")]
<le:Expr> "%" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Mod), Box::new(re)),
#[precedence(level="3")]
#[assoc(side="left")]
<le:Expr> "+" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Add), Box::new(re)),
#[assoc(side="left")]
<le:Expr> "-" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Minus), Box::new(re)),
#[precedence(level="4")]
#[assoc(side="left")]
<le:Expr> "<" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Lt), Box::new(re)),
#[assoc(side="left")]
<le:Expr> "<=" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Le), Box::new(re)),
#[assoc(side="left")]
<le:Expr> ">" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Gt), Box::new(re)),
#[assoc(side="left")]
<le:Expr> ">=" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Ge), Box::new(re)),
#[precedence(level="5")]
#[assoc(side="left")]
<le:Expr> "==" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Eq), Box::new(re)),
#[assoc(side="left")]
<le:Expr> "!=" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Neq), Box::new(re)),
#[precedence(level="6")]
#[assoc(side="left")]
<le:Expr> "&" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::And), Box::new(re)),
#[precedence(level="7")]
#[assoc(side="left")]
<le:Expr> "^" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Xor), Box::new(re)),
#[precedence(level="8")]
#[assoc(side="left")]
<le:Expr> "|" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Val(ValBinaryOp::Or), Box::new(re)),
#[precedence(level="9")]
#[assoc(side="left")]
<le:Expr> "&&" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::And), Box::new(re)),
#[precedence(level="10")]
#[assoc(side="left")]
<le:Expr> "||" <re:Expr> => Expr::Binary(Box::new(le), BinaryOp::Logic(LogicBinaryOp::Or), Box::new(re)),
#[precedence(level="11")]
#[assoc(side="left")]
<r:Ref> <o:AssignOp> <e:Expr> => Expr::Binary(Box::new(Expr::Ref(r)), o, Box::new(e)),
}
AssignOp: BinaryOp = {
"=" => BinaryOp::Assign,
"+=" => BinaryOp::Inplace(ValBinaryOp::Add),
"-=" => BinaryOp::Inplace(ValBinaryOp::Minus),
"*=" => BinaryOp::Inplace(ValBinaryOp::Mul),
"/=" => BinaryOp::Inplace(ValBinaryOp::Div),
"%=" => BinaryOp::Inplace(ValBinaryOp::Mod),
"&=" => BinaryOp::Inplace(ValBinaryOp::And),
"|=" => BinaryOp::Inplace(ValBinaryOp::Or),
"^=" => BinaryOp::Inplace(ValBinaryOp::Xor),
}
pub Ref: Ref = {
<i:Id> => Ref::Var(i),
"$" <i:Id> => Ref::Ctx(i),
"$?" => Ref::Ctx("?".to_string()),
"$" <i:Num> => Ref::Ctx(i.to_string()),
}
Id: String = <s:r"[A-Za-z]\w*"> => s.into();
pub Const: RawValue = {
"~" => RawValue::Unit,
"null" => RawValue::Unit,
<b:Bool> => RawValue::Bool(b),
<n:Num> => RawValue::Num(n),
<s:Str> => RawValue::Str(s),
}
Bool: bool = {
"true" => true,
"false" => false,
}
Num: i64 = <s:r"[0-9]+"> => unwrap_or_default_log!(i64::from_str(s), "Parse num error");
Str: String = <s:r##""[^"\\]*(\\.[^"\\]*)*""##> => s[1..s.len() - 1].into();