add #[hdl(cmp_eq)] to implement HdlPartialEq automatically

This commit is contained in:
Jacob Lifshay 2025-02-16 20:48:16 -08:00
parent 43797db36e
commit 3458c21f44
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
9 changed files with 351 additions and 20 deletions

View file

@ -83,6 +83,7 @@ impl ParsedBundle {
custom_bounds,
no_static: _,
no_runtime_generics: _,
cmp_eq: _,
} = options.body;
let mut fields = match fields {
syn::Fields::Named(fields) => fields,
@ -437,6 +438,7 @@ impl ToTokens for ParsedBundle {
custom_bounds: _,
no_static,
no_runtime_generics,
cmp_eq,
} = &options.body;
let target = get_target(target, ident);
let mut item_attrs = attrs.clone();
@ -765,6 +767,69 @@ impl ToTokens for ParsedBundle {
}
}
.to_tokens(tokens);
if let Some((cmp_eq,)) = cmp_eq {
let mut where_clause =
Generics::from(generics)
.where_clause
.unwrap_or_else(|| syn::WhereClause {
where_token: Token![where](span),
predicates: Punctuated::new(),
});
let mut fields_cmp_eq = vec![];
let mut fields_cmp_ne = vec![];
for field in fields.named() {
let field_ident = field.ident();
let field_ty = field.ty();
where_clause
.predicates
.push(parse_quote_spanned! {cmp_eq.span=>
#field_ty: ::fayalite::expr::ops::ExprPartialEq<#field_ty>
});
fields_cmp_eq.push(quote_spanned! {span=>
::fayalite::expr::ops::ExprPartialEq::cmp_eq(__lhs.#field_ident, __rhs.#field_ident)
});
fields_cmp_ne.push(quote_spanned! {span=>
::fayalite::expr::ops::ExprPartialEq::cmp_ne(__lhs.#field_ident, __rhs.#field_ident)
});
}
let cmp_eq_body;
let cmp_ne_body;
if fields_len == 0 {
cmp_eq_body = quote_spanned! {span=>
::fayalite::expr::ToExpr::to_expr(&true)
};
cmp_ne_body = quote_spanned! {span=>
::fayalite::expr::ToExpr::to_expr(&false)
};
} else {
cmp_eq_body = quote_spanned! {span=>
#(#fields_cmp_eq)&*
};
cmp_ne_body = quote_spanned! {span=>
#(#fields_cmp_ne)|*
};
};
quote_spanned! {span=>
#[automatically_derived]
impl #impl_generics ::fayalite::expr::ops::ExprPartialEq<Self> for #target #type_generics
#where_clause
{
fn cmp_eq(
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
#cmp_eq_body
}
fn cmp_ne(
__lhs: ::fayalite::expr::Expr<Self>,
__rhs: ::fayalite::expr::Expr<Self>,
) -> ::fayalite::expr::Expr<::fayalite::int::Bool> {
#cmp_ne_body
}
}
}
.to_tokens(tokens);
}
if let (None, MaybeParsed::Parsed(generics)) = (no_static, &self.generics) {
let static_generics = generics.clone().for_static_type();
let (static_impl_generics, static_type_generics, static_where_clause) =

View file

@ -155,7 +155,11 @@ impl ParsedEnum {
custom_bounds,
no_static: _,
no_runtime_generics: _,
cmp_eq,
} = options.body;
if let Some((cmp_eq,)) = cmp_eq {
errors.error(cmp_eq, "#[hdl(cmp_eq)] is not yet implemented for enums");
}
attrs.retain(|attr| {
if attr.path().is_ident("repr") {
errors.error(attr, "#[repr] is not supported on #[hdl] enums");
@ -211,6 +215,7 @@ impl ToTokens for ParsedEnum {
custom_bounds: _,
no_static,
no_runtime_generics,
cmp_eq: _, // TODO: implement cmp_eq for enums
} = &options.body;
let target = get_target(target, ident);
let mut struct_attrs = attrs.clone();

View file

@ -49,10 +49,14 @@ impl ParsedTypeAlias {
custom_bounds,
no_static,
no_runtime_generics: _,
cmp_eq,
} = options.body;
if let Some((no_static,)) = no_static {
errors.error(no_static, "no_static is not valid on type aliases");
}
if let Some((cmp_eq,)) = cmp_eq {
errors.error(cmp_eq, "cmp_eq is not valid on type aliases");
}
let generics = if custom_bounds.is_some() {
MaybeParsed::Unrecognized(generics)
} else if let Some(generics) = errors.ok(ParsedGenerics::parse(&mut generics)) {
@ -95,6 +99,7 @@ impl ToTokens for ParsedTypeAlias {
custom_bounds: _,
no_static: _,
no_runtime_generics,
cmp_eq: _,
} = &options.body;
let target = get_target(target, ident);
let mut type_attrs = attrs.clone();

View file

@ -26,6 +26,7 @@ crate::options! {
CustomBounds(custom_bounds),
NoStatic(no_static),
NoRuntimeGenerics(no_runtime_generics),
CmpEq(cmp_eq),
}
}

View file

@ -72,6 +72,7 @@ mod kw {
custom_keyword!(cfg);
custom_keyword!(cfg_attr);
custom_keyword!(clock_domain);
custom_keyword!(cmp_eq);
custom_keyword!(connect_inexact);
custom_keyword!(custom_bounds);
custom_keyword!(flip);