1mod info;
2
3use alloc::rc::Rc;
4use core::ptr::{DynMetadata, Pointee};
5
6pub use self::info::DialectInfo;
7use crate::{
8 AttributeRef, Builder, OperationName, OperationRef, SourceSpan, Type, any::AsAny,
9 attributes::AttributeName, interner,
10};
11
12pub type DialectRegistrationHook = fn(&mut DialectInfo);
13
14pub trait Dialect {
18 fn info(&self) -> &DialectInfo;
20
21 fn name(&self) -> interner::Symbol {
23 self.info().name()
24 }
25
26 fn registered_ops(&self) -> &[OperationName] {
28 self.info().operations()
29 }
30
31 fn registered_attrs(&self) -> &[AttributeName] {
33 self.info().attributes()
34 }
35
36 #[allow(unused_variables)]
44 #[inline]
45 fn materialize_constant(
46 &self,
47 builder: &mut dyn Builder,
48 attr: AttributeRef,
49 ty: &Type,
50 span: SourceSpan,
51 ) -> Option<OperationRef> {
52 None
53 }
54}
55
56impl dyn Dialect {
57 pub fn registered_name<T>(&self) -> Option<OperationName>
59 where
60 T: crate::OpRegistration,
61 {
62 let opcode = <T as crate::OpRegistration>::name();
63 self.registered_ops().iter().find(|op| op.name() == opcode).cloned()
64 }
65
66 pub fn registered_attribute_name<T>(&self) -> Option<AttributeName>
68 where
69 T: crate::AttributeRegistration,
70 {
71 let name = <T as crate::AttributeRegistration>::name();
72 self.registered_attrs().iter().find(|attr| attr.name() == name).cloned()
73 }
74
75 pub fn expect_registered_name<T>(&self) -> OperationName
79 where
80 T: crate::OpRegistration,
81 {
82 self.registered_name::<T>().unwrap_or_else(|| {
83 panic!(
84 "{} is not registered with dialect '{}'",
85 core::any::type_name::<T>(),
86 self.name()
87 )
88 })
89 }
90
91 pub fn expect_registered_attribute_name<T>(&self) -> AttributeName
95 where
96 T: crate::AttributeRegistration,
97 {
98 self.registered_attribute_name::<T>().unwrap_or_else(|| {
99 panic!(
100 "{} is not registered with dialect '{}'",
101 core::any::type_name::<T>(),
102 self.name()
103 )
104 })
105 }
106
107 pub fn as_registered_interface<Trait>(&self) -> Option<&Trait>
109 where
110 Trait: ?Sized + Pointee<Metadata = DynMetadata<Trait>> + 'static,
111 {
112 let this = self as *const dyn Dialect;
113 let (ptr, _) = this.to_raw_parts();
114 let info = self.info();
115 info.upcast(ptr)
116 }
117}
118
119pub trait DialectRegistration: AsAny + Dialect {
126 const NAMESPACE: &'static str;
132
133 fn init(info: DialectInfo) -> Self;
140
141 #[allow(unused_variables)]
145 fn register_operations(info: &mut DialectInfo) {}
146
147 #[allow(unused_variables)]
151 fn register_attributes(info: &mut DialectInfo) {}
152}
153
154inventory::collect!(DialectRegistrationInfo);
155inventory::collect!(DialectRegistrationHookInfo);
156inventory::collect!(DialectOpRegistrationInfo);
157inventory::collect!(DialectAttributeRegistrationInfo);
158
159#[doc(hidden)]
160#[repr(transparent)]
161pub struct DialectRegistrationInfo(DialectRegistrationEntry);
162
163#[doc(hidden)]
164#[repr(transparent)]
165pub struct DialectRegistrationHookInfo(DialectRegistrationHookEntry);
166
167#[doc(hidden)]
168#[repr(transparent)]
169pub struct DialectOpRegistrationInfo(DialectOpRegistrationEntry);
170
171#[doc(hidden)]
172#[repr(transparent)]
173pub struct DialectAttributeRegistrationInfo(DialectAttributeRegistrationEntry);
174
175#[repr(C)]
176struct DialectRegistrationEntry {
177 namespace: &'static str,
178 type_name: &'static str,
179 type_id: core::any::TypeId,
180 builder: fn() -> Rc<dyn Dialect>,
181}
182
183impl DialectRegistrationInfo {
184 pub const fn new<T: DialectRegistration>() -> Self {
185 let namespace = <T as DialectRegistration>::NAMESPACE;
186 Self(DialectRegistrationEntry {
187 namespace,
188 type_name: core::any::type_name::<T>(),
189 type_id: core::any::TypeId::of::<T>(),
190 builder: dialect_init::<T>,
191 })
192 }
193
194 pub(crate) const fn namespace(&self) -> &'static str {
195 self.0.namespace
196 }
197
198 pub(crate) const fn type_name(&self) -> &'static str {
199 self.0.type_name
200 }
201
202 #[allow(unused)]
203 pub(crate) const fn type_id(&self) -> &core::any::TypeId {
204 &self.0.type_id
205 }
206
207 pub(crate) fn create(&self) -> Rc<dyn Dialect> {
208 (self.0.builder)()
209 }
210}
211
212#[repr(C)]
213struct DialectRegistrationHookEntry {
214 namespace: &'static str,
215 type_name: &'static str,
216 type_id: core::any::TypeId,
217 hook: DialectRegistrationHook,
218}
219
220impl DialectRegistrationHookInfo {
221 pub const fn new<T: DialectRegistration>(hook: DialectRegistrationHook) -> Self {
222 let namespace = <T as DialectRegistration>::NAMESPACE;
223 Self(DialectRegistrationHookEntry {
224 namespace,
225 type_name: core::any::type_name::<T>(),
226 type_id: core::any::TypeId::of::<T>(),
227 hook,
228 })
229 }
230}
231
232#[repr(C)]
233struct DialectOpRegistrationEntry {
234 dialect: &'static str,
235 dialect_type: core::any::TypeId,
236 get_opcode: fn() -> interner::Symbol,
237 init: fn(interner::Symbol, alloc::vec::Vec<super::traits::TraitInfo>) -> OperationName,
238}
239
240impl DialectOpRegistrationInfo {
241 pub const fn new<T: super::OpRegistration>() -> Self {
242 let dialect = <<T as super::OpRegistration>::Dialect as DialectRegistration>::NAMESPACE;
243 let dialect_type = core::any::TypeId::of::<<T as super::OpRegistration>::Dialect>();
244 Self(DialectOpRegistrationEntry {
245 dialect,
246 dialect_type,
247 get_opcode: <T as super::OpRegistration>::name,
248 init: OperationName::new::<T>,
249 })
250 }
251}
252
253#[repr(C)]
254struct DialectAttributeRegistrationEntry {
255 dialect: &'static str,
256 dialect_type: core::any::TypeId,
257 get_name: fn() -> interner::Symbol,
258 init: fn(interner::Symbol, alloc::vec::Vec<super::traits::TraitInfo>) -> AttributeName,
259}
260
261impl DialectAttributeRegistrationInfo {
262 pub const fn new<T: crate::AttributeRegistration>() -> Self {
263 let dialect =
264 <<T as crate::AttributeRegistration>::Dialect as DialectRegistration>::NAMESPACE;
265 let dialect_type = core::any::TypeId::of::<<T as crate::AttributeRegistration>::Dialect>();
266 Self(DialectAttributeRegistrationEntry {
267 dialect,
268 dialect_type,
269 get_name: <T as crate::AttributeRegistration>::name,
270 init: AttributeName::new::<T>,
271 })
272 }
273}
274
275pub(super) fn dialect_init<T: DialectRegistration>() -> Rc<dyn Dialect> {
276 let mut info = DialectInfo::new::<T>();
277
278 let dialect_name = <T as DialectRegistration>::NAMESPACE;
279 let dialect_type = core::any::TypeId::of::<T>();
280
281 for dialect_hook in inventory::iter::<DialectRegistrationHookInfo>() {
282 if dialect_hook.0.type_id == dialect_type && dialect_hook.0.namespace == dialect_name {
283 (dialect_hook.0.hook)(&mut info);
284 }
285 }
286
287 for op in inventory::iter::<DialectOpRegistrationInfo>() {
288 if op.0.dialect_type == dialect_type && op.0.dialect == dialect_name {
289 let opcode = (op.0.get_opcode)();
290 info.get_or_register_with(opcode, op.0.init);
291 }
292 }
293
294 for attr in inventory::iter::<DialectAttributeRegistrationInfo>() {
295 if attr.0.dialect_type == dialect_type && attr.0.dialect == dialect_name {
296 let name = (attr.0.get_name)();
297 info.get_or_register_attribute_with(name, attr.0.init);
298 }
299 }
300
301 Rc::new(<T as DialectRegistration>::init(info)) as Rc<dyn Dialect>
302}