yfelo 0.1.1

the Yfelo template engine
Documentation
use super::{RuntimeError, Value};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
    Not,
    Pos,
    Neg,
}

impl UnaryOp {
    pub fn from(input: &str) -> Self {
        match input {
            "!" => Self::Not,
            "+" => Self::Pos,
            "-" => Self::Neg,
            _ => unreachable!(),
        }
    }

    pub fn eval(&self, value: Value) -> Result<Value, RuntimeError> {
        Ok(match self {
            Self::Not => Value::Bool(!value.as_bool()?),
            Self::Pos => Value::Number(value.as_number()?),
            Self::Neg => Value::Number(-value.as_number()?),
        })
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
    Pow,
    Mul, Div, Mod,
    Add, Sub,
    Shl, Shr,
    Lt, Le, Gt, Ge,
    Eq, Ne,
    BitAnd,
    BitXor,
    BitOr,
    And,
    Or,
}

impl BinaryOp {
    pub fn from(input: &str) -> Self {
        match input {
            "**" => Self::Pow,
            "*" => Self::Mul,
            "/" => Self::Div,
            "%" => Self::Mod,
            "+" => Self::Add,
            "-" => Self::Sub,
            "<<" => Self::Shl,
            ">>" => Self::Shr,
            "<" => Self::Lt,
            "<=" => Self::Le,
            ">" => Self::Gt,
            ">=" => Self::Ge,
            "==" => Self::Eq,
            "!=" => Self::Ne,
            "&" => Self::BitAnd,
            "^" => Self::BitXor,
            "|" => Self::BitOr,
            "&&" => Self::And,
            "||" => Self::Or,
            _ => unreachable!(),
        }
    }

    pub fn eval(&self, lhs: Value, rhs: Value) -> Result<Value, RuntimeError> {
        Ok(match self {
            Self::Pow => Value::Number(lhs.as_number()?.powf(rhs.as_number()?)),
            Self::Mul => Value::Number(lhs.as_number()? * rhs.as_number()?),
            Self::Div => Value::Number(lhs.as_number()? / rhs.as_number()?),
            Self::Mod => Value::Number(lhs.as_number()? % rhs.as_number()?),
            Self::Add => match lhs.deref() {
                Value::String(lhs) => Value::String(lhs.clone() + &rhs.as_string()?),
                Value::Number(lhs) => Value::Number(*lhs + rhs.as_number()?),
                _ => return Err(RuntimeError {
                    message: format!("cannot add {} and {}", lhs.type_name(), rhs.type_name()),
                }),
            },
            Self::Sub => Value::Number(lhs.as_number()? - rhs.as_number()?),
            Self::Shl => Value::Number(((lhs.as_number()? as i64) << (rhs.as_number()? as i64)) as f64),
            Self::Shr => Value::Number(((lhs.as_number()? as i64) >> (rhs.as_number()? as i64)) as f64),
            Self::Lt => Value::Bool(lhs.as_number()? < rhs.as_number()?),
            Self::Le => Value::Bool(lhs.as_number()? <= rhs.as_number()?),
            Self::Gt => Value::Bool(lhs.as_number()? > rhs.as_number()?),
            Self::Ge => Value::Bool(lhs.as_number()? >= rhs.as_number()?),
            Self::Eq => Value::Bool(lhs == rhs),
            Self::Ne => Value::Bool(lhs != rhs),
            Self::BitAnd => Value::Number((lhs.as_number()? as i64 & rhs.as_number()? as i64) as f64),
            Self::BitXor => Value::Number((lhs.as_number()? as i64 ^ rhs.as_number()? as i64) as f64),
            Self::BitOr => Value::Number((lhs.as_number()? as i64 | rhs.as_number()? as i64) as f64),
            Self::And => Value::Bool(lhs.as_bool()? && rhs.as_bool()?),
            Self::Or => Value::Bool(lhs.as_bool()? || rhs.as_bool()?),
        })
    }
}