midenc_compile/
lib.rs

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/// The compilation pipeline was stopped early
21#[derive(Debug, thiserror::Error, Diagnostic)]
22#[error("compilation was canceled by user")]
23#[diagnostic()]
24pub struct CompilerStopped;
25
26/// Run the compiler using the provided [Session]
27pub 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
58/// Same as `compile`, but return compiled artifacts to the caller
59pub 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
64/// Same as `compile_to_memory`, but allows registering a callback which will be used as an extra
65/// compiler stage immediately after code generation and prior to assembly, if the linker was run.
66pub 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}