use solar_config::{CompileOpts, CompilerOutput};
use solar_interface::{Result, Session};
use solar_sema::{CompilerRef, ParsingContext};
use std::{ops::ControlFlow, process::ExitCode};
pub(super) fn run(opts: CompileOpts) -> ExitCode {
match run_compiler_args(opts) {
Ok(()) => ExitCode::SUCCESS,
Err(_) => ExitCode::FAILURE,
}
}
pub fn run_compiler_args(opts: CompileOpts) -> Result {
if opts.standard_json {
crate::standard_json::run(opts)
.map_err(|_e| solar_interface::diagnostics::ErrorGuaranteed::new_unchecked())?;
return Ok(());
}
run_compiler_with(opts, run_default)
}
fn run_default(compiler: &mut CompilerRef<'_>) -> Result {
run_pipeline(
compiler,
|pcx| {
let mut seen_stdin = false;
let mut paths = Vec::new();
for arg in pcx.sess.opts.input.clone() {
if arg == "-" {
if !seen_stdin {
pcx.load_stdin()?;
}
seen_stdin = true;
continue;
}
if arg.contains('=') {
continue;
}
paths.push(arg);
}
pcx.par_load_files(paths)
},
|_| {},
)
.map(|_| ())
}
pub(crate) fn run_pipeline(
compiler: &mut CompilerRef<'_>,
load_sources: impl FnOnce(&mut ParsingContext<'_>) -> Result,
after_parsing: impl FnOnce(&CompilerRef<'_>),
) -> Result<ControlFlow<()>> {
let sess = compiler.gcx().sess;
if sess.opts.language.is_yul() && !sess.opts.unstable.parse_yul {
return Err(sess.dcx.err("Yul is not supported yet").emit());
}
let mut pcx = compiler.parse();
load_sources(&mut pcx)?;
pcx.parse();
if compiler.gcx().sources.is_empty() {
let msg = "no files found";
let note = "if you wish to use the standard input, please specify `-` explicitly";
return Err(sess.dcx.err(msg).note(note).emit());
}
compiler.sources_mut().topo_sort();
after_parsing(compiler);
let ControlFlow::Continue(()) = compiler.lower_asts()? else {
return Ok(ControlFlow::Break(()));
};
compiler.drop_asts();
let ControlFlow::Continue(()) = compiler.analysis()? else {
return Ok(ControlFlow::Break(()));
};
let needs_codegen = sess.opts.emit.iter().any(|e| {
matches!(e, CompilerOutput::Mir | CompilerOutput::Bin | CompilerOutput::BinRuntime)
});
if needs_codegen && !sess.opts.unstable.codegen {
return Err(sess
.dcx
.err("code generation is experimental")
.help("pass `-Zcodegen` to emit MIR or bytecode")
.emit());
}
crate::emit::emit_requested(compiler)?;
Ok(ControlFlow::Continue(()))
}
fn run_compiler_with(
opts: CompileOpts,
f: impl FnOnce(&mut CompilerRef<'_>) -> Result + Send,
) -> Result {
let mut sess = Session::new(opts);
sess.infer_language();
run_compiler_session_with(sess, f, true)
}
pub(crate) fn run_compiler_session_with(
sess: Session,
f: impl FnOnce(&mut CompilerRef<'_>) -> Result + Send,
finish: bool,
) -> Result {
sess.validate()?;
let mut compiler = solar_sema::Compiler::new(sess);
compiler.enter_mut(|compiler| {
let mut r = f(compiler);
if finish {
r = r.and(finish_diagnostics(compiler.gcx().sess));
}
r
})
}
fn finish_diagnostics(sess: &Session) -> Result {
sess.dcx.print_error_count()
}