miden_assembly/
procedure.rs

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