use syn::{BinOp, Expr, ExprBinary, ExprMethodCall, ExprParen, ExprPath, ExprUnary, Lit};
use super::{Operator, Output, Reflect, Value};
impl<'a> Reflect<'a> {
pub(super) fn visit_expr(&mut self, e: &'a Expr) {
use syn::Expr::*;
match e {
Binary(i) => self.visit_expr_binary(i),
Lit(i) => self.visit_lit(&i.lit),
MethodCall(i) => self.visit_expr_method_call(i),
Paren(i) => self.visit_expr_paren(i),
Path(i) => self.visit_expr_path(i),
Unary(i) => self.visit_expr_unary(i),
_ => self.on_err = true,
}
}
#[inline]
fn visit_bin_op(&mut self, b: &'a BinOp) {
use syn::BinOp::*;
match *b {
Add(_) => self.push_op(Operator::Add),
Sub(_) => self.push_op(Operator::Sub),
Mul(_) => self.push_op(Operator::Mul),
Div(_) => self.push_op(Operator::Div),
Rem(_) => self.push_op(Operator::Rem),
_ => self.on_err = true,
}
}
#[inline]
fn visit_expr_binary(
&mut self,
ExprBinary {
left, op, right, ..
}: &'a ExprBinary,
) {
self.visit_expr(left);
self.visit_bin_op(op);
self.visit_expr(right);
}
#[inline]
fn visit_expr_method_call(
&mut self,
ExprMethodCall {
receiver,
method,
args,
..
}: &'a ExprMethodCall,
) {
self.push_op(Operator::ParenLeft);
self.visit_expr(receiver);
self.push_op(Operator::ParenRight);
let method: &str = "e!(#method).to_string();
use super::function::Fun::*;
let method = match method {
"abs" => Abs,
"acos" => Acos,
"acosh" => Acosh,
"asin" => Asin,
"asinh" => Asinh,
"atan" => Atan,
"atan2" => Atan2,
"atanh" => Atanh,
"cbrt" => Cbrt,
"ceil" => Ceil,
"cos" => Cos,
"cosh" => Cosh,
"exp" => Exp,
"exp2" => Exp2,
"exp_m1" => ExpM1,
"floor" => Floor,
"fract" => Fract,
"hypot" => Hypot,
"ln" => Ln,
"ln_1p" => Ln1p,
"log" => Log,
"log10" => Log10,
"log2" => Log2,
"max" => Max,
"min" => Min,
"powf" => PowF,
"powi" => PowI,
"recip" => Recip,
"round" => Round,
"signum" => Signum,
"sin" => Sin,
"sinh" => Sinh,
"sqrt" => Sqrt,
"tan" => Tan,
"tanh" => Tanh,
"to_degrees" => ToDegrees,
"to_radians" => ToRadians,
"trunc" => Trunc,
_ => return self.on_err = true,
};
if method.arg() {
if args.len() != 1 {
return self.on_err = true;
}
self.push_op(Operator::ParenLeft);
self.visit_expr(&args[0]);
self.push_op(Operator::ParenRight);
self.output.push(Output::Fn(method));
} else {
if !args.is_empty() {
return self.on_err = true;
}
self.output.push(Output::Fn(method));
}
}
#[inline]
fn visit_expr_paren(&mut self, ExprParen { expr, .. }: &'a ExprParen) {
self.push_op(Operator::ParenLeft);
self.visit_expr(expr);
self.push_op(Operator::ParenRight);
}
#[inline]
fn visit_expr_path(&mut self, ExprPath { path, .. }: &'a ExprPath) {
let path: &str = "e!(#path).to_string();
if let Some(src) = self.ctx.get(&path) {
self.push_op(Operator::ParenLeft);
self.visit_expr(src);
self.push_op(Operator::ParenRight);
} else {
self.on_err = true;
}
}
#[inline]
fn visit_expr_unary(&mut self, ExprUnary { op, expr, .. }: &'a ExprUnary) {
self.visit_expr(expr);
use syn::UnOp::*;
match op {
Neg(_) => {
self.push_op(Operator::Neg);
}
_ => return self.on_err = true,
}
}
#[inline]
fn visit_lit(&mut self, l: &'a Lit) {
use super::Output::V;
use syn::Lit::*;
match l {
Int(a) => self.output.push(V(a.value() as Value)),
Float(a) => self.output.push(V(a.value() as Value)),
_ => self.on_err = true,
}
}
}