Skip to main content

disassemble/
disassemble.rs

1use std::{
2    env,
3    fs::File,
4    path::{Path, PathBuf},
5    process::ExitCode,
6};
7
8use ferro_babe::{Diagnostic, Disassembler, FerroFormatter, Formatter};
9
10fn main() -> ExitCode {
11    run().unwrap_or_else(|message| {
12        eprintln!("ferro-disassemble: {message}");
13        ExitCode::FAILURE
14    })
15}
16
17fn run() -> Result<ExitCode, String> {
18    let path = class_path()?;
19    let file =
20        File::open(&path).map_err(|error| format!("could not open {}: {error}", path.display()))?;
21    let disassembly = Disassembler::default()
22        .parse_reader(file)
23        .map_err(|error| format!("could not parse {}: {error}", path.display()))?;
24
25    let version = disassembly.version();
26    let Some(class) = disassembly.class() else {
27        println!(
28            "partial class file v{}.{}",
29            version.major(),
30            version.minor()
31        );
32        for diagnostic in disassembly.diagnostics() {
33            print_diagnostic(diagnostic);
34        }
35        return Ok(ExitCode::from(2));
36    };
37
38    let output = FerroFormatter
39        .format(class)
40        .map_err(|error| format!("could not format {}: {error}", path.display()))?;
41    print!("{output}");
42
43    Ok(ExitCode::SUCCESS)
44}
45
46fn class_path() -> Result<PathBuf, String> {
47    let mut arguments = env::args_os();
48    let executable = arguments.next().unwrap_or_default();
49    let Some(path) = arguments.next() else {
50        return Err(usage(&executable));
51    };
52
53    if arguments.next().is_some() {
54        return Err(usage(&executable));
55    }
56
57    Ok(PathBuf::from(path))
58}
59
60fn usage(executable: &std::ffi::OsStr) -> String {
61    format!("usage: {} <class-file>", Path::new(executable).display())
62}
63
64fn print_diagnostic(diagnostic: &Diagnostic) {
65    let offset = diagnostic
66        .offset()
67        .map(|offset| format!(" at code offset 0x{offset:04x}"))
68        .unwrap_or_default();
69
70    eprintln!(
71        "diagnostic: {:?} in {:?}{offset}: {}",
72        diagnostic.severity(),
73        diagnostic.stage(),
74        diagnostic.message()
75    );
76}