Skip to main content

bcgen_lang/
output.rs

1//! The result of compiling a unit.
2
3use alloc::vec::Vec;
4
5use bytecode_lang::{FuncId, GlobalId, Module};
6use hir_lang::{ItemId, NodeRef};
7
8/// A compiled unit: the LSB module, its entry points, and the map from every
9/// instruction back to the HIR node it was compiled from.
10///
11/// # Examples
12///
13/// ```
14/// use hir_lang::{Builder, Name};
15/// use intern_lang::Interner;
16///
17/// let mut names = Interner::new();
18/// let mut b = Builder::new();
19/// let one = b.int(1);
20/// let body = b.block(&[], Some(one));
21/// let f = b.func(Name::new(names.intern("one")), &[], body);
22/// let root = b.module(None, &[f]);
23/// let hir = b.finish(root)?;
24///
25/// let out = bcgen_lang::compile(&hir, &names)?;
26/// let func = out.function(f).unwrap();
27/// // Every instruction maps back to a node of the unit.
28/// for pc in 0..out.module().function(func).unwrap().code().len() {
29///     assert!(out.origin(func, pc as u32).is_some());
30/// }
31/// # Ok::<(), Box<dyn std::error::Error>>(())
32/// ```
33#[derive(Clone, Debug, PartialEq, Eq)]
34pub struct Compiled {
35    pub(crate) module: Module,
36    pub(crate) entry: FuncId,
37    pub(crate) start: Option<FuncId>,
38    pub(crate) result: Option<GlobalId>,
39    pub(crate) functions: Vec<(ItemId, FuncId)>,
40    pub(crate) origins: Vec<Vec<NodeRef>>,
41}
42
43impl Compiled {
44    /// The LSB module.
45    ///
46    /// # Examples
47    ///
48    /// ```
49    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
50    /// let out = bcgen_lang::compile(&hir, &intern_lang::Interner::new())?;
51    /// assert_eq!(out.module().functions().len(), 1); // the entry
52    /// # Ok::<(), Box<dyn std::error::Error>>(())
53    /// ```
54    #[must_use]
55    pub fn module(&self) -> &Module {
56        &self.module
57    }
58
59    /// The LSB module, by value (to hand to a VM or an encoder).
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
65    /// let module = bcgen_lang::compile(&hir, &intern_lang::Interner::new())?.into_module();
66    /// assert!(!bytecode_lang::encode(&module).is_empty());
67    /// # Ok::<(), Box<dyn std::error::Error>>(())
68    /// ```
69    #[must_use]
70    pub fn into_module(self) -> Module {
71        self.module
72    }
73
74    /// The entry function, `() -> dyn`, exported as `<entry>`: it returns the
75    /// value of the module body (nil without one). Under
76    /// [`BodyMode::Start`](crate::BodyMode::Start) the body runs once, in the
77    /// start function, and the entry reads its kept value; under
78    /// [`BodyMode::Entry`](crate::BodyMode::Entry) the entry is the body.
79    ///
80    /// # Examples
81    ///
82    /// ```
83    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
84    /// let out = bcgen_lang::compile(&hir, &intern_lang::Interner::new())?;
85    /// assert!(out.module().function(out.entry()).is_some());
86    /// # Ok::<(), Box<dyn std::error::Error>>(())
87    /// ```
88    #[must_use]
89    pub fn entry(&self) -> FuncId {
90        self.entry
91    }
92
93    /// The module's start function, if it has one: global and constant
94    /// initializers, defaults evaluated once, and (under `BodyMode::Start`)
95    /// the body.
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
101    /// assert_eq!(bcgen_lang::compile(&hir, &intern_lang::Interner::new())?.start(), None);
102    /// # Ok::<(), Box<dyn std::error::Error>>(())
103    /// ```
104    #[must_use]
105    pub fn start(&self) -> Option<FuncId> {
106        self.start
107    }
108
109    /// The global holding the module body's value under `BodyMode::Start`.
110    ///
111    /// # Examples
112    ///
113    /// ```
114    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
115    /// assert!(bcgen_lang::compile(&hir, &intern_lang::Interner::new())?.result_global().is_none());
116    /// # Ok::<(), Box<dyn std::error::Error>>(())
117    /// ```
118    #[must_use]
119    pub fn result_global(&self) -> Option<GlobalId> {
120        self.result
121    }
122
123    /// The direct-call function compiled for a HIR function item: its
124    /// parameters are `dyn` (a by-reference parameter is a cell), followed by
125    /// an `i64` presence mask when any parameter has a default; it returns
126    /// `dyn`. Root-level functions are exported under their names.
127    ///
128    /// # Examples
129    ///
130    /// See [`Compiled`].
131    #[must_use]
132    pub fn function(&self, item: ItemId) -> Option<FuncId> {
133        self.functions
134            .iter()
135            .find(|(i, _)| *i == item)
136            .map(|&(_, f)| f)
137    }
138
139    /// The HIR node instruction `pc` of `func` was compiled from.
140    ///
141    /// # Examples
142    ///
143    /// See [`Compiled`].
144    #[must_use]
145    pub fn origin(&self, func: FuncId, pc: u32) -> Option<NodeRef> {
146        self.origins
147            .get(func.index())
148            .and_then(|o| o.get(pc as usize))
149            .copied()
150    }
151
152    /// The HIR node of every instruction of `func`, indexed by pc.
153    ///
154    /// # Examples
155    ///
156    /// ```
157    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
158    /// let out = bcgen_lang::compile(&hir, &intern_lang::Interner::new())?;
159    /// assert_eq!(out.origins(out.entry()).len(), out.module().function(out.entry()).unwrap().code().len());
160    /// # Ok::<(), Box<dyn std::error::Error>>(())
161    /// ```
162    #[must_use]
163    pub fn origins(&self, func: FuncId) -> &[NodeRef] {
164        self.origins.get(func.index()).map_or(&[], Vec::as_slice)
165    }
166}