Skip to main content

miden_assembly_syntax/library/
module.rs

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