miden_assembly_syntax/ast/attribute/
mod.rs1mod meta;
2mod set;
3
4use core::fmt;
5
6use miden_debug_types::{SourceSpan, Spanned};
7
8pub use self::{
9 meta::{BorrowedMeta, Meta, MetaExpr, MetaItem, MetaKeyValue, MetaList},
10 set::{AttributeSet, AttributeSetEntry},
11};
12use crate::{ast::Ident, prettier};
13
14#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub enum Attribute {
38 Marker(Ident),
40 List(MetaList),
42 KeyValue(MetaKeyValue),
44}
45
46impl Attribute {
47 pub fn new(name: Ident, metadata: impl Into<Meta>) -> Self {
58 let metadata = metadata.into();
59 match metadata {
60 Meta::Unit => Self::Marker(name),
61 Meta::List(items) => Self::List(MetaList { span: Default::default(), name, items }),
62 Meta::KeyValue(items) => {
63 Self::KeyValue(MetaKeyValue { span: Default::default(), name, items })
64 },
65 }
66 }
67
68 pub fn from_iter<V, I>(name: Ident, metadata: I) -> Self
74 where
75 Meta: FromIterator<V>,
76 I: IntoIterator<Item = V>,
77 {
78 Self::new(name, Meta::from_iter(metadata))
79 }
80
81 pub fn with_span(self, span: SourceSpan) -> Self {
83 match self {
84 Self::Marker(id) => Self::Marker(id.with_span(span)),
85 Self::List(list) => Self::List(list.with_span(span)),
86 Self::KeyValue(kv) => Self::KeyValue(kv.with_span(span)),
87 }
88 }
89
90 pub fn name(&self) -> &str {
92 match self {
93 Self::Marker(id) => id.as_str(),
94 Self::List(list) => list.name(),
95 Self::KeyValue(kv) => kv.name(),
96 }
97 }
98
99 pub fn id(&self) -> Ident {
101 match self {
102 Self::Marker(id) => id.clone(),
103 Self::List(list) => list.id(),
104 Self::KeyValue(kv) => kv.id(),
105 }
106 }
107
108 pub fn is_marker(&self) -> bool {
110 matches!(self, Self::Marker(_))
111 }
112
113 pub fn is_list(&self) -> bool {
115 matches!(self, Self::List(_))
116 }
117
118 pub fn is_key_value(&self) -> bool {
120 matches!(self, Self::KeyValue(_))
121 }
122
123 pub fn metadata(&self) -> Option<BorrowedMeta<'_>> {
127 match self {
128 Self::Marker(_) => None,
129 Self::List(list) => Some(BorrowedMeta::List(&list.items)),
130 Self::KeyValue(kv) => Some(BorrowedMeta::KeyValue(&kv.items)),
131 }
132 }
133}
134
135impl fmt::Debug for Attribute {
136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137 match self {
138 Self::Marker(id) => f.debug_tuple("Marker").field(&id).finish(),
139 Self::List(meta) => f
140 .debug_struct("List")
141 .field("name", &meta.name)
142 .field("items", &meta.items)
143 .finish(),
144 Self::KeyValue(meta) => f
145 .debug_struct("KeyValue")
146 .field("name", &meta.name)
147 .field("items", &meta.items)
148 .finish(),
149 }
150 }
151}
152
153impl fmt::Display for Attribute {
154 #[inline]
155 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156 use prettier::PrettyPrint;
157 self.pretty_print(f)
158 }
159}
160
161impl prettier::PrettyPrint for Attribute {
162 fn render(&self) -> prettier::Document {
163 use prettier::*;
164 let doc = text(format!("@{}", &self.name()));
165 match self {
166 Self::Marker(_) => doc,
167 Self::List(meta) => {
168 let singleline_items = meta
169 .items
170 .iter()
171 .map(|item| item.render())
172 .reduce(|acc, item| acc + const_text(", ") + item)
173 .unwrap_or(Document::Empty);
174 let multiline_items = indent(
175 4,
176 nl() + meta
177 .items
178 .iter()
179 .map(|item| item.render())
180 .reduce(|acc, item| acc + nl() + item)
181 .unwrap_or(Document::Empty),
182 ) + nl();
183 doc + const_text("(") + (singleline_items | multiline_items) + const_text(")")
184 },
185 Self::KeyValue(meta) => {
186 let singleline_items = meta
187 .items
188 .iter()
189 .map(|(k, v)| text(k) + const_text(" = ") + v.render())
190 .reduce(|acc, item| acc + const_text(", ") + item)
191 .unwrap_or(Document::Empty);
192 let multiline_items = indent(
193 4,
194 nl() + meta
195 .items
196 .iter()
197 .map(|(k, v)| text(k) + const_text(" = ") + v.render())
198 .reduce(|acc, item| acc + nl() + item)
199 .unwrap_or(Document::Empty),
200 ) + nl();
201 doc + const_text("(") + (singleline_items | multiline_items) + const_text(")")
202 },
203 }
204 }
205}
206
207impl Spanned for Attribute {
208 fn span(&self) -> SourceSpan {
209 match self {
210 Self::Marker(id) => id.span(),
211 Self::List(list) => list.span(),
212 Self::KeyValue(kv) => kv.span(),
213 }
214 }
215}
216
217impl From<Ident> for Attribute {
218 fn from(value: Ident) -> Self {
219 Self::Marker(value)
220 }
221}
222
223impl<K, V> From<(K, V)> for Attribute
224where
225 K: Into<Ident>,
226 V: Into<MetaExpr>,
227{
228 fn from(kv: (K, V)) -> Self {
229 let (key, value) = kv;
230 Self::List(MetaList {
231 span: SourceSpan::default(),
232 name: key.into(),
233 items: vec![value.into()],
234 })
235 }
236}
237
238impl From<MetaList> for Attribute {
239 fn from(value: MetaList) -> Self {
240 Self::List(value)
241 }
242}
243
244impl From<MetaKeyValue> for Attribute {
245 fn from(value: MetaKeyValue) -> Self {
246 Self::KeyValue(value)
247 }
248}