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