1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use miden_assembly::Library as CompiledLibrary;
use midenc_hir::Symbol;
use midenc_session::{diagnostics::Report, Emit, OutputMode, OutputType, Session};

use crate::{Library, MastArtifact, Module, Program};

/// The artifact produced by lowering an [hir::Program] to Miden Assembly
///
/// This type is used in compilation pipelines to abstract over the type of output requested.
pub enum MasmArtifact {
    /// An executable program, with a defined entrypoint
    Executable(Box<Program>),
    /// A library, linkable into a program as needed
    Library(Box<Library>),
}

impl MasmArtifact {
    pub fn assemble(&self, session: &Session) -> Result<MastArtifact, Report> {
        match self {
            Self::Executable(program) => program.assemble(session).map(MastArtifact::Executable),
            Self::Library(library) => library.assemble(session).map(MastArtifact::Library),
        }
    }

    /// Get an iterator over the modules in this library
    pub fn modules(&self) -> impl Iterator<Item = &Module> + '_ {
        match self {
            Self::Executable(ref program) => program.library().modules(),
            Self::Library(ref lib) => lib.modules(),
        }
    }

    pub fn insert(&mut self, module: Box<Module>) {
        match self {
            Self::Executable(ref mut program) => program.insert(module),
            Self::Library(ref mut lib) => lib.insert(module),
        }
    }

    pub fn link_library(&mut self, lib: CompiledLibrary) {
        match self {
            Self::Executable(ref mut program) => program.link_library(lib),
            Self::Library(ref mut library) => library.link_library(lib),
        }
    }

    pub fn unwrap_executable(self) -> Box<Program> {
        match self {
            Self::Executable(program) => program,
            Self::Library(_) => panic!("tried to unwrap a mast library as an executable"),
        }
    }
}

impl Emit for MasmArtifact {
    fn name(&self) -> Option<Symbol> {
        None
    }

    fn output_type(&self, _mode: OutputMode) -> OutputType {
        OutputType::Masm
    }

    fn write_to<W: std::io::Write>(
        &self,
        writer: W,
        mode: OutputMode,
        session: &Session,
    ) -> std::io::Result<()> {
        match self {
            Self::Executable(ref prog) => prog.write_to(writer, mode, session),
            Self::Library(ref lib) => lib.write_to(writer, mode, session),
        }
    }
}