solar_cli/commands/
compile.rs1use solar_config::{CompileOpts, CompilerOutput};
2use solar_interface::{Result, Session};
3use solar_sema::{CompilerRef, ParsingContext};
4use std::{ops::ControlFlow, process::ExitCode};
5
6pub(super) fn run(opts: CompileOpts) -> ExitCode {
7 match run_compiler_args(opts) {
8 Ok(()) => ExitCode::SUCCESS,
9 Err(_) => ExitCode::FAILURE,
10 }
11}
12
13pub fn run_compiler_args(opts: CompileOpts) -> Result {
14 if opts.standard_json {
15 crate::standard_json::run(opts)
16 .map_err(|_e| solar_interface::diagnostics::ErrorGuaranteed::new_unchecked())?;
17 return Ok(());
18 }
19
20 run_compiler_with(opts, run_default)
21}
22
23fn run_default(compiler: &mut CompilerRef<'_>) -> Result {
24 run_pipeline(
25 compiler,
26 |pcx| {
27 let mut seen_stdin = false;
32 let mut paths = Vec::new();
33 for arg in pcx.sess.opts.input.clone() {
34 if arg == "-" {
35 if !seen_stdin {
36 pcx.load_stdin()?;
37 }
38 seen_stdin = true;
39 continue;
40 }
41
42 if arg.contains('=') {
43 continue;
44 }
45
46 paths.push(arg);
47 }
48
49 pcx.par_load_files(paths)
50 },
51 |_| {},
52 )
53 .map(|_| ())
54}
55
56pub(crate) fn run_pipeline(
57 compiler: &mut CompilerRef<'_>,
58 load_sources: impl FnOnce(&mut ParsingContext<'_>) -> Result,
59 after_parsing: impl FnOnce(&CompilerRef<'_>),
60) -> Result<ControlFlow<()>> {
61 let sess = compiler.gcx().sess;
62 if sess.opts.language.is_yul() && !sess.opts.unstable.parse_yul {
63 return Err(sess.dcx.err("Yul is not supported yet").emit());
64 }
65
66 let mut pcx = compiler.parse();
67 load_sources(&mut pcx)?;
68 pcx.parse();
69
70 if compiler.gcx().sources.is_empty() {
71 let msg = "no files found";
72 let note = "if you wish to use the standard input, please specify `-` explicitly";
73 return Err(sess.dcx.err(msg).note(note).emit());
74 }
75
76 compiler.sources_mut().topo_sort();
77 after_parsing(compiler);
78
79 let ControlFlow::Continue(()) = compiler.lower_asts()? else {
80 return Ok(ControlFlow::Break(()));
81 };
82 compiler.drop_asts();
83 let ControlFlow::Continue(()) = compiler.analysis()? else {
84 return Ok(ControlFlow::Break(()));
85 };
86
87 let needs_codegen = sess.opts.emit.iter().any(|e| {
90 matches!(e, CompilerOutput::Mir | CompilerOutput::Bin | CompilerOutput::BinRuntime)
91 });
92 if needs_codegen && !sess.opts.unstable.codegen {
93 return Err(sess
94 .dcx
95 .err("code generation is experimental")
96 .help("pass `-Zcodegen` to emit MIR or bytecode")
97 .emit());
98 }
99
100 crate::emit::emit_requested(compiler)?;
101
102 Ok(ControlFlow::Continue(()))
103}
104
105fn run_compiler_with(
106 opts: CompileOpts,
107 f: impl FnOnce(&mut CompilerRef<'_>) -> Result + Send,
108) -> Result {
109 let mut sess = Session::new(opts);
110 sess.infer_language();
111 run_compiler_session_with(sess, f, true)
112}
113
114pub(crate) fn run_compiler_session_with(
115 sess: Session,
116 f: impl FnOnce(&mut CompilerRef<'_>) -> Result + Send,
117 finish: bool,
118) -> Result {
119 sess.validate()?;
120 let mut compiler = solar_sema::Compiler::new(sess);
121 compiler.enter_mut(|compiler| {
122 let mut r = f(compiler);
123 if finish {
124 r = r.and(finish_diagnostics(compiler.gcx().sess));
125 }
126 r
127 })
128}
129
130fn finish_diagnostics(sess: &Session) -> Result {
131 sess.dcx.print_error_count()
132}