melior_macro/dialect/operation/
attribute.rs1use crate::dialect::{
2 error::Error,
3 operation::operation_field::OperationField,
4 utility::{generate_result_type, sanitize_snake_case_identifier},
5};
6use proc_macro2::{Span, TokenStream};
7use quote::quote;
8use std::collections::HashMap;
9use std::sync::LazyLock;
10use syn::{parse_quote, Ident, Type};
11use tblgen::{error::TableGenError, Record};
12
13macro_rules! prefixed_string {
14 ($prefix:literal, $name:ident) => {
15 concat!($prefix, stringify!($name))
16 };
17}
18
19macro_rules! mlir_attribute {
20 ($name:ident) => {
21 prefixed_string!("::mlir::", $name)
22 };
23}
24
25macro_rules! melior_attribute {
26 ($name:ident) => {
27 prefixed_string!("::melior::ir::attribute::", $name)
28 };
29}
30
31static ATTRIBUTE_TYPES: LazyLock<HashMap<&'static str, &'static str>> = LazyLock::new(|| {
32 let mut map = HashMap::new();
33
34 macro_rules! initialize_attributes {
35 ($($mlir:ident => $melior:ident),* $(,)*) => {
36 $(
37 map.insert(
38 mlir_attribute!($mlir),
39 melior_attribute!($melior),
40 );
41 )*
42 };
43 }
44
45 initialize_attributes!(
46 ArrayAttr => ArrayAttribute,
47 Attribute => Attribute,
48 DenseElementsAttr => DenseElementsAttribute,
49 DenseI32ArrayAttr => DenseI32ArrayAttribute,
50 FlatSymbolRefAttr => FlatSymbolRefAttribute,
51 FloatAttr => FloatAttribute,
52 IntegerAttr => IntegerAttribute,
53 StringAttr => StringAttribute,
54 TypeAttr => TypeAttribute,
55 );
56
57 map
58});
59
60#[derive(Debug)]
61pub struct Attribute<'a> {
62 name: &'a str,
63 singular_identifier: Ident,
64 storage_type_string: String,
65 set_identifier: Ident,
66 remove_identifier: Ident,
67 storage_type: Type,
68 optional: bool,
69 default: bool,
70}
71
72impl<'a> Attribute<'a> {
73 pub fn new(name: &'a str, record: Record<'a>) -> Result<Self, Error> {
74 let storage_type_string = record.string_value("storageType")?;
75
76 Ok(Self {
77 name,
78 singular_identifier: sanitize_snake_case_identifier(name)?,
79 set_identifier: sanitize_snake_case_identifier(&format!("set_{name}"))?,
80 remove_identifier: sanitize_snake_case_identifier(&format!("remove_{name}"))?,
81 storage_type: syn::parse_str(
82 ATTRIBUTE_TYPES
83 .get(storage_type_string.trim())
84 .copied()
85 .unwrap_or(melior_attribute!(Attribute)),
86 )?,
87 storage_type_string,
88 optional: record.bit_value("isOptional")?,
89 default: match record.string_value("defaultValue") {
90 Ok(value) => !value.is_empty(),
91 Err(error) => {
92 if !matches!(error.error(), TableGenError::InitConversion { .. }) {
94 return Err(error.into());
95 }
96
97 false
98 }
99 },
100 })
101 }
102
103 pub const fn set_identifier(&self) -> &Ident {
104 &self.set_identifier
105 }
106
107 pub const fn remove_identifier(&self) -> &Ident {
108 &self.remove_identifier
109 }
110
111 pub fn is_unit(&self) -> bool {
112 self.storage_type_string == mlir_attribute!(UnitAttr)
113 }
114}
115
116impl OperationField for Attribute<'_> {
117 fn name(&self) -> &str {
118 self.name
119 }
120
121 fn singular_identifier(&self) -> &Ident {
122 &self.singular_identifier
123 }
124
125 fn plural_kind_identifier(&self) -> Ident {
126 Ident::new("attributes", Span::call_site())
127 }
128
129 fn parameter_type(&self) -> Type {
130 if self.is_unit() {
131 parse_quote!(bool)
132 } else {
133 let r#type = &self.storage_type;
134 parse_quote!(#r#type<'c>)
135 }
136 }
137
138 fn return_type(&self) -> Type {
139 if self.is_unit() {
140 parse_quote!(bool)
141 } else {
142 generate_result_type(self.parameter_type())
143 }
144 }
145
146 fn is_optional(&self) -> bool {
147 self.optional || self.default
148 }
149
150 fn add_arguments(&self, name: &Ident) -> TokenStream {
151 let name_string = &self.name;
152
153 quote! {
154 &[(
155 ::melior::ir::Identifier::new(self.context, #name_string),
156 #name.into(),
157 )]
158 }
159 }
160}