Skip to main content

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(..) => {
52                            unreachable!("mixed MetaItem variants in iterator: expected Expr")
53                        },
54                    }))
55                    .collect(),
56            ),
57            Some(MetaItem::KeyValue(k, v)) => Self::KeyValue(
58                core::iter::once((k, v))
59                    .chain(iter.map(|item| match item {
60                        MetaItem::KeyValue(k, v) => (k, v),
61                        MetaItem::Expr(_) => {
62                            unreachable!("mixed MetaItem variants in iterator: expected KeyValue")
63                        },
64                    }))
65                    .collect(),
66            ),
67        }
68    }
69}
70
71impl FromIterator<MetaExpr> for Meta {
72    #[inline]
73    fn from_iter<T: IntoIterator<Item = MetaExpr>>(iter: T) -> Self {
74        Self::List(iter.into_iter().collect())
75    }
76}
77
78impl FromIterator<(Ident, MetaExpr)> for Meta {
79    #[inline]
80    fn from_iter<T: IntoIterator<Item = (Ident, MetaExpr)>>(iter: T) -> Self {
81        Self::KeyValue(iter.into_iter().collect())
82    }
83}
84
85impl<'a> FromIterator<(&'a str, MetaExpr)> for Meta {
86    #[inline]
87    fn from_iter<T>(iter: T) -> Self
88    where
89        T: IntoIterator<Item = (&'a str, MetaExpr)>,
90    {
91        Self::KeyValue(
92            iter.into_iter()
93                .map(|(k, v)| {
94                    let k = Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(k)));
95                    (k, v)
96                })
97                .collect(),
98        )
99    }
100}
101
102impl<I, V> From<I> for Meta
103where
104    Meta: FromIterator<V>,
105    I: IntoIterator<Item = V>,
106{
107    #[inline]
108    fn from(iter: I) -> Self {
109        Self::from_iter(iter)
110    }
111}
112
113/// Represents a reference to the metadata for an [super::Attribute]
114///
115/// See [Meta] for what metadata is represented, and its syntax.
116#[derive(Copy, Clone, PartialEq, Eq)]
117pub enum BorrowedMeta<'a> {
118    /// A list of metadata expressions
119    List(&'a [MetaExpr]),
120    /// A list of uniquely-named metadata expressions
121    KeyValue(&'a BTreeMap<Ident, MetaExpr>),
122}
123impl fmt::Debug for BorrowedMeta<'_> {
124    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125        match self {
126            Self::List(items) => write!(f, "{items:#?}"),
127            Self::KeyValue(items) => write!(f, "{items:#?}"),
128        }
129    }
130}
131
132/// Represents a single metadata item provided as an argument to an attribute.
133///
134/// For example, the `foo` attribute in `@foo(bar, baz)` has two metadata items, both of `Expr`
135/// type, which compose a `
136#[derive(Clone, PartialEq, Eq)]
137pub enum MetaItem {
138    /// A metadata expression, e.g. `"some text"` in `@foo("some text")`
139    ///
140    /// This represents the element type for `Meta::List`-based attributes.
141    Expr(MetaExpr),
142    /// A named metadata expression, e.g. `letter = a` in `@foo(letter = a)`
143    ///
144    /// This represents the element type for `Meta::KeyValue`-based attributes.
145    KeyValue(Ident, MetaExpr),
146}
147
148impl MetaItem {
149    /// Unwrap this item to extract the contained [MetaExpr].
150    ///
151    /// Panics if this item is not the `Expr` variant.
152    #[inline]
153    #[track_caller]
154    pub fn unwrap_expr(self) -> MetaExpr {
155        match self {
156            Self::Expr(expr) => expr,
157            Self::KeyValue(..) => unreachable!("tried to unwrap key-value as expression"),
158        }
159    }
160
161    /// Unwrap this item to extract the contained key-value pair.
162    ///
163    /// Panics if this item is not the `KeyValue` variant.
164    #[inline]
165    #[track_caller]
166    pub fn unwrap_key_value(self) -> (Ident, MetaExpr) {
167        match self {
168            Self::KeyValue(k, v) => (k, v),
169            Self::Expr(_) => unreachable!("tried to unwrap expression as key-value"),
170        }
171    }
172}
173
174impl From<Ident> for MetaItem {
175    fn from(value: Ident) -> Self {
176        Self::Expr(MetaExpr::Ident(value))
177    }
178}
179
180impl From<&str> for MetaItem {
181    fn from(value: &str) -> Self {
182        Self::Expr(MetaExpr::from(value))
183    }
184}
185
186impl From<String> for MetaItem {
187    fn from(value: String) -> Self {
188        Self::Expr(MetaExpr::from(value))
189    }
190}
191
192impl From<u8> for MetaItem {
193    fn from(value: u8) -> Self {
194        Self::Expr(MetaExpr::from(value))
195    }
196}
197
198impl From<u16> for MetaItem {
199    fn from(value: u16) -> Self {
200        Self::Expr(MetaExpr::from(value))
201    }
202}
203
204impl From<u32> for MetaItem {
205    fn from(value: u32) -> Self {
206        Self::Expr(MetaExpr::from(value))
207    }
208}
209
210impl From<Felt> for MetaItem {
211    fn from(value: Felt) -> Self {
212        Self::Expr(MetaExpr::from(value))
213    }
214}
215
216impl From<WordValue> for MetaItem {
217    fn from(value: WordValue) -> Self {
218        Self::Expr(MetaExpr::from(value))
219    }
220}
221
222impl<V> From<(Ident, V)> for MetaItem
223where
224    V: Into<MetaExpr>,
225{
226    fn from(entry: (Ident, V)) -> Self {
227        let (key, value) = entry;
228        Self::KeyValue(key, value.into())
229    }
230}
231
232impl<V> From<(&str, V)> for MetaItem
233where
234    V: Into<MetaExpr>,
235{
236    fn from(entry: (&str, V)) -> Self {
237        let (key, value) = entry;
238        let key = Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(key)));
239        Self::KeyValue(key, value.into())
240    }
241}
242
243impl<V> From<(String, V)> for MetaItem
244where
245    V: Into<MetaExpr>,
246{
247    fn from(entry: (String, V)) -> Self {
248        let (key, value) = entry;
249        let key =
250            Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(key.into_boxed_str())));
251        Self::KeyValue(key, value.into())
252    }
253}