use crate::ir::expr::{BinOp, ConcatPart, ConstVal, Expr};
use crate::ir::stmt::Stmt;
use crate::types::JavaType;
#[derive(Debug, Clone)]
pub enum Term {
Fallthrough,
Goto,
Cond {
cond: Expr,
},
Switch {
selector: Expr,
targets: SwitchTargets,
default: Option<u32>,
},
Return(Option<Expr>),
Throw(Expr),
Jsr,
Ret,
}
#[derive(Debug, Clone)]
pub enum SwitchTargets {
Table { low: i32, targets: Vec<u32> },
Lookup { pairs: Vec<(i32, u32)> },
}
#[derive(Debug, Clone)]
pub struct BlockResult {
pub stmts: Vec<Stmt>,
pub out_stack: Vec<Expr>,
pub term: Term,
}
#[derive(Debug)]
pub struct BuildError(pub String);
pub type BResult<T> = Result<T, BuildError>;
pub fn int_const(i: i32) -> Expr {
Expr::Const(ConstVal::Int(i))
}
pub fn has_side_effects(e: &Expr) -> bool {
match e {
Expr::Const(_) | Expr::Local { .. } | Expr::This | Expr::Raw(_) | Expr::RawT(..) => false,
Expr::New { .. }
| Expr::Method { .. }
| Expr::Invokedynamic { .. }
| Expr::Lambda(_)
| Expr::AnonNew { .. } => true,
Expr::Assign { .. } | Expr::PreIncDec { .. } | Expr::PostIncDec { .. } => true,
Expr::Field { owner, .. } => {
owner.is_some()
}
Expr::ArrayIndex { .. } => true,
Expr::Un { e, .. } | Expr::Cast { e, .. } | Expr::InstanceOf { e, .. } => {
has_side_effects(e)
}
Expr::Bin { l, r, .. } => has_side_effects(l) || has_side_effects(r),
Expr::Cond { c, t, f } => has_side_effects(c) || has_side_effects(t) || has_side_effects(f),
Expr::NewArray { dims, init, .. } => {
dims.iter().any(has_side_effects)
|| init
.as_ref()
.map(|v| v.iter().any(has_side_effects))
.unwrap_or(false)
}
Expr::NewMultiArray { dims, .. } => dims.iter().any(has_side_effects),
Expr::StringConcat(parts) => parts.iter().any(|p| match p {
ConcatPart::Str(e) => has_side_effects(e),
ConcatPart::Const(_) => false,
}),
}
}
pub fn unfold_cmp(v: Expr, op_if_int: BinOp) -> (Expr, Expr, BinOp) {
if let Expr::Invokedynamic { name, args, .. } = &v {
if name.starts_with("\u{0}cmp") && args.len() == 2 {
let mut args = match v {
Expr::Invokedynamic { args, .. } => args,
_ => unreachable!(),
};
let r = args.pop().unwrap();
let l = args.pop().unwrap();
return (l, r, op_if_int);
}
}
(v, int_const(0), op_if_int)
}
pub fn class_name_to_type(name: &str) -> JavaType {
if name.starts_with('[') {
crate::types::parse_field_descriptor(name).unwrap_or(JavaType::Object(name.into()))
} else {
JavaType::Object(name.into())
}
}