Skip to main content

midenc_driver/
midenc.rs

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/// This struct provides the command-line interface used by `midenc`
15#[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    /// The input file to compile
26    ///
27    /// You may specify `-` to read from stdin, otherwise you must provide a path
28    #[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}