use std::path::Path;
use rsleigh::codegen::GeneratedModuleKind;
fn main() {
let args: Vec<String> = std::env::args().collect();
let archs: Vec<&str> = if args.len() > 1 {
args[1..].iter().map(|s| s.as_str()).collect()
} else {
vec!["x86-64", "x86-32", "aarch64", "riscv", "mips", "arm32"]
};
for arch in &archs {
match *arch {
"x86-64" => generate_arch(
"x86-64",
Path::new("slaspec/x86/x86-64.slaspec"),
"x86",
200,
8,
),
"x86-32" | "x86" => generate_arch(
"x86-32",
Path::new("slaspec/x86/x86.slaspec"),
"x86-32",
200,
4,
),
"aarch64" | "arm64" => generate_arch(
"aarch64",
Path::new("slaspec/AARCH64/AARCH64.slaspec"),
"aarch64",
200,
4,
),
"mips" | "mips32" => generate_arch(
"mips32",
Path::new("slaspec/MIPS/mips32be.slaspec"),
"mips",
200,
2,
),
"arm32" | "arm" => generate_arch(
"arm32",
Path::new("slaspec/ARM/ARM7_le.slaspec"),
"arm32",
200,
2,
),
"riscv" | "riscv64" => generate_arch(
"riscv64",
Path::new("slaspec/RISCV/riscv.lp64d.slaspec"),
"riscv",
200,
2,
),
other => {
eprintln!("Unknown arch: {other}. Supported: x86-64, aarch64");
std::process::exit(1);
}
}
}
}
fn generate_arch(
display_name: &str,
slaspec: &Path,
prefix: &str,
constructors_per_file: usize,
num_batches: usize,
) {
let arch_out = Path::new("generated").join(prefix).join("out");
std::fs::create_dir_all(&arch_out).unwrap();
eprintln!("Parsing {display_name} slaspec...");
let modules = rsleigh::codegen::generate_split_disassembler(
slaspec,
constructors_per_file,
"PLACEHOLDER",
)
.expect(&format!("failed to generate {display_name} disassembler"));
let mut instr_files = Vec::new();
let mut subtable_files = Vec::new();
let mut split_enum_files = Vec::new();
for m in &modules {
match m.kind {
GeneratedModuleKind::Shared | GeneratedModuleKind::Root => {}
GeneratedModuleKind::TableBatch => {
if m.is_instruction_table {
instr_files.push(m);
} else {
subtable_files.push(m);
}
}
GeneratedModuleKind::TableEnum => subtable_files.push(m),
GeneratedModuleKind::SplitTableEnum => {
if m.is_instruction_table {
split_enum_files.push(m);
} else {
subtable_files.push(m);
}
}
}
}
eprintln!(
" {} modules: {} instruction files, {} subtable files",
modules.len(),
instr_files.len(),
subtable_files.len()
);
let shared = modules.iter().find(|m| m.filename == "shared.rs").unwrap();
write_module(&arch_out.join("shared.rs"), shared);
{
let mut combined = String::new();
for m in &subtable_files {
let code = strip_super_import(&get_code(m));
combined.push_str(&code);
combined.push('\n');
}
std::fs::write(arch_out.join("subtables.rs"), &combined).unwrap();
eprintln!(" subtables: {:.1} KB", combined.len() as f64 / 1e3);
}
let mut recursive_code = String::new();
let mut nonrecursive_files: Vec<String> = Vec::new();
for m in &instr_files {
let code = strip_super_import(&get_code(m));
if code.contains("Tableinstruction") {
recursive_code.push_str(&code);
recursive_code.push('\n');
} else {
nonrecursive_files.push(code);
}
}
let actual_batches = num_batches.min(nonrecursive_files.len().max(1));
let files_per_batch = if nonrecursive_files.is_empty() {
1
} else {
(nonrecursive_files.len() + actual_batches - 1) / actual_batches
};
for batch_idx in 0..actual_batches {
let start = batch_idx * files_per_batch;
let end = (start + files_per_batch).min(nonrecursive_files.len());
let mut combined = String::new();
for code in &nonrecursive_files[start..end] {
combined.push_str(code);
combined.push('\n');
}
let fname = format!("batch_{:02}.rs", batch_idx);
std::fs::write(arch_out.join(&fname), &combined).unwrap();
eprintln!(
" {fname}: {:.1} KB ({} files)",
combined.len() as f64 / 1e3,
end - start
);
}
for batch_idx in actual_batches..num_batches {
let fname = format!("batch_{:02}.rs", batch_idx);
std::fs::write(arch_out.join(&fname), "").unwrap();
}
let root = modules.iter().find(|m| m.filename == "root.rs").unwrap();
let parse_fn = if let Some(raw) = &root.raw_code {
let mut result = String::new();
if let Some(idx) = raw.find("pub fn parse_instruction") {
result.push_str(&raw[idx..]);
}
for i in 0..300 {
result = result.replace(&format!("table_{} :: ", i), "");
}
result
} else {
root.code.to_string()
};
let mut root_code = String::new();
for m in &split_enum_files {
let code = strip_super_import(&get_code(m));
root_code.push_str(&code);
root_code.push('\n');
}
root_code.push_str(&recursive_code);
root_code.push('\n');
root_code.push_str(&parse_fn);
std::fs::write(arch_out.join("root.rs"), &root_code).unwrap();
eprintln!(" root: {:.1} KB", root_code.len() as f64 / 1e3);
eprintln!(" Done!");
}
fn get_code(m: &rsleigh::codegen::GeneratedModule) -> String {
if let Some(raw) = &m.raw_code {
raw.clone()
} else {
m.code.to_string()
}
}
fn strip_super_import(code: &str) -> String {
code.replace("# [allow (unused_imports)] use super :: * ;", "")
}
fn write_module(path: &Path, m: &rsleigh::codegen::GeneratedModule) {
if let Some(raw) = &m.raw_code {
std::fs::write(path, raw).unwrap();
} else {
std::fs::write(path, m.code.to_string()).unwrap();
}
}