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 {
19 cond: Expr,
20 },
21 Switch {
26 selector: Expr,
27 targets: SwitchTargets,
28 default: Option<u32>,
29 },
30 Return(Option<Expr>),
31 Throw(Expr),
32 Jsr,
34 Ret,
36}
37
38#[derive(Debug, Clone)]
39pub enum SwitchTargets {
40 Table { low: i32, targets: Vec<u32> },
42 Lookup { pairs: Vec<(i32, u32)> },
44}
45
46#[derive(Debug, Clone)]
47pub struct BlockResult {
48 pub stmts: Vec<Stmt>,
51 pub out_stack: Vec<Expr>,
55 pub term: Term,
56}
57
58#[derive(Debug)]
59pub struct BuildError(pub String);
60
61pub type BResult<T> = Result<T, BuildError>;
62
63pub fn int_const(i: i32) -> Expr {
65 Expr::Const(ConstVal::Int(i))
66}
67
68pub fn has_side_effects(e: &Expr) -> bool {
71 match e {
72 Expr::Const(_) | Expr::Local { .. } | Expr::This | Expr::Raw(_) | Expr::RawT(..) => false,
73 Expr::New { .. }
74 | Expr::Method { .. }
75 | Expr::Invokedynamic { .. }
76 | Expr::Lambda(_)
77 | Expr::AnonNew { .. } => true,
78 Expr::Assign { .. } | Expr::PreIncDec { .. } | Expr::PostIncDec { .. } => true,
79 Expr::Field { owner, .. } => match owner.as_deref() {
80 None => false,
84 Some(Expr::This) => false,
85 Some(Expr::Local { var: 0, .. }) => false,
86 Some(_) => true,
87 },
88 Expr::ArrayIndex { .. } => true,
89 Expr::Un { e, .. } | Expr::Cast { e, .. } | Expr::InstanceOf { e, .. } => {
90 has_side_effects(e)
91 }
92 Expr::Bin { l, r, .. } => has_side_effects(l) || has_side_effects(r),
93 Expr::Cond { c, t, f } => has_side_effects(c) || has_side_effects(t) || has_side_effects(f),
94 Expr::NewArray { dims, init, .. } => {
95 dims.iter().any(has_side_effects)
96 || init
97 .as_ref()
98 .map(|v| v.iter().any(has_side_effects))
99 .unwrap_or(false)
100 }
101 Expr::NewMultiArray { dims, .. } => dims.iter().any(has_side_effects),
102 Expr::StringConcat(parts) => parts.iter().any(|p| match p {
103 ConcatPart::Str(e) => has_side_effects(e),
104 ConcatPart::Const(_) => false,
105 }),
106 }
107}
108
109pub fn unfold_cmp(v: Expr, op_if_int: BinOp) -> (Expr, Expr, BinOp) {
112 if let Expr::Invokedynamic { name, args, .. } = &v {
113 if name.starts_with("\u{0}cmp") && args.len() == 2 {
114 let mut args = match v {
115 Expr::Invokedynamic { args, .. } => args,
116 _ => unreachable!(),
117 };
118 let r = args.pop().unwrap();
119 let l = args.pop().unwrap();
120 return (l, r, op_if_int);
121 }
122 }
123 (v, int_const(0), op_if_int)
124}
125
126pub fn class_name_to_type(name: &str) -> JavaType {
128 if name.starts_with('[') {
129 crate::types::parse_field_descriptor(name).unwrap_or(JavaType::Object(name.into()))
130 } else {
131 JavaType::Object(name.into())
132 }
133}