Skip to main content

miden_assembly_syntax/ast/item/
items.rs

1use alloc::string::String;
2
3use crate::{
4    ast::{AttributeSet, Constant, FunctionType, Ident, Invoke, Procedure, TypeDecl, Visibility},
5    debuginfo::{SourceSpan, Span, Spanned},
6};
7
8// MODULE ITEM
9// ================================================================================================
10
11/// Represents an exportable item from a [crate::ast::Module].
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Item {
14    /// A locally-defined procedure.
15    Procedure(Procedure),
16    /// A locally-defined constant.
17    Constant(Constant),
18    /// A locally-defined type.
19    Type(TypeDecl),
20}
21
22impl Item {
23    /// Adds documentation to this export.
24    pub fn with_docs(self, docs: Option<Span<String>>) -> Self {
25        match self {
26            Self::Procedure(item) => Self::Procedure(item.with_docs(docs)),
27            Self::Constant(item) => Self::Constant(item.with_docs(docs)),
28            Self::Type(item) => Self::Type(item.with_docs(docs)),
29        }
30    }
31
32    /// Returns the name of the exported procedure.
33    pub fn name(&self) -> &Ident {
34        match self {
35            Self::Procedure(item) => item.name().as_ref(),
36            Self::Constant(item) => &item.name,
37            Self::Type(item) => item.name(),
38        }
39    }
40
41    /// Returns the documentation for this item.
42    pub fn docs(&self) -> Option<&str> {
43        match self {
44            Self::Procedure(item) => item.docs().map(Span::into_inner),
45            Self::Constant(item) => item.docs().map(Span::into_inner),
46            Self::Type(item) => item.docs().map(Span::into_inner),
47        }
48    }
49
50    /// Returns the attributes for this item, if it is a procedure.
51    pub fn attributes(&self) -> Option<&AttributeSet> {
52        match self {
53            Self::Procedure(proc) => Some(proc.attributes()),
54            Self::Constant(_) | Self::Type(_) => None,
55        }
56    }
57
58    /// Returns the visibility of this item (e.g. public or private).
59    ///
60    /// See [Visibility] for more details on what visibilities are supported.
61    pub fn visibility(&self) -> Visibility {
62        match self {
63            Self::Procedure(item) => item.visibility(),
64            Self::Constant(item) => item.visibility,
65            Self::Type(item) => item.visibility(),
66        }
67    }
68
69    /// Returns a reference to the type signature of this item, if it is a procedure, and known.
70    pub fn signature(&self) -> Option<&FunctionType> {
71        match self {
72            Self::Procedure(item) => item.signature(),
73            Self::Constant(_) | Self::Type(_) => None,
74        }
75    }
76
77    /// Returns the number of automatically-allocated words of memory this item requires
78    /// for the storage of temporaries/local variables.
79    ///
80    /// NOTE: This is only applicable for procedure items - the value 0 will be returned if this
81    /// is a non-procedure item, or if the type of item is not yet known.
82    pub fn num_locals(&self) -> usize {
83        match self {
84            Self::Procedure(proc) => proc.num_locals() as usize,
85            Self::Constant(_) | Self::Type(_) => 0,
86        }
87    }
88
89    /// Returns true if this procedure is the program entrypoint.
90    pub fn is_main(&self) -> bool {
91        self.name().as_str() == Ident::MAIN
92    }
93
94    /// Unwraps this [Item] as a [Procedure], or panic.
95    #[track_caller]
96    pub fn unwrap_procedure(&self) -> &Procedure {
97        match self {
98            Self::Procedure(item) => item,
99            Self::Constant(_) => panic!("attempted to unwrap constant as procedure definition"),
100            Self::Type(_) => panic!("attempted to unwrap type as procedure definition"),
101        }
102    }
103
104    /// Get an iterator over the set of other procedures invoked from this procedure.
105    ///
106    /// NOTE: This only applies to [Procedure]s, other types currently return an empty
107    /// iterator whenever called.
108    pub fn invoked<'a, 'b: 'a>(&'b self) -> impl Iterator<Item = &'a Invoke> + 'a {
109        use crate::ast::procedure::InvokedIter;
110
111        match self {
112            Self::Procedure(item) if item.invoked.is_empty() => InvokedIter::Empty,
113            Self::Procedure(item) => InvokedIter::NonEmpty(item.invoked.iter()),
114            Self::Constant(_) | Self::Type(_) => InvokedIter::Empty,
115        }
116    }
117}
118
119impl crate::prettier::PrettyPrint for Item {
120    fn render(&self) -> crate::prettier::Document {
121        match self {
122            Self::Procedure(item) => item.render(),
123            Self::Constant(item) => item.render(),
124            Self::Type(item) => item.render(),
125        }
126    }
127}
128
129impl Spanned for Item {
130    fn span(&self) -> SourceSpan {
131        match self {
132            Self::Procedure(spanned) => spanned.span(),
133            Self::Constant(spanned) => spanned.span(),
134            Self::Type(spanned) => spanned.span(),
135        }
136    }
137}