1use crate::ir::expr::{BinOp, ConcatPart, ConstVal, Expr};
9use crate::ir::stmt::Stmt;
10use crate::types::JavaType;
11
12#[derive(Debug, Clone)]
14pub enum Term {
15 Fallthrough,
16 Goto,
17 Cond { cond: Expr },
19 Switch {
24 selector: Expr,
25 targets: SwitchTargets,
26 default: Option<u32>,
27 },
28 Return(Option<Expr>),
29 Throw(Expr),
30 Jsr,
32 Ret,
34}
35
36#[derive(Debug, Clone)]
37pub enum SwitchTargets {
38 Table { low: i32, targets: Vec<u32> },
40 Lookup { pairs: Vec<(i32, u32)> },
42}
43
44#[derive(Debug, Clone)]
45pub struct BlockResult {
46 pub stmts: Vec<Stmt>,
49 pub out_stack: Vec<Expr>,
53 pub term: Term,
54}
55
56#[derive(Debug)]
57pub struct BuildError(pub String);
58
59pub type BResult<T> = Result<T, BuildError>;
60
61pub fn int_const(i: i32) -> Expr {
63 Expr::Const(ConstVal::Int(i))
64}
65
66pub fn has_side_effects(e: &Expr) -> bool {
69 match e {
70 Expr::Const(_) | Expr::Local { .. } | Expr::This | Expr::Raw(_) | Expr::RawT(..) => false,
71 Expr::New { .. } | Expr::Method { .. } | Expr::Invokedynamic { .. } | Expr::Lambda(_)
72 | Expr::AnonNew { .. } => true,
73 Expr::Assign { .. } | Expr::PreIncDec { .. } | Expr::PostIncDec { .. } => true,
74 Expr::Field { owner, .. } => {
75 owner.is_some()
77 }
78 Expr::ArrayIndex { .. } => true,
79 Expr::Un { e, .. } | Expr::Cast { e, .. } | Expr::InstanceOf { e, .. } => has_side_effects(e),
80 Expr::Bin { l, r, .. } => has_side_effects(l) || has_side_effects(r),
81 Expr::Cond { c, t, f } => has_side_effects(c) || has_side_effects(t) || has_side_effects(f),
82 Expr::NewArray { dims, init, .. } => {
83 dims.iter().any(has_side_effects)
84 || init
85 .as_ref()
86 .map(|v| v.iter().any(has_side_effects))
87 .unwrap_or(false)
88 }
89 Expr::NewMultiArray { dims, .. } => dims.iter().any(has_side_effects),
90 Expr::StringConcat(parts) => parts.iter().any(|p| match p {
91 ConcatPart::Str(e) => has_side_effects(e),
92 ConcatPart::Const(_) => false,
93 }),
94 }
95}
96
97pub fn unfold_cmp(v: Expr, op_if_int: BinOp) -> (Expr, Expr, BinOp) {
100 if let Expr::Invokedynamic { name, args, .. } = &v {
101 if name.starts_with("\u{0}cmp") && args.len() == 2 {
102 let mut args = match v {
103 Expr::Invokedynamic { args, .. } => args,
104 _ => unreachable!(),
105 };
106 let r = args.pop().unwrap();
107 let l = args.pop().unwrap();
108 return (l, r, op_if_int);
109 }
110 }
111 (v, int_const(0), op_if_int)
112}
113
114pub fn class_name_to_type(name: &str) -> JavaType {
116 if name.starts_with('[') {
117 crate::types::parse_field_descriptor(name).unwrap_or(JavaType::Object(name.to_string()))
118 } else {
119 JavaType::Object(name.to_string())
120 }
121}