1use std::error::Error;
2use std::ffi::OsString;
3use std::fmt::{self, Display, Formatter};
4use std::path::PathBuf;
5
6use clap::ArgAction::{Set, SetTrue};
7use clap::Parser;
8use tracing::{Level, event, span};
9use tracing_subscriber::prelude::*;
10
11use assembler::*;
12
13const AUTHOR: &str = "James Youngman <james@youngman.org>";
17
18#[derive(Parser, Debug)]
20#[clap(author = AUTHOR, version, about, long_about = None)]
21struct Cli {
22 #[clap(action=Set)]
24 input: OsString,
25
26 #[clap(action = Set, short = 'o', long)]
28 output: OsString,
29
30 #[clap(action = SetTrue, long)]
33 list: bool,
34}
35
36#[derive(Debug)]
37enum Fail {
38 AsmFail(AssemblerFailure),
40 InitialisationFailure(String),
42}
43
44impl Display for Fail {
45 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
46 match self {
47 Fail::AsmFail(assembler_failure) => assembler_failure.fmt(f),
48 Fail::InitialisationFailure(msg) => f.write_str(msg.as_str()),
49 }
50 }
51}
52
53impl Error for Fail {}
54fn run_asembler() -> Result<(), Fail> {
55 let cli = Cli::parse();
56
57 let fmt_layer = tracing_subscriber::fmt::layer().with_target(true);
62 let filter_layer = match tracing_subscriber::EnvFilter::try_from_default_env()
63 .or_else(|_| tracing_subscriber::EnvFilter::try_new("info"))
64 {
65 Err(e) => {
66 return Err(Fail::InitialisationFailure(format!(
67 "failed to initialise tracing filter (perhaps there is a problem with environment variables): {e}"
68 )));
69 }
70 Ok(layer) => layer,
71 };
72
73 tracing_subscriber::registry()
74 .with(filter_layer)
75 .with(fmt_layer)
76 .init();
77
78 let span = span!(Level::ERROR, "assemble", input=?cli.input, output=?cli.output);
79 let _enter = span.enter();
80 let output_path = PathBuf::from(cli.output);
81 let options: OutputOptions = OutputOptions { list: cli.list };
82 let result = assemble_file(&cli.input, &output_path, options).map_err(Fail::AsmFail);
83 if let Err(e) = &result {
84 event!(Level::ERROR, "assembly failed: {:?}", e);
85 } else {
86 event!(Level::INFO, "assembly succeeded");
87 }
88 result
89}
90
91fn main() {
92 unsafe { backtrace_on_stack_overflow::enable() };
93
94 match run_asembler() {
95 Err(e) => {
96 eprintln!("{e}");
97 std::process::exit(1);
98 }
99 Ok(()) => {
100 std::process::exit(0);
101 }
102 }
103}