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