solar_cli/
lib.rs

1#![doc = include_str!("../README.md")]
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/solar/main/assets/logo.png",
4    html_favicon_url = "https://raw.githubusercontent.com/paradigmxyz/solar/main/assets/favicon.ico"
5)]
6#![cfg_attr(docsrs, feature(doc_cfg))]
7
8use clap::Parser as _;
9use solar_interface::{Result, Session};
10use solar_sema::CompilerRef;
11use std::ops::ControlFlow;
12
13pub use solar_config::{self as config, Opts, UnstableOpts, version};
14
15pub mod utils;
16
17#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
18pub mod signal_handler;
19
20/// Signal handler to extract a backtrace from stack overflow.
21///
22/// This is a no-op because this platform doesn't support our signal handler's requirements.
23#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
24pub mod signal_handler {
25    #[cfg(unix)]
26    use libc as _;
27
28    /// No-op function.
29    pub fn install() {}
30}
31
32// `asm` feature.
33use alloy_primitives as _;
34
35use tracing as _;
36
37pub fn parse_args<I, T>(itr: I) -> Result<Opts, clap::Error>
38where
39    I: IntoIterator<Item = T>,
40    T: Into<std::ffi::OsString> + Clone,
41{
42    let mut opts = Opts::try_parse_from(itr)?;
43    opts.finish()?;
44    Ok(opts)
45}
46
47pub fn run_compiler_args(opts: Opts) -> Result {
48    run_compiler_with(opts, run_default)
49}
50
51fn run_default(compiler: &mut CompilerRef<'_>) -> Result {
52    let sess = compiler.gcx().sess;
53    if sess.opts.language.is_yul() && !sess.opts.unstable.parse_yul {
54        return Err(sess.dcx.err("Yul is not supported yet").emit());
55    }
56
57    let mut pcx = compiler.parse();
58
59    // Partition arguments into three categories:
60    // - `stdin`: `-`, occurrences after the first are ignored
61    // - remappings: `[context:]prefix=path`, already parsed as part of `Opts`
62    // - paths: everything else
63    let mut seen_stdin = false;
64    let mut paths = Vec::new();
65    for arg in sess.opts.input.iter().map(String::as_str) {
66        if arg == "-" {
67            if !seen_stdin {
68                pcx.load_stdin()?;
69            }
70            seen_stdin = true;
71            continue;
72        }
73
74        if arg.contains('=') {
75            continue;
76        }
77
78        paths.push(arg);
79    }
80
81    pcx.par_load_files(paths)?;
82
83    pcx.parse();
84    let ControlFlow::Continue(()) = compiler.lower_asts()? else { return Ok(()) };
85    compiler.drop_asts();
86    let ControlFlow::Continue(()) = compiler.analysis()? else { return Ok(()) };
87
88    Ok(())
89}
90
91fn run_compiler_with(opts: Opts, f: impl FnOnce(&mut CompilerRef<'_>) -> Result + Send) -> Result {
92    let mut sess = Session::new(opts);
93    sess.infer_language();
94    sess.validate()?;
95
96    let mut compiler = solar_sema::Compiler::new(sess);
97    compiler.enter_mut(|compiler| {
98        let mut r = f(compiler);
99        r = r.and(finish_diagnostics(compiler.gcx().sess));
100        r
101    })
102}
103
104fn finish_diagnostics(sess: &Session) -> Result {
105    sess.dcx.print_error_count()
106}