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}