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),
}
}
}