ccarp 0.1.2

(trans)Compile C And Rust Partially
Documentation
//! Rust Compile Time Evaluation
//! 
//! This module implements traits associated with compile time evaluation.
use crate::ccarp::error::{c2rust_err, safe_unwrap, unimpl_err, CCErr, Result};

use super::{defs::{Context, Eval, GetType}, rustdecl::{RInit, RType}, rustexpr::*, rustprimitives::*};

macro_rules! no_eval {
    ($ex:expr) => {
        c2rust_err!("Could not evaluate expression '{}'",$ex)
    };
}

macro_rules! bin_expr {
    ($context:expr,$lhs:expr,$rhs:expr,$op:tt) => {
        Ok(($lhs.eval($context)? $op $rhs.eval($context)?).into())
    };
    ($name:ident; $base:ident, $($p:ident => $op:tt),+) => {
        impl Eval for $name {
            fn eval(&self, context: &Context) -> Result<i128> {
                match self {
                    $name::$base(base) => base.eval(context),
                    $(
                        $name::$p(lhs,rhs) => bin_expr!(context,lhs,rhs,$op),
                    )+
                }
            }
        }
    };
}

impl Eval for RIdent {
    fn eval(&self, context: &Context) -> Result<i128> {
        let consts=context.get_const_integers();
        for (name,val) in consts.into_iter().rev() {
            if name==self.0.as_str() { return Ok(val) }
        }
        let enums=context.get_enum_vals();
        for (name,val) in enums {
            if name==self.0.as_str() { return Ok(val) }
        }
        Err(no_eval!(self))
    }
}

impl Eval for TypedIdent {
    fn eval(&self, context: &Context) -> Result<i128> {
        self.0.eval(context)
    }
}

impl Eval for RLit {
    fn eval(&self, _context: &Context) -> Result<i128> {
        match self {
            Self::Int(int,_) => {
                let tmp=int.replace('i', "u");
                let mut sp=tmp.split('u');
                let num=safe_unwrap!(sp.next() => "A newly contructed Split always has at least 1 element!");
                num.strip_prefix("0x").map_or_else(
                    || num.strip_prefix("0o").map_or_else(
                        || str::parse::<i128>(num).map_err(|_| no_eval!(num)), 
                        |num| i128::from_str_radix(num,8).map_err(|_| no_eval!(num))), 
                    |num| i128::from_str_radix(num,16).map_err(|_| no_eval!(num))
                )
            },
            Self::Float(float,_) => {
                let mut sp=float.split('.');
                let num=safe_unwrap!(sp.next() => "A newly contructed Split always has at least 1 element!");
                str::parse::<i128>(num).map_err(|_| no_eval!(float))
            },
            Self::String(..) => Err(no_eval!(self)),
        }
    }
}

impl Eval for RPrimaryExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Lit(rlit) => rlit.eval(context),
            Self::Ident(rident) => rident.eval(context),
            Self::Expr(rexpr) => rexpr.eval(context),
            Self::RInit(rinit) => {
                match rinit.as_ref() {
                    RInit::Expr(rexpr) => rexpr.eval(context),
                    _ => Err(no_eval!(self))
                }
            },
        }
    }
}

impl Eval for RFieldExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        if self.1.is_empty() { self.0.eval(context) }
        else { Err(no_eval!(self)) }
    }
}

impl Eval for RPostfixExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Field(rfield_expr) => rfield_expr.eval(context),
            Self::SizeofType(rtype) => Ok(rtype.sizeof(context)? as i128),
            Self::Sizeof(expr) => Ok(expr.get_type().sizeof(context)? as i128),
            _ => Err(no_eval!(self))
        }
    }
}

impl Eval for RUnaryExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Postfix(rpostfix_expr) => rpostfix_expr.eval(context),
            Self::Minus(runary_expr) => runary_expr.eval(context).map(|x| -x),
            Self::Not(runary_expr) => runary_expr.eval(context).map(|x| !x),
            _ => Err(no_eval!(self))
        }
    }
}

impl Eval for RCastExpr {
    #[allow(clippy::cast_possible_wrap,clippy::cast_lossless,clippy::cast_possible_truncation,clippy::cast_sign_loss,clippy::cast_precision_loss)]
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Unary(runary_expr) => runary_expr.eval(context),
            Self::Cast(rcast_expr, rtype) => {
                let eval=rcast_expr.eval(context);
                match rtype {
                    RType::I8 => eval.map(|x| x as i8 as i128),
                    RType::U8 => eval.map(|x| x as u8 as i128),
                    RType::I16 => eval.map(|x| x as i16 as i128),
                    RType::U16 => eval.map(|x| x as u16 as i128),
                    RType::I32 => eval.map(|x| x as i32 as i128),
                    RType::U32 => eval.map(|x| x as u32 as i128),
                    RType::I64 => eval.map(|x| x as i64 as i128),
                    RType::U64 => eval.map(|x| x as u64 as i128),
                    RType::I128 => eval,
                    RType::U128 => eval.map(|x| x as u128 as i128),
                    RType::Isize => eval.map(|x| x as isize as i128),
                    RType::Usize => eval.map(|x| x as usize as i128),
                    RType::F32 => eval.map(|x| x as f32 as i128),
                    RType::F64 => eval.map(|x| x as f64 as i128),
                    RType::Bool => eval.map(|x| (x!=0).into()),
                    _ => Err(no_eval!(self))
                }
            },
        }
    }
}

bin_expr!(RMulExpr; Cast, Mul => *, Div => /, Mod => %);
bin_expr!(RAddExpr; Mul, Add => +, Sub => -);
bin_expr!(RShiftExpr; Add, LShift => <<, RShift => >>);
bin_expr!(RAndExpr; Shift, And => &);
bin_expr!(RXorExpr; And, Xor => ^);
bin_expr!(ROrExpr; Xor, Or => |);
bin_expr!(RCompExpr; Or, Eq => ==, Neq => !=, Gt => <, Lt => >, Gte => <=, Lte => >=);

impl Eval for RLogAndExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Comp(rcomp_expr) => rcomp_expr.eval(context),
            Self::And(rlog_and_expr, rcomp_expr) => {
                if let Ok(and)=rlog_and_expr.eval(context) {
                    if and==0 { return Ok(0) }
                    return rcomp_expr.eval(context)
                }
                Err(no_eval!(self))
            },
        }
    }
}

impl Eval for RLogOrExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::And(rlog_and_expr) => rlog_and_expr.eval(context),
            Self::Or(rlog_or_expr, rlog_and_expr) => {
                if let Ok(or)=rlog_or_expr.eval(context) {
                    if or!=0 { return Ok(1) }
                    return rlog_and_expr.eval(context)
                }
                Err(no_eval!(self))
            },
        }
    }
}

impl Eval for RTernary {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Or(rlog_or_expr) => rlog_or_expr.eval(context),
            Self::Ternary(rlog_or_expr, rexpr, rternary) => {
                rlog_or_expr.eval(context).and_then(|val| if val==0 { rternary.eval(context) } else { rexpr.eval(context) })
            },
        }
    }
}

impl Eval for RAssignExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Ternary(rternary) => rternary.eval(context),
            _ => Err(no_eval!(self))
        }
    }
}

impl Eval for RExpr {
    fn eval(&self, context: &Context) -> Result<i128> {
        match self {
            Self::Expr(rassign_expr) => rassign_expr.eval(context),
            Self::Block(rassign_exprs) => safe_unwrap!(rassign_exprs.last();"Expression Block","Expression").eval(context),
        }
    }
}