miden_assembly_syntax/ast/attribute/
meta.rs

1mod expr;
2mod kv;
3mod list;
4
5use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
6use core::fmt;
7
8use miden_debug_types::{SourceSpan, Span};
9
10pub use self::{expr::MetaExpr, kv::MetaKeyValue, list::MetaList};
11use crate::{Felt, ast::Ident, parser::WordValue};
12
13/// Represents the metadata provided as arguments to an attribute.
14#[derive(Clone, PartialEq, Eq)]
15pub enum Meta {
16    /// Represents empty metadata, e.g. `@foo`
17    Unit,
18    /// A list of metadata expressions, e.g. `@foo(a, "some text", 0x01)`
19    ///
20    /// The list should always have at least one element, and this is guaranteed by the parser.
21    List(Vec<MetaExpr>),
22    /// A set of uniquely-named metadata expressions, e.g. `@foo(letter = a, text = "some text")`
23    ///
24    /// The set should always have at least one key-value pair, and this is guaranteed by the
25    /// parser.
26    KeyValue(BTreeMap<Ident, MetaExpr>),
27}
28impl Meta {
29    /// Borrow the metadata without unwrapping the specific type
30    ///
31    /// Returns `None` if there is no meaningful metadata
32    #[inline]
33    pub fn borrow(&self) -> Option<BorrowedMeta<'_>> {
34        match self {
35            Self::Unit => None,
36            Self::List(list) => Some(BorrowedMeta::List(list)),
37            Self::KeyValue(kv) => Some(BorrowedMeta::KeyValue(kv)),
38        }
39    }
40}
41impl FromIterator<MetaItem> for Meta {
42    #[inline]
43    fn from_iter<T: IntoIterator<Item = MetaItem>>(iter: T) -> Self {
44        let mut iter = iter.into_iter();
45        match iter.next() {
46            None => Self::Unit,
47            Some(MetaItem::Expr(expr)) => Self::List(
48                core::iter::once(expr)
49                    .chain(iter.map(|item| match item {
50                        MetaItem::Expr(expr) => expr,
51                        MetaItem::KeyValue(..) => unsafe { core::hint::unreachable_unchecked() },
52                    }))
53                    .collect(),
54            ),
55            Some(MetaItem::KeyValue(k, v)) => Self::KeyValue(
56                core::iter::once((k, v))
57                    .chain(iter.map(|item| match item {
58                        MetaItem::KeyValue(k, v) => (k, v),
59                        MetaItem::Expr(_) => unsafe { core::hint::unreachable_unchecked() },
60                    }))
61                    .collect(),
62            ),
63        }
64    }
65}
66
67impl FromIterator<MetaExpr> for Meta {
68    #[inline]
69    fn from_iter<T: IntoIterator<Item = MetaExpr>>(iter: T) -> Self {
70        Self::List(iter.into_iter().collect())
71    }
72}
73
74impl FromIterator<(Ident, MetaExpr)> for Meta {
75    #[inline]
76    fn from_iter<T: IntoIterator<Item = (Ident, MetaExpr)>>(iter: T) -> Self {
77        Self::KeyValue(iter.into_iter().collect())
78    }
79}
80
81impl<'a> FromIterator<(&'a str, MetaExpr)> for Meta {
82    #[inline]
83    fn from_iter<T>(iter: T) -> Self
84    where
85        T: IntoIterator<Item = (&'a str, MetaExpr)>,
86    {
87        Self::KeyValue(
88            iter.into_iter()
89                .map(|(k, v)| {
90                    let k = Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(k)));
91                    (k, v)
92                })
93                .collect(),
94        )
95    }
96}
97
98impl<I, V> From<I> for Meta
99where
100    Meta: FromIterator<V>,
101    I: IntoIterator<Item = V>,
102{
103    #[inline]
104    fn from(iter: I) -> Self {
105        Self::from_iter(iter)
106    }
107}
108
109/// Represents a reference to the metadata for an [super::Attribute]
110///
111/// See [Meta] for what metadata is represented, and its syntax.
112#[derive(Copy, Clone, PartialEq, Eq)]
113pub enum BorrowedMeta<'a> {
114    /// A list of metadata expressions
115    List(&'a [MetaExpr]),
116    /// A list of uniquely-named metadata expressions
117    KeyValue(&'a BTreeMap<Ident, MetaExpr>),
118}
119impl fmt::Debug for BorrowedMeta<'_> {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        match self {
122            Self::List(items) => write!(f, "{items:#?}"),
123            Self::KeyValue(items) => write!(f, "{items:#?}"),
124        }
125    }
126}
127
128/// Represents a single metadata item provided as an argument to an attribute.
129///
130/// For example, the `foo` attribute in `@foo(bar, baz)` has two metadata items, both of `Expr`
131/// type, which compose a `
132#[derive(Clone, PartialEq, Eq)]
133pub enum MetaItem {
134    /// A metadata expression, e.g. `"some text"` in `@foo("some text")`
135    ///
136    /// This represents the element type for `Meta::List`-based attributes.
137    Expr(MetaExpr),
138    /// A named metadata expression, e.g. `letter = a` in `@foo(letter = a)`
139    ///
140    /// This represents the element type for `Meta::KeyValue`-based attributes.
141    KeyValue(Ident, MetaExpr),
142}
143
144impl MetaItem {
145    /// Unwrap this item to extract the contained [MetaExpr].
146    ///
147    /// Panics if this item is not the `Expr` variant.
148    #[inline]
149    #[track_caller]
150    pub fn unwrap_expr(self) -> MetaExpr {
151        match self {
152            Self::Expr(expr) => expr,
153            Self::KeyValue(..) => unreachable!("tried to unwrap key-value as expression"),
154        }
155    }
156
157    /// Unwrap this item to extract the contained key-value pair.
158    ///
159    /// Panics if this item is not the `KeyValue` variant.
160    #[inline]
161    #[track_caller]
162    pub fn unwrap_key_value(self) -> (Ident, MetaExpr) {
163        match self {
164            Self::KeyValue(k, v) => (k, v),
165            Self::Expr(_) => unreachable!("tried to unwrap expression as key-value"),
166        }
167    }
168}
169
170impl From<Ident> for MetaItem {
171    fn from(value: Ident) -> Self {
172        Self::Expr(MetaExpr::Ident(value))
173    }
174}
175
176impl From<&str> for MetaItem {
177    fn from(value: &str) -> Self {
178        Self::Expr(MetaExpr::from(value))
179    }
180}
181
182impl From<String> for MetaItem {
183    fn from(value: String) -> Self {
184        Self::Expr(MetaExpr::from(value))
185    }
186}
187
188impl From<u8> for MetaItem {
189    fn from(value: u8) -> Self {
190        Self::Expr(MetaExpr::from(value))
191    }
192}
193
194impl From<u16> for MetaItem {
195    fn from(value: u16) -> Self {
196        Self::Expr(MetaExpr::from(value))
197    }
198}
199
200impl From<u32> for MetaItem {
201    fn from(value: u32) -> Self {
202        Self::Expr(MetaExpr::from(value))
203    }
204}
205
206impl From<Felt> for MetaItem {
207    fn from(value: Felt) -> Self {
208        Self::Expr(MetaExpr::from(value))
209    }
210}
211
212impl From<WordValue> for MetaItem {
213    fn from(value: WordValue) -> Self {
214        Self::Expr(MetaExpr::from(value))
215    }
216}
217
218impl<V> From<(Ident, V)> for MetaItem
219where
220    V: Into<MetaExpr>,
221{
222    fn from(entry: (Ident, V)) -> Self {
223        let (key, value) = entry;
224        Self::KeyValue(key, value.into())
225    }
226}
227
228impl<V> From<(&str, V)> for MetaItem
229where
230    V: Into<MetaExpr>,
231{
232    fn from(entry: (&str, V)) -> Self {
233        let (key, value) = entry;
234        let key = Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(key)));
235        Self::KeyValue(key, value.into())
236    }
237}
238
239impl<V> From<(String, V)> for MetaItem
240where
241    V: Into<MetaExpr>,
242{
243    fn from(entry: (String, V)) -> Self {
244        let (key, value) = entry;
245        let key =
246            Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(key.into_boxed_str())));
247        Self::KeyValue(key, value.into())
248    }
249}