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::{
12    Felt,
13    ast::Ident,
14    parser::{IntValue, WordValue},
15};
16
17/// Represents the metadata provided as arguments to an attribute.
18#[derive(Clone, PartialEq, Eq)]
19pub enum Meta {
20    /// Represents empty metadata, e.g. `@foo`
21    Unit,
22    /// A list of metadata expressions, e.g. `@foo(a, "some text", 0x01)`
23    ///
24    /// The list should always have at least one element, and this is guaranteed by the parser.
25    List(Vec<MetaExpr>),
26    /// A set of uniquely-named metadata expressions, e.g. `@foo(letter = a, text = "some text")`
27    ///
28    /// The set should always have at least one key-value pair, and this is guaranteed by the
29    /// parser.
30    KeyValue(BTreeMap<Ident, MetaExpr>),
31}
32impl Meta {
33    /// Borrow the metadata without unwrapping the specific type
34    ///
35    /// Returns `None` if there is no meaningful metadata
36    #[inline]
37    pub fn borrow(&self) -> Option<BorrowedMeta<'_>> {
38        match self {
39            Self::Unit => None,
40            Self::List(list) => Some(BorrowedMeta::List(list)),
41            Self::KeyValue(kv) => Some(BorrowedMeta::KeyValue(kv)),
42        }
43    }
44}
45impl FromIterator<MetaItem> for Meta {
46    #[inline]
47    fn from_iter<T: IntoIterator<Item = MetaItem>>(iter: T) -> Self {
48        let mut iter = iter.into_iter();
49        match iter.next() {
50            None => Self::Unit,
51            Some(MetaItem::Expr(expr)) => Self::List(
52                core::iter::once(expr)
53                    .chain(iter.map(|item| match item {
54                        MetaItem::Expr(expr) => expr,
55                        MetaItem::KeyValue(..) => unsafe { core::hint::unreachable_unchecked() },
56                    }))
57                    .collect(),
58            ),
59            Some(MetaItem::KeyValue(k, v)) => Self::KeyValue(
60                core::iter::once((k, v))
61                    .chain(iter.map(|item| match item {
62                        MetaItem::KeyValue(k, v) => (k, v),
63                        MetaItem::Expr(_) => unsafe { core::hint::unreachable_unchecked() },
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::String(Ident::from_raw_parts(Span::new(
183            SourceSpan::UNKNOWN,
184            Arc::from(value),
185        ))))
186    }
187}
188
189impl From<String> for MetaItem {
190    fn from(value: String) -> Self {
191        Self::Expr(MetaExpr::String(Ident::from_raw_parts(Span::new(
192            SourceSpan::UNKNOWN,
193            Arc::from(value.into_boxed_str()),
194        ))))
195    }
196}
197
198impl From<u8> for MetaItem {
199    fn from(value: u8) -> Self {
200        Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, IntValue::U8(value))))
201    }
202}
203
204impl From<u16> for MetaItem {
205    fn from(value: u16) -> Self {
206        Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, IntValue::U16(value))))
207    }
208}
209
210impl From<u32> for MetaItem {
211    fn from(value: u32) -> Self {
212        Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, IntValue::U32(value))))
213    }
214}
215
216impl From<Felt> for MetaItem {
217    fn from(value: Felt) -> Self {
218        Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, IntValue::Felt(value))))
219    }
220}
221
222impl From<WordValue> for MetaItem {
223    fn from(value: WordValue) -> Self {
224        Self::Expr(MetaExpr::Int(Span::new(SourceSpan::UNKNOWN, IntValue::Word(value))))
225    }
226}
227
228impl<V> From<(Ident, V)> for MetaItem
229where
230    V: Into<MetaExpr>,
231{
232    fn from(entry: (Ident, V)) -> Self {
233        let (key, value) = entry;
234        Self::KeyValue(key, value.into())
235    }
236}
237
238impl<V> From<(&str, V)> for MetaItem
239where
240    V: Into<MetaExpr>,
241{
242    fn from(entry: (&str, V)) -> Self {
243        let (key, value) = entry;
244        let key = Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(key)));
245        Self::KeyValue(key, value.into())
246    }
247}
248
249impl<V> From<(String, V)> for MetaItem
250where
251    V: Into<MetaExpr>,
252{
253    fn from(entry: (String, V)) -> Self {
254        let (key, value) = entry;
255        let key =
256            Ident::from_raw_parts(Span::new(SourceSpan::UNKNOWN, Arc::from(key.into_boxed_str())));
257        Self::KeyValue(key, value.into())
258    }
259}