tjs2dec\decompile/
mod.rs

1pub mod cfg;
2pub mod decode;
3pub mod expr;
4pub mod expr_build;
5pub mod hlir;
6pub mod srcgen_high;
7pub mod srcgen_low;
8pub mod ssa;
9
10use anyhow::Result;
11
12use crate::model::Tjs2File;
13
14/// Build CFG + SSA for each object and return a text dump.
15///
16/// This is a parallel pipeline to the executable-emitter mode.
17/// The dump is a developer-facing artifact intended for validation.
18pub fn dump_ssa_file(file: &Tjs2File) -> Result<String> {
19    let mut out = String::new();
20    out.push_str(&format!("toplevel: {}\n", file.toplevel));
21    out.push_str(&format!("objects: {}\n\n", file.objects.len()));
22
23    for obj in &file.objects {
24        out.push_str(&format!(
25            "== object {}: {} ==\n",
26            obj.index,
27            obj.name.as_deref().unwrap_or("<anonymous>")
28        ));
29        if obj.code.is_empty() {
30            out.push_str("  (empty code area; skipped)\n\n");
31            continue;
32        }
33        let cfg = cfg::Cfg::build(obj)?;
34        let ssa = ssa::SsaProgram::from_cfg(&cfg)?;
35        out.push_str(&ssa.dump());
36        out.push('\n');
37    }
38    Ok(out)
39}
40
41/// Build a basic HLIR representation (SSA-backed) and return a dump.
42///
43/// At this stage, HLIR is intentionally conservative: it keeps side-effects explicit
44/// and avoids reordering across potential exception boundaries.
45pub fn dump_hlir_file(file: &Tjs2File) -> Result<String> {
46    let mut out = String::new();
47    out.push_str(&format!("toplevel: {}\n", file.toplevel));
48    out.push_str(&format!("objects: {}\n\n", file.objects.len()));
49
50    for obj in &file.objects {
51        out.push_str(&format!(
52            "== object {}: {} ==\n",
53            obj.index,
54            obj.name.as_deref().unwrap_or("<anonymous>")
55        ));
56        let cfg = cfg::Cfg::build(obj)?;
57        let ssa = ssa::SsaProgram::from_cfg(&cfg)?;
58        let hlir = hlir::HlirProgram::from_ssa(&ssa)?;
59        out.push_str(&hlir.dump());
60        out.push('\n');
61    }
62    Ok(out)
63}
64
65pub fn dump_expr_file(file: &Tjs2File) -> Result<String> {
66    let mut out = String::new();
67    out.push_str(&format!("toplevel: {}\n", file.toplevel));
68    out.push_str(&format!("objects: {}\n\n", file.objects.len()));
69
70    for obj in &file.objects {
71        out.push_str(&format!(
72            "== object {}: {} ==\n",
73            obj.index,
74            obj.name.as_deref().unwrap_or("<anonymous>")
75        ));
76        if obj.code.is_empty() {
77            out.push_str("  (empty code area; skipped)\n\n");
78            continue;
79        }
80        let cfg = cfg::Cfg::build(obj)?;
81        let ssa = ssa::SsaProgram::from_cfg(&cfg)?;
82        let ep = expr_build::ExprProgram::from_ssa(file, obj, &ssa)?;
83        out.push_str(&ep.dump());
84        out.push('\n');
85    }
86    Ok(out)
87}