use super::{defs::{CastInto, GetType}, rustdecl::{RInit, RType}, rustexpr::*, rustprimitives::{RLit, TypedIdent}};
macro_rules! cast {
($ty:expr,$id:ident,$lhs:expr,$rhs:expr) => {
Self::$id(Box::new($lhs.cast($ty)), $rhs.cast($ty))
};
}
impl GetType for TypedIdent {
fn get_type(&self) -> RType {
*self.1.clone()
}
}
impl GetType for RLit {
fn get_type(&self) -> RType {
match self {
Self::Int(_, rtype)|Self::Float(_, rtype)|Self::String(_, rtype) => rtype.clone(),
}
}
}
impl GetType for RPrimaryExpr {
fn get_type(&self) -> RType {
match self {
Self::Lit(rlit) => rlit.get_type(),
Self::Ident(typed_ident) => typed_ident.get_type(),
Self::RInit(rinit) => rinit.get_type(),
Self::Expr(rexpr) => rexpr.get_type(),
}
}
}
impl GetType for RFieldExpr {
fn get_type(&self) -> RType {
self.2.clone()
}
}
impl GetType for RPostfixExpr {
fn get_type(&self) -> RType {
match self {
Self::Field(rfield_expr) => rfield_expr.get_type(),
Self::Func(..,ty) => ty.clone(),
Self::Array(rpostfix_expr, _) => {
let ty=rpostfix_expr.get_type();
match ty {
RType::Point(rtype)|RType::PointMut(rtype)|RType::Ref(_,rtype)|RType::RefMut(_,rtype)|
RType::ThinPoint(rtype)|RType::ThinPointMut(rtype)|RType::ThinRef(_,rtype)|RType::ThinRefMut(_,rtype)|
RType::Array(rtype, _)|RType::GenericArray(rtype, _)|
RType::UnsizedArray(rtype) => *rtype,
_ => ty }
},
Self::Sizeof(_)|Self::SizeofType(_) => RType::Usize,
}
}
}
impl GetType for RUnaryExpr {
fn get_type(&self) -> RType {
match self {
Self::Postfix(rpostfix_expr) => rpostfix_expr.get_type(),
Self::Minus(runary_expr)|Self::Not(runary_expr) => runary_expr.get_type(),
Self::Deref(runary_expr) => runary_expr.get_type().get_type_alias().deref(),
Self::Ref(runary_expr) => runary_expr.get_type().get_type_alias().ref_const(),
Self::RefMut(runary_expr) => runary_expr.get_type().get_type_alias().ref_mut(),
}
}
}
fn deref(expr: RCastExpr) -> RUnaryExpr {
match expr {
RCastExpr::Unary(unary) => {
match unary {
RUnaryExpr::Ref(runary_expr)|RUnaryExpr::RefMut(runary_expr) => *runary_expr,
_ => unary.deref()
}
},
RCastExpr::Cast(..) => RUnaryExpr::from(RExpr::from(expr)).deref(),
}
}
fn cast(expr: RUnaryExpr,ty: &RType) -> RCastExpr {
RCastExpr::Unary(expr).cast(ty)
}
fn reref(expr: RCastExpr) -> RUnaryExpr {
match expr {
RCastExpr::Unary(unary) => RUnaryExpr::Ref(Box::new(unary)),
RCastExpr::Cast(..) => RUnaryExpr::Ref(Box::new(RUnaryExpr::from(RExpr::from(expr)))),
}
}
fn rerefmut(expr: RCastExpr) -> RUnaryExpr {
match expr {
RCastExpr::Unary(unary) => RUnaryExpr::RefMut(Box::new(unary)),
RCastExpr::Cast(..) => RUnaryExpr::RefMut(Box::new(RUnaryExpr::from(RExpr::from(expr)))),
}
}
fn arrayify(expr: RCastExpr) -> RPrimaryExpr {
let ty=expr.get_type().get_type_alias();
RPrimaryExpr::RInit(Box::new(RInit::Array(vec![RInit::Expr(expr.into())], ty)))
}
fn first_elem(expr: RCastExpr) -> RUnaryExpr {
let postfix=
match expr {
RCastExpr::Unary(RUnaryExpr::Postfix(post)) => *post,
_ => RExpr::from(expr).into()
};
RUnaryExpr::Postfix(Box::new(
RPostfixExpr::Array(Box::new(postfix), Box::new(RExpr::from(0)))
))
}
fn ref_point(val: RCastExpr, ref_ty: &RType, self_ty: RType) -> RCastExpr {
match self_ty {
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::Point(rtype)|RType::PointMut(rtype) => {
if *ref_ty==*rtype { val }
else { RCastExpr::Unary(reref(cast(deref(val),ref_ty))) }
},
RType::ThinRef(_,rtype)|RType::ThinRefMut(_,rtype)|RType::ThinPoint(rtype)|RType::ThinPointMut(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(RUnaryExpr::Ref(Box::new(arrayify(RCastExpr::Unary(deref(val))).into()))) }
else {
match *rtype {
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::Point(rtype)|RType::PointMut(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(deref(val)) }
else { RCastExpr::Unary(reref(cast(deref(RCastExpr::Unary(deref(val))),ref_ty))) }
},
RType::Array(rtype, _)|RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _) => {
if *ref_ty==*rtype { val }
else { RCastExpr::Unary(reref(cast(deref(val),ref_ty))) }
},
_ => RCastExpr::Unary(reref(cast(arrayify(RCastExpr::Unary(deref(val))).into(),ref_ty)))
}
}
},
RType::Array(rtype, _)|RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _) => {
if *ref_ty==*rtype { RCastExpr::Unary(reref(val)) }
else { RCastExpr::Unary(reref(val.cast(ref_ty))) }
},
RType::Function(..)|RType::EnumDecl(..)|RType::Enum(_)|RType::Typedef(..)|RType::StructDecl(..)|
RType::UnionDecl(..)|RType::Struct(_)|RType::Union(_)|RType::Unit => val, _ => RCastExpr::Unary(RUnaryExpr::Ref(Box::new(arrayify(val).into())))
}
}
fn ref_point_mut(val: RCastExpr, ref_ty: &RType, self_ty: RType) -> RCastExpr {
match self_ty {
RType::Ref(_,rtype)|RType::Point(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(rerefmut(RCastExpr::Unary(deref(val)))) }
else { RCastExpr::Unary(rerefmut(cast(deref(val),ref_ty))) }
},
RType::RefMut(_,rtype)|RType::PointMut(rtype) => {
if *ref_ty==*rtype { val }
else { RCastExpr::Unary(rerefmut(cast(deref(val),ref_ty))) }
},
RType::ThinRef(_,rtype)|RType::ThinRefMut(_,rtype)|RType::ThinPoint(rtype)|RType::ThinPointMut(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(RUnaryExpr::RefMut(Box::new(arrayify(RCastExpr::Unary(deref(val))).into()))) }
else {
match *rtype {
RType::Ref(_,rtype)|RType::Point(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(rerefmut(RCastExpr::Unary(deref(RCastExpr::Unary(deref(val)))))) }
else { RCastExpr::Unary(rerefmut(cast(deref(RCastExpr::Unary(deref(val))),ref_ty))) }
},
RType::RefMut(_,rtype)|RType::PointMut(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(deref(val)) }
else { RCastExpr::Unary(rerefmut(cast(deref(RCastExpr::Unary(deref(val))),ref_ty))) }
},
RType::Array(rtype, _)|RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _) => {
if *ref_ty==*rtype { val }
else { RCastExpr::Unary(rerefmut(cast(deref(val),ref_ty))) }
},
_ => RCastExpr::Unary(rerefmut(cast(arrayify(RCastExpr::Unary(deref(val))).into(),ref_ty)))
}
}
},
RType::Array(rtype, _)|RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _) => {
if *ref_ty==*rtype { RCastExpr::Unary(rerefmut(val)) }
else { RCastExpr::Unary(rerefmut(val.cast(ref_ty))) }
},
RType::Function(..)|RType::EnumDecl(..)|RType::Enum(_)|RType::Typedef(..)|RType::StructDecl(..)|
RType::UnionDecl(..)|RType::Struct(_)|RType::Union(_)|RType::Unit => val, _ => RCastExpr::Unary(RUnaryExpr::RefMut(Box::new(arrayify(val).into())))
}
}
fn thin_const(val: RCastExpr, ref_ty: &RType, self_ty: RType) -> RCastExpr {
match self_ty {
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::Point(rtype)|RType::PointMut(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(reref(RCastExpr::Unary(deref(val)))) }
else { RCastExpr::Unary(reref(cast(deref(val),ref_ty))) }
},
RType::ThinRef(_,rtype)|RType::ThinRefMut(_,rtype)|RType::ThinPoint(rtype)|RType::ThinPointMut(rtype) => {
if *ref_ty==*rtype { val }
else { RCastExpr::Unary(reref(cast(deref(val),ref_ty))) }
},
RType::Array(rtype, _)|RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _) => {
if *ref_ty==*rtype { RCastExpr::Unary(reref(RCastExpr::Unary(first_elem(val)))) }
else { RCastExpr::Unary(reref(cast(first_elem(val),ref_ty)))}
},
RType::Function(..)|RType::EnumDecl(..)|RType::Enum(_)|RType::Typedef(..)|RType::StructDecl(..)|
RType::UnionDecl(..)|RType::Struct(_)|RType::Union(_)|RType::Unit => val, _ => RCastExpr::Unary(reref(val))
}
}
fn thin_mut(val: RCastExpr, ref_ty: &RType, self_ty: RType) -> RCastExpr {
match self_ty {
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::Point(rtype)|RType::PointMut(rtype)|
RType::ThinRef(_,rtype)|RType::ThinPoint(rtype) => {
if *ref_ty==*rtype { RCastExpr::Unary(rerefmut(RCastExpr::Unary(deref(val)))) }
else { RCastExpr::Unary(rerefmut(cast(deref(val),ref_ty))) }
},
RType::ThinRefMut(_,rtype)|RType::ThinPointMut(rtype) => {
if *ref_ty==*rtype { val }
else { RCastExpr::Unary(rerefmut(cast(deref(val),ref_ty))) }
},
RType::Array(rtype, _)|RType::UnsizedArray(rtype)|RType::GenericArray(rtype, _) => {
if *ref_ty==*rtype { RCastExpr::Unary(rerefmut(RCastExpr::Unary(first_elem(val)))) }
else { RCastExpr::Unary(rerefmut(cast(first_elem(val),ref_ty)))}
},
RType::Function(..)|RType::EnumDecl(..)|RType::Enum(_)|RType::Typedef(..)|RType::StructDecl(..)|
RType::UnionDecl(..)|RType::Struct(_)|RType::Union(_)|RType::Unit => val, _ => RCastExpr::Unary(rerefmut(val))
}
}
macro_rules! ty_check {
($self:expr,$ty:expr) => {
{
let self_ty=$self.get_type().get_type_alias();
if *$ty==self_ty || *$ty==RType::I8 && self_ty==RType::BoolI8 { return $self }
}
};
}
impl GetType for RCastExpr {
fn get_type(&self) -> RType {
match self {
Self::Unary(runary_expr) => runary_expr.get_type(),
Self::Cast(_, rtype) => rtype.clone(),
}
}
}
impl CastInto for RCastExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
let self_ty=self.get_type().get_type_alias();
let ty=ty.clone().get_type_alias();
if matches!(ty,RType::Enum(_)|RType::EnumDecl(..)|RType::Function(..)) || matches!(self_ty,RType::Function(..)) { return self }
if self_ty==ty || matches!(ty,RType::GenericArray(..)|RType::Unit) { return self }
if matches!(self_ty,RType::StructDecl(..)|RType::UnionDecl(..)|RType::Struct(_)|RType::Union(_)|RType::Unit) { return self }
match ty {
RType::Ref(_,ref_ty)|RType::Point(ref_ty) => ref_point(self, ref_ty.as_ref(), self_ty),
RType::RefMut(_,ref_ty)|RType::PointMut(ref_ty) => ref_point_mut(self, ref_ty.as_ref(), self_ty),
RType::ThinRef(_,ref_ty)|RType::ThinPoint(ref_ty) => thin_const(self, ref_ty.as_ref(), self_ty),
RType::ThinRefMut(_,ref_ty)|RType::ThinPointMut(ref_ty) => thin_mut(self, ref_ty.as_ref(), self_ty),
RType::Function(..)|RType::Typedef(..)|RType::GenericArray(..)|RType::Unit => self, _ => Self::Cast(Box::new(self), ty),
}
}
}
impl GetType for RMulExpr {
fn get_type(&self) -> RType {
match self {
Self::Cast(rcast_expr)|Self::Mul(_, rcast_expr)|
Self::Div(_, rcast_expr)|Self::Mod(_, rcast_expr) => rcast_expr.get_type(),
}
}
}
impl CastInto for RMulExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Cast(rcast_expr) => Self::Cast(rcast_expr.cast(ty)),
Self::Mul(rmul_expr, rcast_expr) => cast!(ty,Mul,rmul_expr,rcast_expr),
Self::Div(rmul_expr, rcast_expr) => cast!(ty,Div,rmul_expr,rcast_expr),
Self::Mod(rmul_expr, rcast_expr) => cast!(ty,Mod,rmul_expr,rcast_expr),
}
}
}
impl GetType for RAddExpr {
fn get_type(&self) -> RType {
match self {
Self::Mul(rmul_expr)|Self::Add(_, rmul_expr)|Self::Sub(_, rmul_expr) => rmul_expr.get_type(),
}
}
}
impl CastInto for RAddExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Mul(rmul_expr) => Self::Mul(rmul_expr.cast(ty)),
Self::Add(radd_expr, rmul_expr) => cast!(ty,Add,radd_expr,rmul_expr),
Self::Sub(radd_expr, rmul_expr) => cast!(ty,Sub,radd_expr,rmul_expr),
}
}
}
impl GetType for RShiftExpr {
fn get_type(&self) -> RType {
match self {
Self::Add(radd_expr)|Self::LShift(_, radd_expr)|Self::RShift(_, radd_expr) => radd_expr.get_type(),
}
}
}
impl CastInto for RShiftExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Add(radd_expr) => Self::Add(radd_expr.cast(ty)),
Self::LShift(rshift_expr, radd_expr) => cast!(ty,LShift,rshift_expr,radd_expr),
Self::RShift(rshift_expr, radd_expr) => cast!(ty,RShift,rshift_expr,radd_expr),
}
}
}
impl GetType for RAndExpr {
fn get_type(&self) -> RType {
match self {
Self::Shift(rshift_expr)|Self::And(_, rshift_expr) => rshift_expr.get_type(),
}
}
}
impl CastInto for RAndExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Shift(rshift_expr) => Self::Shift(rshift_expr.cast(ty)),
Self::And(rand_expr, rshift_expr) => cast!(ty,And,rand_expr,rshift_expr),
}
}
}
impl GetType for RXorExpr {
fn get_type(&self) -> RType {
match self {
Self::And(rand_expr)|Self::Xor(_, rand_expr) => rand_expr.get_type(),
}
}
}
impl CastInto for RXorExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::And(rand_expr) => Self::And(rand_expr.cast(ty)),
Self::Xor(rxor_expr, rand_expr) => cast!(ty,Xor,rxor_expr,rand_expr),
}
}
}
impl GetType for ROrExpr {
fn get_type(&self) -> RType {
match self {
Self::Xor(rxor_expr)|Self::Or(_, rxor_expr) => rxor_expr.get_type(),
}
}
}
impl CastInto for ROrExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Xor(xor) => Self::Xor(xor.cast(ty)),
Self::Or(or, xor) => cast!(ty,Or,or,xor),
}
}
}
impl GetType for RCompExpr {
fn get_type(&self) -> RType {
match self {
Self::Or(ror_expr) => ror_expr.get_type(),
_ => RType::Bool
}
}
}
impl CastInto for RCompExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
if let Self::Or(ror_expr) = self { Self::Or(ror_expr.cast(ty)) }
else { RExpr::from(RCastExpr::from(RExpr::from(self)).cast(ty)).into() }
}
}
impl GetType for RLogAndExpr {
fn get_type(&self) -> RType {
match self {
Self::Comp(rcomp_expr) => rcomp_expr.get_type(),
Self::And(..) => RType::Bool
}
}
}
impl CastInto for RLogAndExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
if let Self::Comp(rcomp_expr) = self { Self::Comp(rcomp_expr.cast(ty)) }
else { RExpr::from(RCastExpr::from(RExpr::from(self)).cast(ty)).into() }
}
}
impl GetType for RLogOrExpr {
fn get_type(&self) -> RType {
match self {
Self::And(rlog_and_expr) => rlog_and_expr.get_type(),
Self::Or(..) => RType::Bool
}
}
}
impl CastInto for RLogOrExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
if let Self::And(rlog_and_expr) = self { Self::And(rlog_and_expr.cast(ty)) }
else { RExpr::from(RCastExpr::from(RExpr::from(self)).cast(ty)).into() }
}
}
impl GetType for RTernary {
fn get_type(&self) -> RType {
match self {
Self::Or(rlog_or_expr) => rlog_or_expr.get_type(),
Self::Ternary(_, rexpr, _) => rexpr.get_type(),
}
}
}
impl CastInto for RTernary {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Or(rlog_or_expr) => Self::Or(Box::new(rlog_or_expr.cast(ty))),
Self::Ternary(rlog_or_expr, rexpr, rternary) => {
Self::Ternary(rlog_or_expr, Box::new(rexpr.cast(ty)), Box::new(rternary.cast(ty)))
},
}
}
}
impl GetType for RAssignExpr {
fn get_type(&self) -> RType {
match self {
Self::Ternary(rternary) => rternary.get_type(),
_ => RType::Unit
}
}
}
impl CastInto for RAssignExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Ternary(rternary) => Self::Ternary(rternary.cast(ty)),
_ => self }
}
}
impl GetType for RExpr {
fn get_type(&self) -> RType {
match self {
Self::Expr(rassign_expr) => rassign_expr.get_type(),
Self::Block(rassign_exprs) => rassign_exprs.last().map(GetType::get_type).unwrap_or_default(),
}
}
}
impl CastInto for RExpr {
fn cast(self, ty: &RType) -> Self {
ty_check!(self,ty);
match self {
Self::Expr(rassign_expr) => Self::Expr(Box::new(rassign_expr.cast(ty))),
Self::Block(mut rassign_exprs) => {
let last=rassign_exprs.pop();
if let Some(last)=last {
rassign_exprs.push(last.cast(ty));
}
Self::Block(rassign_exprs)
},
}
}
}
impl GetType for RInit {
fn get_type(&self) -> RType {
match self {
Self::Expr(rexpr) => rexpr.get_type(),
Self::Array(_, ty) => ty.clone(),
Self::Struct(rident, _) => RType::Struct(rident.clone()),
Self::Union(rident, _) => RType::Union(rident.clone()),
Self::Default(rtype) => rtype.clone(),
}
}
}
impl CastInto for RInit {
fn cast(self, ty: &RType) -> Self {
match self {
Self::Expr(rexpr) => Self::Expr(rexpr.cast(ty)),
Self::Default(_) => Self::Default(ty.clone()),
Self::Array(mut rinits, rtype) => {
let rtype=rtype.get_type_alias();
match rtype {
RType::Ref(_,rtype)|RType::RefMut(_,rtype)|RType::Point(rtype)|RType::PointMut(rtype)|RType::Array(rtype, _)
=> Self::Array(rinits.into_iter().map(|x| x.cast(&rtype)).collect(), *rtype),
_ => {
if rinits.is_empty() { Self::Default(ty.clone()) } else { rinits.remove(0).cast(ty) }
},
}
},
_ => self
}
}
}