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 function compiled for a HIR function item: its parameters are
124    /// `dyn` (a by-reference parameter is a `ref cell dyn` holding an LSB
125    /// reference), followed by an `i64` presence mask when any parameter has
126    /// a default; it returns `dyn` (a generator's returns its coroutine). It
127    /// carries the item's LSB parameter list, so it can be called typed
128    /// (`call`, `Vm::run`) or bound dynamically. Root-level functions are
129    /// exported under their names.
130    ///
131    /// # Examples
132    ///
133    /// See [`Compiled`].
134    #[must_use]
135    pub fn function(&self, item: ItemId) -> Option<FuncId> {
136        self.functions
137            .iter()
138            .find(|(i, _)| *i == item)
139            .map(|&(_, f)| f)
140    }
141
142    /// The HIR node instruction `pc` of `func` was compiled from.
143    ///
144    /// # Examples
145    ///
146    /// See [`Compiled`].
147    #[must_use]
148    pub fn origin(&self, func: FuncId, pc: u32) -> Option<NodeRef> {
149        self.origins
150            .get(func.index())
151            .and_then(|o| o.get(pc as usize))
152            .copied()
153    }
154
155    /// The HIR node of every instruction of `func`, indexed by pc.
156    ///
157    /// # Examples
158    ///
159    /// ```
160    /// let hir = { let mut b = hir_lang::Builder::new(); let r = b.module(None, &[]); b.finish(r)? };
161    /// let out = bcgen_lang::compile(&hir, &intern_lang::Interner::new())?;
162    /// assert_eq!(out.origins(out.entry()).len(), out.module().function(out.entry()).unwrap().code().len());
163    /// # Ok::<(), Box<dyn std::error::Error>>(())
164    /// ```
165    #[must_use]
166    pub fn origins(&self, func: FuncId) -> &[NodeRef] {
167        self.origins.get(func.index()).map_or(&[], Vec::as_slice)
168    }
169}