1mod compiler;
2mod stage;
3mod stages;
4
5use std::rc::Rc;
6
7use either::Either::{self, Left, Right};
8use midenc_codegen_masm::{self as masm, MasmArtifact};
9use midenc_hir::{
10 diagnostics::{miette, Diagnostic, IntoDiagnostic, Report, WrapErr},
11 pass::AnalysisManager,
12};
13use midenc_session::{OutputMode, Session};
14
15pub use self::compiler::Compiler;
16use self::{stage::Stage, stages::*};
17
18pub type CompilerResult<T> = Result<T, Report>;
19
20#[derive(Debug, thiserror::Error, Diagnostic)]
22#[error("compilation was canceled by user")]
23#[diagnostic()]
24pub struct CompilerStopped;
25
26pub fn compile(session: Rc<Session>) -> CompilerResult<()> {
28 use midenc_hir::formatter::DisplayHex;
29 let mut analyses = AnalysisManager::new();
30 log::info!("starting compilation session");
31 match compile_inputs(session.inputs.clone(), &mut analyses, &session)? {
32 Artifact::Assembled(ref mast) => {
33 log::info!(
34 "succesfully assembled mast package '{}' with digest {}",
35 mast.name,
36 DisplayHex::new(&mast.digest.as_bytes())
37 );
38 session
39 .emit(OutputMode::Text, mast)
40 .into_diagnostic()
41 .wrap_err("failed to pretty print 'mast' artifact")?;
42 session
43 .emit(OutputMode::Binary, mast)
44 .into_diagnostic()
45 .wrap_err("failed to serialize 'mast' artifact")
46 }
47 Artifact::Linked(_) => {
48 log::debug!("no outputs requested by user: pipeline stopped after linking");
49 Ok(())
50 }
51 Artifact::Lowered(_) => {
52 log::debug!("no outputs requested by user: pipeline stopped before linking");
53 Ok(())
54 }
55 }
56}
57
58pub fn compile_to_memory(session: Rc<Session>) -> CompilerResult<Artifact> {
60 let mut analyses = AnalysisManager::new();
61 compile_inputs(session.inputs.clone(), &mut analyses, &session)
62}
63
64pub fn compile_to_memory_with_pre_assembly_stage<F>(
67 session: Rc<Session>,
68 stage: &mut F,
69) -> CompilerResult<Artifact>
70where
71 F: FnMut(MasmArtifact, &mut AnalysisManager, &Session) -> CompilerResult<MasmArtifact>,
72{
73 type AssemblyInput = Either<MasmArtifact, masm::ModuleTree>;
74
75 let mut analyses = AnalysisManager::new();
76
77 let mut pre_assembly_stage = move |output: AssemblyInput,
78 analysis: &mut AnalysisManager,
79 session: &Session| {
80 match output {
81 Left(artifact) => stage(artifact, analysis, session).map(Left),
82 right @ Right(_) => Ok(right),
83 }
84 };
85 let mut stages = ParseStage
86 .next(SemanticAnalysisStage)
87 .next_optional(ApplyRewritesStage)
88 .collect(LinkerStage)
89 .next(CodegenStage)
90 .next(
91 &mut pre_assembly_stage
92 as &mut (dyn FnMut(
93 AssemblyInput,
94 &mut AnalysisManager,
95 &Session,
96 ) -> CompilerResult<AssemblyInput>
97 + '_),
98 )
99 .next(AssembleStage);
100
101 stages.run(session.inputs.clone(), &mut analyses, &session)
102}
103
104fn compile_inputs(
105 inputs: Vec<midenc_session::InputFile>,
106 analyses: &mut AnalysisManager,
107 session: &Session,
108) -> CompilerResult<Artifact> {
109 let mut stages = ParseStage
110 .next(SemanticAnalysisStage)
111 .next_optional(ApplyRewritesStage)
112 .collect(LinkerStage)
113 .next(CodegenStage)
114 .next(AssembleStage);
115
116 stages.run(inputs, analyses, session)
117}