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