1use std::collections::HashMap;
2
3use hlbc::fmt::EnhancedFmt;
4use hlbc::types::{RefEnumConstruct, RefField, RefFloat, RefFun, RefInt, RefString, RefType, Reg};
5use hlbc::{Bytecode, Str};
6
7#[derive(Debug)]
8pub struct SourceFile {
9 pub class: Class,
10}
11
12#[derive(Debug)]
13pub struct Class {
14 pub name: Str,
15 pub parent: Option<Str>,
16 pub fields: Vec<ClassField>,
17 pub methods: Vec<Method>,
18}
19
20#[derive(Debug)]
21pub struct ClassField {
22 pub name: Str,
23 pub ty: RefType,
24 pub static_: bool,
25}
26
27#[derive(Debug)]
28pub struct Method {
29 pub fun: RefFun,
30 pub static_: bool,
31 pub dynamic: bool,
32 pub statements: Vec<Statement>,
33}
34
35#[derive(Debug, Clone, Copy)]
36pub enum Constant {
37 InlineInt(usize),
38 Int(RefInt),
39 Float(RefFloat),
40 String(RefString),
41 Bool(bool),
42 Null,
43 This,
45}
46
47#[derive(Debug, Clone)]
48pub enum Operation {
49 Add(Box<Expr>, Box<Expr>),
51 Sub(Box<Expr>, Box<Expr>),
53 Mul(Box<Expr>, Box<Expr>),
55 Div(Box<Expr>, Box<Expr>),
57 Mod(Box<Expr>, Box<Expr>),
59 Shl(Box<Expr>, Box<Expr>),
61 Shr(Box<Expr>, Box<Expr>),
63 And(Box<Expr>, Box<Expr>),
65 Or(Box<Expr>, Box<Expr>),
67 Xor(Box<Expr>, Box<Expr>),
69 Neg(Box<Expr>),
71 Not(Box<Expr>),
73 Incr(Box<Expr>),
75 Decr(Box<Expr>),
77 Eq(Box<Expr>, Box<Expr>),
79 NotEq(Box<Expr>, Box<Expr>),
81 Gt(Box<Expr>, Box<Expr>),
83 Gte(Box<Expr>, Box<Expr>),
85 Lt(Box<Expr>, Box<Expr>),
87 Lte(Box<Expr>, Box<Expr>),
89}
90
91#[derive(Debug, Clone)]
93pub struct ConstructorCall {
94 pub ty: RefType,
95 pub args: Vec<Expr>,
96}
97
98impl ConstructorCall {
99 pub fn new(ty: RefType, args: Vec<Expr>) -> Self {
100 Self { ty, args }
101 }
102}
103
104#[derive(Debug, Clone)]
106pub struct Call {
107 pub fun: Expr,
108 pub args: Vec<Expr>,
109}
110
111impl Call {
112 pub fn new(fun: Expr, args: Vec<Expr>) -> Self {
113 Self { fun, args }
114 }
115
116 pub fn new_fun(fun: RefFun, args: Vec<Expr>) -> Self {
117 Self {
118 fun: Expr::FunRef(fun),
119 args,
120 }
121 }
122}
123
124#[derive(Debug, Clone)]
126pub enum Expr {
127 Anonymous(RefType, HashMap<RefField, Expr>),
129 Array(Box<Expr>, Box<Expr>),
131 Call(Box<Call>),
133 Constant(Constant),
135 Constructor(ConstructorCall),
137 Closure(RefFun, Vec<Statement>),
139 EnumConstr(RefType, RefEnumConstruct, Vec<Expr>),
140 Field(Box<Expr>, Str),
142 FunRef(RefFun),
144 IfElse {
146 cond: Box<Expr>,
147 if_: Vec<Statement>,
149 else_: Vec<Statement>,
151 },
152 Op(Operation),
154 Unknown(String),
156 Variable(Reg, Option<Str>),
158}
159
160pub const fn cst_int(cst: RefInt) -> Expr {
161 Expr::Constant(Constant::Int(cst))
162}
163
164pub const fn cst_float(cst: RefFloat) -> Expr {
165 Expr::Constant(Constant::Float(cst))
166}
167
168pub const fn cst_bool(cst: bool) -> Expr {
169 Expr::Constant(Constant::Bool(cst))
170}
171
172pub const fn cst_string(cst: RefString) -> Expr {
173 Expr::Constant(Constant::String(cst))
174}
175
176pub const fn cst_null() -> Expr {
177 Expr::Constant(Constant::Null)
178}
179
180pub const fn cst_this() -> Expr {
181 Expr::Constant(Constant::This)
182}
183
184macro_rules! make_op_shorthand {
186 ($name:ident, $op:ident, $( $e:ident ),+) => {
187 pub(crate) fn $name($( $e: Expr ),+) -> Expr {
188 Expr::Op(Operation::$op($( Box::new($e) ),+))
189 }
190 }
191}
192
193make_op_shorthand!(add, Add, e1, e2);
194make_op_shorthand!(sub, Sub, e1, e2);
195make_op_shorthand!(mul, Mul, e1, e2);
196make_op_shorthand!(div, Div, e1, e2);
197make_op_shorthand!(modulo, Mod, e1, e2);
198make_op_shorthand!(shl, Shl, e1, e2);
199make_op_shorthand!(shr, Shr, e1, e2);
200make_op_shorthand!(and, And, e1, e2);
201make_op_shorthand!(or, Or, e1, e2);
202make_op_shorthand!(xor, Xor, e1, e2);
203make_op_shorthand!(neg, Neg, e1);
204make_op_shorthand!(incr, Incr, e1);
205make_op_shorthand!(decr, Decr, e1);
206make_op_shorthand!(eq, Eq, e1, e2);
207make_op_shorthand!(noteq, NotEq, e1, e2);
208make_op_shorthand!(gt, Gt, e1, e2);
209make_op_shorthand!(gte, Gte, e1, e2);
210make_op_shorthand!(lt, Lt, e1, e2);
211make_op_shorthand!(lte, Lte, e1, e2);
212
213pub fn not(e: Expr) -> Expr {
215 use Expr::Op;
216 use Operation::*;
217 match e {
218 Op(Not(a)) => *a,
219 Op(Eq(a, b)) => Op(NotEq(a, b)),
220 Op(NotEq(a, b)) => Op(Eq(a, b)),
221 Op(Gt(a, b)) => Op(Lte(a, b)),
222 Op(Gte(a, b)) => Op(Lt(a, b)),
223 Op(Lt(a, b)) => Op(Gte(a, b)),
224 Op(Lte(a, b)) => Op(Gt(a, b)),
225 _ => Op(Not(Box::new(e))),
226 }
227}
228
229pub fn flip(e: Expr) -> Expr {
231 use Expr::Op;
232 use Operation::*;
233 match e {
234 Op(Add(a, b)) => Op(Add(b, a)),
235 Op(Eq(a, b)) => Op(Eq(b, a)),
236 Op(NotEq(a, b)) => Op(NotEq(b, a)),
237 Op(Gt(a, b)) => Op(Lt(b, a)),
238 Op(Gte(a, b)) => Op(Lte(b, a)),
239 Op(Lt(a, b)) => Op(Gt(b, a)),
240 Op(Lte(a, b)) => Op(Gte(b, a)),
241 _ => e,
242 }
243}
244
245pub fn array(array: Expr, index: Expr) -> Expr {
246 Expr::Array(Box::new(array), Box::new(index))
247}
248
249pub fn call(fun: Expr, args: Vec<Expr>) -> Expr {
250 Expr::Call(Box::new(Call::new(fun, args)))
251}
252
253pub fn call_fun(fun: RefFun, args: Vec<Expr>) -> Expr {
254 Expr::Call(Box::new(Call::new_fun(fun, args)))
255}
256
257pub fn field(expr: Expr, obj: RefType, field: RefField, code: &Bytecode) -> Expr {
258 Expr::Field(
260 Box::new(expr),
261 Str::from(field.display::<EnhancedFmt>(code, &code[obj]).to_string()),
262 )
263}
264
265#[derive(Debug, Clone)]
266pub enum Statement {
267 Assign {
269 declaration: bool,
271 variable: Expr,
272 assign: Expr,
273 },
274 ExprStatement(Expr),
276 Return(Option<Expr>),
278 IfElse {
280 cond: Expr,
281 if_: Vec<Statement>,
282 else_: Vec<Statement>,
284 },
285 Switch {
286 arg: Expr,
287 default: Vec<Statement>,
288 cases: Vec<(Expr, Vec<Statement>)>,
289 },
290 While {
292 cond: Expr,
293 stmts: Vec<Statement>,
294 },
295 Break,
296 Continue,
297 Throw(Expr),
298 Try {
299 stmts: Vec<Statement>,
300 },
301 Catch {
302 stmts: Vec<Statement>,
303 },
304 Comment(String),
305}
306
307pub fn stmt(e: Expr) -> Statement {
309 Statement::ExprStatement(e)
310}
311
312pub fn comment(comment: impl Into<String>) -> Statement {
313 Statement::Comment(comment.into())
314}