miden_assembly/
procedure.rs

1use alloc::sync::Arc;
2
3use miden_assembly_syntax::{
4    ast::types::FunctionType,
5    debuginfo::{SourceManager, SourceSpan, Spanned},
6};
7use miden_core::{Word, mast::MastNodeId};
8
9use super::GlobalProcedureIndex;
10use crate::{
11    LibraryPath,
12    ast::{ProcedureName, QualifiedProcedureName, Visibility},
13};
14
15// PROCEDURE CONTEXT
16// ================================================================================================
17
18/// Information about a procedure currently being compiled.
19pub struct ProcedureContext {
20    source_manager: Arc<dyn SourceManager>,
21    gid: GlobalProcedureIndex,
22    span: SourceSpan,
23    name: QualifiedProcedureName,
24    signature: Option<Arc<FunctionType>>,
25    visibility: Visibility,
26    is_kernel: bool,
27    num_locals: u16,
28}
29
30// ------------------------------------------------------------------------------------------------
31/// Constructors
32impl ProcedureContext {
33    pub fn new(
34        gid: GlobalProcedureIndex,
35        name: QualifiedProcedureName,
36        visibility: Visibility,
37        signature: Option<Arc<FunctionType>>,
38        is_kernel: bool,
39        source_manager: Arc<dyn SourceManager>,
40    ) -> Self {
41        Self {
42            source_manager,
43            gid,
44            span: name.span(),
45            name,
46            visibility,
47            signature,
48            is_kernel,
49            num_locals: 0,
50        }
51    }
52
53    /// Sets the number of locals to allocate for the procedure.
54    pub fn with_num_locals(mut self, num_locals: u16) -> Self {
55        self.num_locals = num_locals;
56        self
57    }
58
59    pub fn with_span(mut self, span: SourceSpan) -> Self {
60        self.span = span;
61        self
62    }
63}
64
65// ------------------------------------------------------------------------------------------------
66/// Public accessors
67impl ProcedureContext {
68    pub fn id(&self) -> GlobalProcedureIndex {
69        self.gid
70    }
71
72    pub fn name(&self) -> &QualifiedProcedureName {
73        &self.name
74    }
75
76    pub fn signature(&self) -> Option<Arc<FunctionType>> {
77        self.signature.clone()
78    }
79
80    pub fn set_signature(&mut self, signature: Option<Arc<FunctionType>>) {
81        self.signature = signature;
82    }
83
84    pub fn num_locals(&self) -> u16 {
85        self.num_locals
86    }
87
88    #[allow(unused)]
89    pub fn module(&self) -> &LibraryPath {
90        &self.name.module
91    }
92
93    /// Returns true if the procedure is being assembled for a kernel.
94    pub fn is_kernel(&self) -> bool {
95        self.is_kernel
96    }
97
98    #[inline(always)]
99    pub fn source_manager(&self) -> &dyn SourceManager {
100        self.source_manager.as_ref()
101    }
102}
103
104// ------------------------------------------------------------------------------------------------
105/// State mutators
106impl ProcedureContext {
107    /// Transforms this procedure context into a [Procedure].
108    ///
109    /// The passed-in `mast_root` defines the MAST root of the procedure's body while
110    /// `mast_node_id` specifies the ID of the procedure's body node in the MAST forest in
111    /// which the procedure is defined. Note that if the procedure is re-exported (i.e., the body
112    /// of the procedure is defined in some other MAST forest) `mast_node_id` will point to a
113    /// single `External` node.
114    ///
115    /// <div class="warning">
116    /// `mast_root` and `mast_node_id` must be consistent. That is, the node located in the MAST
117    /// forest under `mast_node_id` must have the digest equal to the `mast_root`.
118    /// </div>
119    pub fn into_procedure(self, mast_root: Word, mast_node_id: MastNodeId) -> Procedure {
120        Procedure::new(
121            self.name,
122            self.visibility,
123            self.signature,
124            self.num_locals as u32,
125            mast_root,
126            mast_node_id,
127        )
128        .with_span(self.span)
129    }
130}
131
132impl Spanned for ProcedureContext {
133    fn span(&self) -> SourceSpan {
134        self.span
135    }
136}
137
138// PROCEDURE
139// ================================================================================================
140
141/// A compiled Miden Assembly procedure, consisting of MAST info and basic metadata.
142///
143/// Procedure metadata includes:
144///
145/// - Fully-qualified path of the procedure in Miden Assembly (if known).
146/// - Number of procedure locals to allocate.
147/// - The visibility of the procedure (e.g. public/private/syscall)
148/// - The set of MAST roots invoked by this procedure.
149/// - The original source span and file of the procedure (if available).
150#[derive(Clone, Debug)]
151pub struct Procedure {
152    span: SourceSpan,
153    path: QualifiedProcedureName,
154    signature: Option<Arc<FunctionType>>,
155    visibility: Visibility,
156    num_locals: u32,
157    /// The MAST root of the procedure.
158    mast_root: Word,
159    /// The MAST node id which resolves to the above MAST root.
160    body_node_id: MastNodeId,
161}
162
163// ------------------------------------------------------------------------------------------------
164/// Constructors
165impl Procedure {
166    fn new(
167        path: QualifiedProcedureName,
168        visibility: Visibility,
169        signature: Option<Arc<FunctionType>>,
170        num_locals: u32,
171        mast_root: Word,
172        body_node_id: MastNodeId,
173    ) -> Self {
174        Self {
175            span: SourceSpan::default(),
176            path,
177            visibility,
178            signature,
179            num_locals,
180            mast_root,
181            body_node_id,
182        }
183    }
184
185    pub(crate) fn with_span(mut self, span: SourceSpan) -> Self {
186        self.span = span;
187        self
188    }
189}
190
191// ------------------------------------------------------------------------------------------------
192/// Public accessors
193impl Procedure {
194    /// Returns a reference to the name of this procedure
195    #[allow(unused)]
196    pub fn name(&self) -> &ProcedureName {
197        &self.path.name
198    }
199
200    /// Returns a reference to the fully-qualified name of this procedure
201    pub fn fully_qualified_name(&self) -> &QualifiedProcedureName {
202        &self.path
203    }
204
205    /// Returns the visibility of this procedure as expressed in the original source code
206    pub fn visibility(&self) -> Visibility {
207        self.visibility
208    }
209
210    /// Returns a reference to the fully-qualified module path of this procedure
211    pub fn path(&self) -> &LibraryPath {
212        &self.path.module
213    }
214
215    /// Returns a reference to the type signature of this procedure
216    pub fn signature(&self) -> Option<Arc<FunctionType>> {
217        self.signature.clone()
218    }
219
220    /// Returns the number of memory locals reserved by the procedure.
221    pub fn num_locals(&self) -> u32 {
222        self.num_locals
223    }
224
225    /// Returns the root of this procedure's MAST.
226    pub fn mast_root(&self) -> Word {
227        self.mast_root
228    }
229
230    /// Returns a reference to the MAST node ID of this procedure.
231    pub fn body_node_id(&self) -> MastNodeId {
232        self.body_node_id
233    }
234}
235
236impl Spanned for Procedure {
237    fn span(&self) -> SourceSpan {
238        self.span
239    }
240}