miden_assembly_syntax/ast/attribute/
mod.rs1mod meta;
2mod set;
3
4use core::fmt;
5
6use miden_core::utils::{
7 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
8};
9use miden_debug_types::{SourceSpan, Spanned};
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13pub use self::{
14 meta::{BorrowedMeta, Meta, MetaExpr, MetaItem, MetaKeyValue, MetaList},
15 set::{AttributeSet, AttributeSetEntry},
16};
17use crate::{ast::Ident, prettier};
18
19#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43#[cfg_attr(
44 all(feature = "serde", feature = "arbitrary", test),
45 miden_serde_test_macros::serde_test
46)]
47pub enum Attribute {
48 Marker(Ident),
50 List(MetaList),
52 KeyValue(MetaKeyValue),
54}
55
56impl Attribute {
57 pub fn new(name: Ident, metadata: impl Into<Meta>) -> Self {
68 let metadata = metadata.into();
69 match metadata {
70 Meta::Unit => Self::Marker(name),
71 Meta::List(items) => Self::List(MetaList { span: Default::default(), name, items }),
72 Meta::KeyValue(items) => {
73 Self::KeyValue(MetaKeyValue { span: Default::default(), name, items })
74 },
75 }
76 }
77
78 pub fn from_iter<V, I>(name: Ident, metadata: I) -> Self
84 where
85 Meta: FromIterator<V>,
86 I: IntoIterator<Item = V>,
87 {
88 Self::new(name, Meta::from_iter(metadata))
89 }
90
91 pub fn with_span(self, span: SourceSpan) -> Self {
93 match self {
94 Self::Marker(id) => Self::Marker(id.with_span(span)),
95 Self::List(list) => Self::List(list.with_span(span)),
96 Self::KeyValue(kv) => Self::KeyValue(kv.with_span(span)),
97 }
98 }
99
100 pub fn name(&self) -> &str {
102 match self {
103 Self::Marker(id) => id.as_str(),
104 Self::List(list) => list.name(),
105 Self::KeyValue(kv) => kv.name(),
106 }
107 }
108
109 pub fn id(&self) -> Ident {
111 match self {
112 Self::Marker(id) => id.clone(),
113 Self::List(list) => list.id(),
114 Self::KeyValue(kv) => kv.id(),
115 }
116 }
117
118 pub fn is_marker(&self) -> bool {
120 matches!(self, Self::Marker(_))
121 }
122
123 pub fn is_list(&self) -> bool {
125 matches!(self, Self::List(_))
126 }
127
128 pub fn is_key_value(&self) -> bool {
130 matches!(self, Self::KeyValue(_))
131 }
132
133 pub fn metadata(&self) -> Option<BorrowedMeta<'_>> {
137 match self {
138 Self::Marker(_) => None,
139 Self::List(list) => Some(BorrowedMeta::List(&list.items)),
140 Self::KeyValue(kv) => Some(BorrowedMeta::KeyValue(&kv.items)),
141 }
142 }
143}
144
145impl fmt::Debug for Attribute {
146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147 match self {
148 Self::Marker(id) => f.debug_tuple("Marker").field(&id).finish(),
149 Self::List(meta) => f
150 .debug_struct("List")
151 .field("name", &meta.name)
152 .field("items", &meta.items)
153 .finish(),
154 Self::KeyValue(meta) => f
155 .debug_struct("KeyValue")
156 .field("name", &meta.name)
157 .field("items", &meta.items)
158 .finish(),
159 }
160 }
161}
162
163impl fmt::Display for Attribute {
164 #[inline]
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 use prettier::PrettyPrint;
167 self.pretty_print(f)
168 }
169}
170
171impl prettier::PrettyPrint for Attribute {
172 fn render(&self) -> prettier::Document {
173 use prettier::*;
174 let doc = text(format!("@{}", &self.name()));
175 match self {
176 Self::Marker(_) => doc,
177 Self::List(meta) => {
178 let singleline_items = meta
179 .items
180 .iter()
181 .map(|item| item.render())
182 .reduce(|acc, item| acc + const_text(", ") + item)
183 .unwrap_or(Document::Empty);
184 let multiline_items = indent(
185 4,
186 nl() + meta
187 .items
188 .iter()
189 .map(|item| item.render())
190 .reduce(|acc, item| acc + nl() + item)
191 .unwrap_or(Document::Empty),
192 ) + nl();
193 doc + const_text("(") + (singleline_items | multiline_items) + const_text(")")
194 },
195 Self::KeyValue(meta) => {
196 let singleline_items = meta
197 .items
198 .iter()
199 .map(|(k, v)| text(k) + const_text(" = ") + v.render())
200 .reduce(|acc, item| acc + const_text(", ") + item)
201 .unwrap_or(Document::Empty);
202 let multiline_items = indent(
203 4,
204 nl() + meta
205 .items
206 .iter()
207 .map(|(k, v)| text(k) + const_text(" = ") + v.render())
208 .reduce(|acc, item| acc + nl() + item)
209 .unwrap_or(Document::Empty),
210 ) + nl();
211 doc + const_text("(") + (singleline_items | multiline_items) + const_text(")")
212 },
213 }
214 }
215}
216
217impl Spanned for Attribute {
218 fn span(&self) -> SourceSpan {
219 match self {
220 Self::Marker(id) => id.span(),
221 Self::List(list) => list.span(),
222 Self::KeyValue(kv) => kv.span(),
223 }
224 }
225}
226
227impl From<Ident> for Attribute {
228 fn from(value: Ident) -> Self {
229 Self::Marker(value)
230 }
231}
232
233impl<K, V> From<(K, V)> for Attribute
234where
235 K: Into<Ident>,
236 V: Into<MetaExpr>,
237{
238 fn from(kv: (K, V)) -> Self {
239 let (key, value) = kv;
240 Self::List(MetaList {
241 span: SourceSpan::default(),
242 name: key.into(),
243 items: vec![value.into()],
244 })
245 }
246}
247
248impl From<MetaList> for Attribute {
249 fn from(value: MetaList) -> Self {
250 Self::List(value)
251 }
252}
253
254impl From<MetaKeyValue> for Attribute {
255 fn from(value: MetaKeyValue) -> Self {
256 Self::KeyValue(value)
257 }
258}
259
260#[cfg(feature = "arbitrary")]
261impl proptest::arbitrary::Arbitrary for Attribute {
262 type Parameters = ();
263
264 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
265 use proptest::{arbitrary::any, prop_oneof, strategy::Strategy};
266
267 prop_oneof![
268 any::<Ident>().prop_map(Self::Marker),
269 any::<MetaList>().prop_map(Self::List),
270 any::<MetaKeyValue>().prop_map(Self::KeyValue),
271 ]
272 .boxed()
273 }
274
275 type Strategy = proptest::prelude::BoxedStrategy<Self>;
276}
277
278impl Serializable for Attribute {
279 fn write_into<W: ByteWriter>(&self, target: &mut W) {
280 match self {
281 Self::Marker(name) => {
282 target.write_u8(0);
283 name.write_into(target);
284 },
285 Self::List(list) => {
286 target.write_u8(1);
287 list.write_into(target);
288 },
289 Self::KeyValue(kv) => {
290 target.write_u8(1);
291 kv.write_into(target);
292 },
293 }
294 }
295}
296
297impl Deserializable for Attribute {
298 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
299 match source.read_u8()? {
300 0 => Ident::read_from(source).map(Self::Marker),
301 1 => MetaList::read_from(source).map(Self::List),
302 2 => MetaKeyValue::read_from(source).map(Self::KeyValue),
303 n => Err(DeserializationError::InvalidValue(format!(
304 "unknown Attribute variant tag '{n}'"
305 ))),
306 }
307 }
308}