1use std::{
40 fmt::{Debug, Display},
41 hash::Hash,
42 ops::Deref,
43 sync::LazyLock,
44};
45
46use combine::{Parser, parser, token};
47use downcast_rs::{Downcast, impl_downcast};
48use dyn_clone::DynClone;
49use rustc_hash::FxHashMap;
50
51use crate::{
52 builtin::attr_interfaces::OutlinedAttr,
53 common_traits::Verify,
54 context::{Context, collect_deduped_interface_verifiers},
55 dialect::{Dialect, DialectName},
56 identifier::Identifier,
57 impl_printable_for_display, input_err,
58 irfmt::{
59 parsers::{attr_parser, delimited_list_parser, spaced},
60 printers::iter_with_sep,
61 },
62 location::Located,
63 parsable::{Parsable, ParseResult, StateStream},
64 printable::{self, Printable},
65 result::Result,
66};
67
68#[derive(Clone)]
70struct AttributeDictKeyVal<'a> {
71 key: &'a Identifier,
72 val: &'a AttrObj,
73}
74
75impl<'a> Printable for AttributeDictKeyVal<'a> {
76 fn fmt(
77 &self,
78 ctx: &Context,
79 _state: &printable::State,
80 f: &mut std::fmt::Formatter<'_>,
81 ) -> std::fmt::Result {
82 write!(f, "{}: {}", self.key, self.val.disp(ctx))
83 }
84}
85
86impl<'b> Parsable for AttributeDictKeyVal<'b> {
87 type Arg = ();
88
89 type Parsed = (Identifier, AttrObj);
90
91 fn parse<'a>(
92 state_stream: &mut StateStream<'a>,
93 _arg: Self::Arg,
94 ) -> ParseResult<'a, Self::Parsed> {
95 (Identifier::parser(()), spaced(token(':')), attr_parser())
96 .map(|(key, _, val)| (key, val))
97 .parse_stream(state_stream)
98 .into_result()
99 }
100}
101
102impl Printable for AttributeDict {
103 fn fmt(
104 &self,
105 ctx: &Context,
106 _state: &printable::State,
107 f: &mut std::fmt::Formatter<'_>,
108 ) -> std::fmt::Result {
109 write!(
110 f,
111 "[{}]",
112 iter_with_sep(
113 self.0
114 .iter()
115 .map(|(key, val)| AttributeDictKeyVal { key, val }),
116 printable::ListSeparator::CharSpace(','),
117 )
118 .disp(ctx)
119 )
120 }
121}
122
123impl Parsable for AttributeDict {
124 type Arg = ();
125 type Parsed = Self;
126
127 fn parse<'a>(
128 state_stream: &mut StateStream<'a>,
129 _arg: Self::Arg,
130 ) -> ParseResult<'a, Self::Parsed> {
131 delimited_list_parser('[', ']', ',', AttributeDictKeyVal::parser(()))
132 .map(|key_vals| AttributeDict(key_vals.into_iter().collect()))
133 .parse_stream(state_stream)
134 .into_result()
135 }
136}
137
138#[derive(Default, Debug, Clone, PartialEq, Eq)]
140pub struct AttributeDict(pub FxHashMap<Identifier, AttrObj>);
141
142impl AttributeDict {
143 pub fn get<T: Attribute>(&self, k: &Identifier) -> Option<&T> {
145 self.0.get(k).and_then(|ao| ao.downcast_ref::<T>())
146 }
147
148 pub fn get_mut<T: Attribute>(&mut self, k: &Identifier) -> Option<&mut T> {
150 self.0.get_mut(k).and_then(|ao| ao.downcast_mut::<T>())
151 }
152
153 pub fn get_as<T: ?Sized + AttrInterfaceMarker + 'static>(&self, k: &Identifier) -> Option<&T> {
155 self.0.get(k).and_then(|ao| attr_cast::<T>(&**ao))
156 }
157
158 pub fn set<T: Attribute>(&mut self, k: Identifier, v: T) {
160 self.0.insert(k, Box::new(v));
161 }
162
163 pub fn clone_skip_outlined(&self) -> Self {
165 self.0
166 .iter()
167 .filter_map(|(k, v)| {
168 if attr_impls::<dyn OutlinedAttr>(&**v) {
169 None
170 } else {
171 Some((k.clone(), dyn_clone::clone_box(&**v)))
172 }
173 })
174 .collect::<FxHashMap<Identifier, AttrObj>>()
175 .into()
176 }
177}
178
179impl From<FxHashMap<Identifier, AttrObj>> for AttributeDict {
180 fn from(value: FxHashMap<Identifier, AttrObj>) -> Self {
181 AttributeDict(value)
182 }
183}
184
185pub trait Attribute: Printable + Verify + Downcast + Sync + Send + DynClone + Debug {
189 fn eq_attr(&self, other: &dyn Attribute) -> bool;
191
192 fn get_attr_id(&self) -> AttrId;
195
196 fn get_attr_id_static() -> AttrId
198 where
199 Self: Sized;
200
201 #[doc(hidden)]
202 fn verify_interfaces(&self, ctx: &Context) -> Result<()>;
204
205 fn register<A: Attribute>(ctx: &mut Context)
207 where
208 Self: Sized + Parsable<Arg = (), Parsed = A>,
209 {
210 let attr_parser: AttrParserFn = Box::new(|&()| {
211 combine::parser(move |parsable_state: &mut StateStream<'_>| {
212 Self::parse(parsable_state, ())
213 .map(|(attr, r)| -> (AttrObj, _) { (Box::new(attr), r) })
214 })
215 .boxed()
216 });
217 let attrid = Self::get_attr_id_static();
218 Dialect::register(ctx, &attrid.dialect).add_attr(attrid.clone(), attr_parser);
219 }
220}
221impl_downcast!(Attribute);
222dyn_clone::clone_trait_object!(Attribute);
223
224pub type AttrObj = Box<dyn Attribute>;
226
227pub(crate) type AttrParserFn = Box<
230 for<'a> fn(
231 &'a (),
232 ) -> Box<dyn Parser<StateStream<'a>, Output = AttrObj, PartialState = ()> + 'a>,
233>;
234
235impl PartialEq for AttrObj {
236 fn eq(&self, other: &Self) -> bool {
237 (**self).eq_attr(&**other)
238 }
239}
240
241impl<T: Attribute> From<T> for AttrObj {
242 fn from(value: T) -> Self {
243 Box::new(value)
244 }
245}
246
247impl Eq for AttrObj {}
248
249impl Printable for AttrObj {
250 fn fmt(
251 &self,
252 ctx: &Context,
253 state: &printable::State,
254 f: &mut core::fmt::Formatter<'_>,
255 ) -> core::fmt::Result {
256 write!(f, "{} ", self.get_attr_id())?;
257 Printable::fmt(self.deref(), ctx, state, f)
258 }
259}
260
261impl Parsable for AttrObj {
262 type Arg = ();
263 type Parsed = AttrObj;
264
265 fn parse<'a>(
266 state_stream: &mut StateStream<'a>,
267 _arg: Self::Arg,
268 ) -> ParseResult<'a, Self::Parsed> {
269 let loc = state_stream.loc();
270 let attr_id_parser = spaced(AttrId::parser(()));
271
272 let mut attr_parser = attr_id_parser.then(move |attr_id: AttrId| {
273 let loc = loc.clone();
274 combine::parser(move |parsable_state: &mut StateStream<'a>| {
275 let state = &parsable_state.state;
276 let dialect = state
277 .ctx
278 .dialects
279 .get(&attr_id.dialect)
280 .expect("Dialect name parsed but dialect isn't registered");
281 let Some(attr_parser) = dialect.attributes.get(&attr_id) else {
282 input_err!(
283 loc.clone(),
284 "Unregistered attribute {}",
285 attr_id.disp(state.ctx)
286 )?
287 };
288 attr_parser(&()).parse_stream(parsable_state).into_result()
289 })
290 });
291
292 attr_parser.parse_stream(state_stream).into_result()
293 }
294}
295
296pub fn verify_attr(attr: &dyn Attribute, ctx: &Context) -> Result<()> {
300 attr.verify_interfaces(ctx)?;
302
303 Verify::verify(attr, ctx)
305}
306
307impl Verify for AttrObj {
308 fn verify(&self, ctx: &Context) -> Result<()> {
309 verify_attr(self.as_ref(), ctx)
310 }
311}
312
313#[diagnostic::on_unimplemented(
318 message = "`{Self}` not an attribute interface.",
319 label = "If `{Self}` is a trait, annotate it with #[attr_interface] to be able to cast to it from a `&dyn Attribute`",
320 note = "If you want to cast to a concrete `Attribute`, use `downcast_ref` instead."
321)]
322pub trait AttrInterfaceMarker {}
323
324pub fn attr_cast<T: ?Sized + AttrInterfaceMarker + 'static>(attr: &dyn Attribute) -> Option<&T> {
348 crate::utils::trait_cast::any_to_trait::<T>(attr.as_any())
349}
350
351pub fn attr_impls<T: ?Sized + AttrInterfaceMarker + 'static>(attr: &dyn Attribute) -> bool {
373 attr_cast::<T>(attr).is_some()
374}
375
376#[derive(Clone, Hash, PartialEq, Eq)]
377pub struct AttrName(String);
379
380impl AttrName {
381 pub fn new(name: &str) -> AttrName {
383 AttrName(name.to_string())
384 }
385}
386
387impl_printable_for_display!(AttrName);
388
389impl Display for AttrName {
390 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
391 write!(f, "{}", self.0)
392 }
393}
394
395impl Parsable for AttrName {
396 type Arg = ();
397 type Parsed = AttrName;
398
399 fn parse<'a>(
400 state_stream: &mut crate::parsable::StateStream<'a>,
401 _arg: Self::Arg,
402 ) -> ParseResult<'a, Self::Parsed>
403 where
404 Self: Sized,
405 {
406 Identifier::parser(())
407 .map(|name| AttrName::new(&name))
408 .parse_stream(state_stream)
409 .into()
410 }
411}
412
413impl Deref for AttrName {
414 type Target = String;
415
416 fn deref(&self) -> &Self::Target {
417 &self.0
418 }
419}
420#[derive(Clone, Hash, PartialEq, Eq)]
422pub struct AttrId {
423 pub dialect: DialectName,
424 pub name: AttrName,
425}
426
427impl_printable_for_display!(AttrId);
428
429impl Display for AttrId {
430 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
431 write!(f, "{}.{}", self.dialect, self.name)
432 }
433}
434
435impl Parsable for AttrId {
436 type Arg = ();
437 type Parsed = AttrId;
438
439 fn parse<'a>(
441 state_stream: &mut StateStream<'a>,
442 _arg: Self::Arg,
443 ) -> ParseResult<'a, Self::Parsed>
444 where
445 Self: Sized,
446 {
447 let mut parser = DialectName::parser(())
448 .skip(parser::char::char('.'))
449 .and(AttrName::parser(()))
450 .map(|(dialect, name)| AttrId { dialect, name });
451 parser.parse_stream(state_stream).into()
452 }
453}
454
455pub type AttrInterfaceVerifier = fn(&dyn Attribute, &Context) -> Result<()>;
457pub type AttrInterfaceAllVerifiers = fn() -> Vec<AttrInterfaceVerifier>;
459
460#[doc(hidden)]
461type AttrInterfaceVerifierInfo = (std::any::TypeId, AttrInterfaceAllVerifiers);
464
465#[cfg(not(target_family = "wasm"))]
466pub mod statics {
467 use super::*;
468
469 #[::pliron::linkme::distributed_slice]
470 pub static ATTR_INTERFACE_VERIFIERS: [LazyLock<AttrInterfaceVerifierInfo>] = [..];
471
472 pub fn get_attr_interface_verifiers()
473 -> impl Iterator<Item = &'static LazyLock<AttrInterfaceVerifierInfo>> {
474 ATTR_INTERFACE_VERIFIERS.iter()
475 }
476}
477
478#[cfg(target_family = "wasm")]
479pub mod statics {
480 use super::*;
481 use crate::utils::inventory::LazyLockWrapper;
482
483 ::pliron::inventory::collect!(LazyLockWrapper<AttrInterfaceVerifierInfo>);
484
485 pub fn get_attr_interface_verifiers()
486 -> impl Iterator<Item = &'static LazyLock<AttrInterfaceVerifierInfo>> {
487 ::pliron::inventory::iter::<LazyLockWrapper<AttrInterfaceVerifierInfo>>().map(|llw| llw.0)
488 }
489}
490
491pub use statics::*;
492
493#[doc(hidden)]
494pub static ATTR_INTERFACE_VERIFIERS_MAP: LazyLock<
497 FxHashMap<std::any::TypeId, Vec<AttrInterfaceVerifier>>,
498> = LazyLock::new(|| collect_deduped_interface_verifiers(get_attr_interface_verifiers()));