algorithmify 0.1.1

Create specifications for algorithms defined using Rust code
Documentation
use crate::interpreter::context::Context;

use super::Expression;
use anyhow::anyhow;

#[derive(Debug, Clone, PartialEq)]
pub enum Operation {
    Add(Expression, Expression),
    Sub(Expression, Expression),
    Div(Expression, Expression),
    Mul(Expression, Expression),
    BitAnd(Expression, Expression),
    BitOr(Expression, Expression),
    And(Expression, Expression),
    Or(Expression, Expression),
    Eq(Expression, Expression),
    Ne(Expression, Expression),
    Lt(Expression, Expression),
    Lte(Expression, Expression),
    Gt(Expression, Expression),
    Gte(Expression, Expression),
}

impl Operation {
    pub fn execute(&self, context: &mut Context) -> anyhow::Result<Expression> {
        Ok(match self {
            Self::Add(lhs, rhs) => add(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::Sub(lhs, rhs) => sub(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::Mul(lhs, rhs) => mul(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::Div(lhs, rhs) => div(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::BitAnd(lhs, rhs) => bitand(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::BitOr(lhs, rhs) => bitor(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::And(lhs, rhs) => and(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::Or(lhs, rhs) => or(lhs.execute(context)?, rhs.execute(context)?)?,
            Self::Eq(lhs, rhs) => eq(&lhs.execute(context)?, &rhs.execute(context)?)?,
            Self::Ne(lhs, rhs) => ne(&lhs.execute(context)?, &rhs.execute(context)?)?,
            Self::Lt(lhs, rhs) => lt(&lhs.execute(context)?, &rhs.execute(context)?)?,
            Self::Lte(lhs, rhs) => lte(&lhs.execute(context)?, &rhs.execute(context)?)?,
            Self::Gt(lhs, rhs) => gt(&lhs.execute(context)?, &rhs.execute(context)?)?,
            Self::Gte(lhs, rhs) => gte(&lhs.execute(context)?, &rhs.execute(context)?)?,
        })
    }
}

fn add(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Integer(lhs + rhs)),
        (Expression::Float(lhs), Expression::Float(rhs)) => Ok(Expression::Float(lhs + rhs)),
        (Expression::String(lhs), Expression::String(rhs)) => {
            Ok(Expression::String(lhs.clone() + &rhs))
        }
        (Expression::String(lhs), Expression::Char(rhs)) => {
            Ok(Expression::String(lhs.clone() + &rhs.to_string()))
        }
        (Expression::Char(lhs), Expression::String(rhs)) => {
            Ok(Expression::String(lhs.to_string() + &rhs))
        }
        (lhs, rhs) => Err(anyhow!(
            "Unsupported addition between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn sub(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Integer(lhs - rhs)),
        (Expression::Float(lhs), Expression::Float(rhs)) => Ok(Expression::Float(lhs - rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported substraction between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn mul(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Integer(lhs * rhs)),
        (Expression::Float(lhs), Expression::Float(rhs)) => Ok(Expression::Float(lhs * rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported multiplication between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn div(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Integer(lhs / rhs)),
        (Expression::Float(lhs), Expression::Float(rhs)) => Ok(Expression::Float(lhs / rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported division between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn bitand(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Integer(lhs & rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported bitwise AND between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn bitor(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Integer(lhs | rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported bitwise OR between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn and(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Bool(lhs), Expression::Bool(rhs)) => Ok(Expression::Bool(lhs && rhs)),
        (lhs, rhs) => Err(anyhow!("Unsupported AND between {:?} and {:?}", lhs, rhs)),
    }
}

fn or(lhs: Expression, rhs: Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Bool(lhs), Expression::Bool(rhs)) => Ok(Expression::Bool(lhs || rhs)),
        (lhs, rhs) => Err(anyhow!("Unsupported OR between {:?} and {:?}", lhs, rhs)),
    }
}

fn eq(lhs: &Expression, rhs: &Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Bool(*lhs == *rhs)),
        (Expression::Float(lhs), Expression::Float(rhs)) => Ok(Expression::Bool(*lhs == *rhs)),
        (Expression::Bool(lhs), Expression::Bool(rhs)) => Ok(Expression::Bool(*lhs == *rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported equals between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn ne(lhs: &Expression, rhs: &Expression) -> anyhow::Result<Expression> {
    eq(lhs, rhs)
        .map(|result| Expression::Bool(!result.as_boolean().unwrap()))
        .map_err(|_| anyhow!("Unsupported not equals between {:?} and {:?}", lhs, rhs))
}

fn lt(lhs: &Expression, rhs: &Expression) -> anyhow::Result<Expression> {
    match (lhs, rhs) {
        (Expression::Integer(lhs), Expression::Integer(rhs)) => Ok(Expression::Bool(*lhs < *rhs)),
        (Expression::Float(lhs), Expression::Float(rhs)) => Ok(Expression::Bool(*lhs < *rhs)),
        (Expression::Bool(lhs), Expression::Bool(rhs)) => Ok(Expression::Bool(*lhs < *rhs)),
        (lhs, rhs) => Err(anyhow!(
            "Unsupported less than between {:?} and {:?}",
            lhs,
            rhs
        )),
    }
}

fn lte(lhs: &Expression, rhs: &Expression) -> anyhow::Result<Expression> {
    eq(lhs, rhs)
        .and_then(|eq| {
            lt(lhs, rhs)
                .map(|lt| Expression::Bool(eq.as_boolean().unwrap() || lt.as_boolean().unwrap()))
        })
        .map_err(|_| {
            anyhow!(
                "Unsupported less than equals between {:?} and {:?}",
                lhs,
                rhs
            )
        })
}

fn gt(lhs: &Expression, rhs: &Expression) -> anyhow::Result<Expression> {
    eq(lhs, rhs)
        .and_then(|eq| {
            lt(lhs, rhs)
                .map(|lt| Expression::Bool(!eq.as_boolean().unwrap() && !lt.as_boolean().unwrap()))
        })
        .map_err(|_| anyhow!("Unsupported greater than between {:?} and {:?}", lhs, rhs))
}

fn gte(lhs: &Expression, rhs: &Expression) -> anyhow::Result<Expression> {
    lt(lhs, rhs)
        .map(|result| Expression::Bool(!result.as_boolean().unwrap()))
        .map_err(|_| {
            anyhow!(
                "Unsupported greater than equals between {:?} and {:?}",
                lhs,
                rhs
            )
        })
}