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}