Skip to main content

miden_assembly_syntax/library/
module.rs

1use alloc::{sync::Arc, vec::Vec};
2use core::ops::Index;
3
4use miden_core::mast::MastNodeId;
5use midenc_hir_type::FunctionType;
6
7use crate::{
8    Path, Word,
9    ast::{self, AttributeSet, ConstantValue, Ident, ItemIndex, ProcedureName},
10};
11
12// MODULE INFO
13// ================================================================================================
14
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct ModuleInfo {
17    path: Arc<Path>,
18    /// When specified, multiple modules with the same name can be present, so long as they are
19    /// disambiguated by version.
20    version: Option<crate::Version>,
21    items: Vec<ItemInfo>,
22}
23
24impl ModuleInfo {
25    pub(crate) fn raw_items(&self) -> &[ItemInfo] {
26        &self.items
27    }
28
29    /// Returns a new [`ModuleInfo`] instantiated by library path and optional semantic version.
30    ///
31    /// The semantic version is optional, as currently the assembler allows assembling artifacts
32    /// without providing one.
33    pub fn new(path: Arc<Path>, version: Option<crate::Version>) -> Self {
34        Self { version, path, items: Vec::new() }
35    }
36
37    /// Specify the version of this module
38    pub fn set_version(&mut self, version: crate::Version) {
39        self.version = Some(version);
40    }
41
42    /// Adds a procedure to the module.
43    pub fn add_procedure(
44        &mut self,
45        name: ProcedureName,
46        digest: Word,
47        signature: Option<Arc<FunctionType>>,
48        attributes: AttributeSet,
49    ) {
50        self.add_procedure_with_provenance(name, digest, signature, attributes, None, None);
51    }
52
53    /// Adds a procedure to the module with optional source provenance.
54    pub fn add_procedure_with_provenance(
55        &mut self,
56        name: ProcedureName,
57        digest: Word,
58        signature: Option<Arc<FunctionType>>,
59        attributes: AttributeSet,
60        source_root_id: Option<MastNodeId>,
61        source_library_commitment: Option<Word>,
62    ) {
63        self.items.push(ItemInfo::Procedure(ProcedureInfo {
64            name,
65            digest,
66            signature,
67            attributes,
68            source_root_id,
69            source_library_commitment,
70        }));
71    }
72
73    /// Adds a constant to the module.
74    pub fn add_constant(&mut self, name: Ident, value: ConstantValue) {
75        self.items.push(ItemInfo::Constant(ConstantInfo { name, value }));
76    }
77
78    /// Adds a type declaration to the module.
79    pub fn add_type(&mut self, name: Ident, ty: ast::types::Type) {
80        self.items.push(ItemInfo::Type(TypeInfo { name, ty }));
81    }
82
83    /// Returns the module's library path.
84    pub fn path(&self) -> &Path {
85        &self.path
86    }
87
88    /// Returns the number of procedures in the module.
89    pub fn num_procedures(&self) -> usize {
90        self.items.iter().filter(|item| matches!(item, ItemInfo::Procedure(_))).count()
91    }
92
93    /// Returns the [`ItemInfo`] of the item at the provided index, if any.
94    pub fn get_item_by_index(&self, index: ItemIndex) -> Option<&ItemInfo> {
95        self.items.get(index.as_usize())
96    }
97
98    /// Returns the [ItemIndex] of an item by its local name
99    pub fn get_item_index_by_name(&self, name: &str) -> Option<ItemIndex> {
100        self.items.iter().enumerate().find_map(|(idx, info)| {
101            if info.name().as_str() == name {
102                Some(ItemIndex::new(idx))
103            } else {
104                None
105            }
106        })
107    }
108
109    /// Returns the procedure info for the procedure with the provided name, if any.
110    pub fn get_procedure_by_name(&self, name: &str) -> Option<&ProcedureInfo> {
111        self.items.iter().find_map(|info| match info {
112            ItemInfo::Procedure(proc) if proc.name.as_str() == name => Some(proc),
113            _ => None,
114        })
115    }
116
117    /// Returns the digest of the procedure with the provided name, if any.
118    pub fn get_procedure_digest_by_name(&self, name: &str) -> Option<Word> {
119        self.get_procedure_by_name(name).map(|proc| proc.digest)
120    }
121
122    /// Returns an iterator over the items in the module with their corresponding item index in the
123    /// module.
124    pub fn items(&self) -> impl ExactSizeIterator<Item = (ItemIndex, &ItemInfo)> {
125        self.items.iter().enumerate().map(|(idx, item)| (ItemIndex::new(idx), item))
126    }
127
128    /// Returns an iterator over the procedure infos in the module with their corresponding
129    /// item index in the module.
130    pub fn procedures(&self) -> impl Iterator<Item = (ItemIndex, &ProcedureInfo)> {
131        self.items.iter().enumerate().filter_map(|(idx, item)| match item {
132            ItemInfo::Procedure(proc) => Some((ItemIndex::new(idx), proc)),
133            _ => None,
134        })
135    }
136
137    /// Returns an iterator over the MAST roots of procedures defined in this module.
138    pub fn procedure_digests(&self) -> impl Iterator<Item = Word> + '_ {
139        self.items.iter().filter_map(|item| match item {
140            ItemInfo::Procedure(proc) => Some(proc.digest),
141            _ => None,
142        })
143    }
144
145    /// Access the constants associated with this module
146    pub fn constants(&self) -> impl Iterator<Item = (ItemIndex, &ConstantInfo)> {
147        self.items.iter().enumerate().filter_map(|(idx, item)| match item {
148            ItemInfo::Constant(info) => Some((ItemIndex::new(idx), info)),
149            _ => None,
150        })
151    }
152
153    /// Access the type declarations associated with this module
154    pub fn types(&self) -> impl Iterator<Item = (ItemIndex, &TypeInfo)> {
155        self.items.iter().enumerate().filter_map(|(idx, item)| match item {
156            ItemInfo::Type(info) => Some((ItemIndex::new(idx), info)),
157            _ => None,
158        })
159    }
160}
161
162impl Index<ItemIndex> for ModuleInfo {
163    type Output = ItemInfo;
164
165    fn index(&self, index: ItemIndex) -> &Self::Output {
166        &self.items[index.as_usize()]
167    }
168}
169
170/// Stores information about an item
171#[derive(Debug, Clone, PartialEq, Eq)]
172pub enum ItemInfo {
173    Procedure(ProcedureInfo),
174    Constant(ConstantInfo),
175    Type(TypeInfo),
176}
177
178impl ItemInfo {
179    pub fn name(&self) -> &Ident {
180        match self {
181            Self::Procedure(info) => info.name.as_ref(),
182            Self::Constant(info) => &info.name,
183            Self::Type(info) => &info.name,
184        }
185    }
186
187    pub fn attributes(&self) -> Option<&AttributeSet> {
188        match self {
189            Self::Procedure(info) => Some(&info.attributes),
190            Self::Constant(_) | Self::Type(_) => None,
191        }
192    }
193
194    pub fn unwrap_procedure(&self) -> &ProcedureInfo {
195        match self {
196            Self::Procedure(info) => info,
197            Self::Constant(_) | Self::Type(_) => panic!("expected item to be a procedure"),
198        }
199    }
200}
201
202/// Stores the name and digest of a procedure.
203#[derive(Debug, Clone, PartialEq, Eq)]
204pub struct ProcedureInfo {
205    pub name: ProcedureName,
206    pub digest: Word,
207    pub signature: Option<Arc<FunctionType>>,
208    pub attributes: AttributeSet,
209    /// The exact procedure root in the source library, if known.
210    ///
211    /// This is needed when multiple exported procedures share the same digest but carry different
212    /// diagnostics metadata.
213    pub source_root_id: Option<MastNodeId>,
214    /// The commitment of the source library forest that `source_root_id` belongs to, if known.
215    pub source_library_commitment: Option<Word>,
216}
217
218impl ProcedureInfo {
219    pub fn source_root_id(&self) -> Option<MastNodeId> {
220        self.source_root_id
221    }
222
223    pub fn source_library_commitment(&self) -> Option<Word> {
224        self.source_library_commitment
225    }
226}
227
228/// Stores the name and value of a constant
229#[derive(Debug, Clone, PartialEq, Eq)]
230pub struct ConstantInfo {
231    pub name: Ident,
232    pub value: ConstantValue,
233}
234
235/// Stores the name and concrete type of a type declaration
236#[derive(Debug, Clone, PartialEq, Eq)]
237pub struct TypeInfo {
238    pub name: Ident,
239    pub ty: ast::types::Type,
240}