1use std::{ffi::OsString, path::PathBuf, rc::Rc, sync::Arc};
2
3use clap::Parser;
4use log::Log;
5use midenc_compile as compile;
6use midenc_hir::Context;
7use midenc_session::{
8 InputFile,
9 diagnostics::{Emitter, Report},
10};
11
12use crate::ClapDiagnostic;
13
14#[derive(Debug, Parser)]
16#[command(name = "midenc")]
17#[command(
18 author,
19 version,
20 about = "A compiler for Miden Assembly",
21 long_about = None,
22 arg_required_else_help = false,
23)]
24pub struct Midenc {
25 #[arg(value_name = "FILE")]
29 input: Option<InputFile>,
30 #[command(flatten)]
31 options: compile::Compiler,
32}
33
34impl Midenc {
35 pub fn run<P, A>(
36 cwd: P,
37 args: A,
38 logger: Box<dyn Log>,
39 filter: log::LevelFilter,
40 ) -> Result<(), Report>
41 where
42 P: Into<PathBuf>,
43 A: IntoIterator<Item = OsString>,
44 {
45 Self::run_with_emitter(cwd, args, None, logger, filter)
46 }
47
48 pub fn run_with_emitter<P, A>(
49 cwd: P,
50 args: A,
51 emitter: Option<Arc<dyn Emitter>>,
52 logger: Box<dyn Log>,
53 filter: log::LevelFilter,
54 ) -> Result<(), Report>
55 where
56 P: Into<PathBuf>,
57 A: IntoIterator<Item = OsString>,
58 {
59 log::set_boxed_logger(logger)
60 .unwrap_or_else(|err| panic!("failed to install logger: {err}"));
61 log::set_max_level(filter);
62
63 let command = <Self as clap::CommandFactory>::command();
64 let command = midenc_session::flags::register_flags(command);
65
66 let mut matches = command.try_get_matches_from(args).map_err(ClapDiagnostic::from)?;
67 let compile_matches = matches.clone();
68 let Self { input, options } =
69 <Self as clap::FromArgMatches>::from_arg_matches_mut(&mut matches)
70 .map_err(format_error::<Self>)
71 .map_err(ClapDiagnostic::from)?;
72
73 let mut options = options.into_options(cwd.into());
74 options.set_extra_flags(compile_matches.into());
75
76 let input = input.unwrap_or_else(|| {
77 InputFile::new(
78 midenc_session::FileType::Toml,
79 midenc_session::InputType::Real(options.current_dir.join("miden-project.toml")),
80 )
81 });
82
83 let session = Rc::new(options.into_session(input, emitter, None)?);
84 let context = Rc::new(Context::new(session));
85 compile::compile(context)
86 }
87}
88
89fn format_error<I: clap::CommandFactory>(err: clap::Error) -> clap::Error {
90 let mut cmd = I::command();
91 err.format(&mut cmd)
92}