Skip to content

Commit

Permalink
feat: add repr attribute via ast_node attribute.
Browse files Browse the repository at this point in the history
  • Loading branch information
rzvxa committed Apr 15, 2024
1 parent 0a8106f commit add6be0
Showing 1 changed file with 38 additions and 14 deletions.
52 changes: 38 additions & 14 deletions crates/oxc_macros/src/ast_node.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use std::slice;

use proc_macro2::TokenStream as TokenStream2;

use quote::quote;
use syn::{
punctuated::Punctuated, Attribute, Generics, Ident, Item, ItemEnum, ItemStruct, Meta, Token,
parse_quote, punctuated::Punctuated, Attribute, Generics, Ident, Item, ItemEnum, ItemStruct,
Meta, Token,
};

pub fn ast_node(mut item: Item) -> TokenStream2 {
Expand All @@ -25,30 +24,55 @@ pub fn ast_node(mut item: Item) -> TokenStream2 {
}

fn modify_struct(item: &mut ItemStruct) -> NodeData {
validate_struct_attributes(item.attrs.iter());
validate_struct_attributes(&item.attrs);
item.attrs.push(parse_quote!(#[repr(C)]));
NodeData { ident: &item.ident, generics: &item.generics }
}

fn modify_enum(item: &mut ItemEnum) -> NodeData {
validate_enum_attributes(item.attrs.iter());
validate_enum_attributes(&item.attrs);
item.attrs.push(parse_quote!(#[repr(C, u8)]));
NodeData { ident: &item.ident, generics: &item.generics }
}

fn validate_struct_attributes<'a>(mut attrs: slice::Iter<'a, Attribute>) {
fn validate_struct_attributes<I>(attrs: &I)
where
for<'a> &'a I: IntoIterator<Item = &'a Attribute>,
{
// make sure that no structure derives Clone/Copy traits.
// TODO: It will fail if there is a manual Clone/Copy traits implemented for the struct.
// Negative traits (!Copy and !Clone) are nightly so I'm not sure how we can fully enforce it.
assert!(!attrs.any(|attr| {
let args = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated);
attr.path().is_ident("derive")
&& args.is_ok_and(|args| {
args.iter().any(|arg| arg.path().is_ident("Clone") || arg.path().is_ident("Copy"))
})
}));
assert!(
!attrs.into_iter().any(|attr| {
let args = attr.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated);
attr.path().is_ident("derive")
&& args.is_ok_and(|args| {
args.iter()
.any(|arg| arg.path().is_ident("Clone") || arg.path().is_ident("Copy"))
})
}),
"`ast_node` can't have Clone or Copy traits"
);

validate_attributes(attrs);
}

fn validate_enum_attributes<'a>(_: slice::Iter<'a, Attribute>) {
fn validate_enum_attributes<I>(attrs: &I)
where
for<'a> &'a I: IntoIterator<Item = &'a Attribute>,
{
// TODO: Later on we may want to enforce deriving clone and copy traits for all enum types
validate_attributes(attrs);
}

fn validate_attributes<I>(attrs: &I)
where
for<'a> &'a I: IntoIterator<Item = &'a Attribute>,
{
assert!(
!attrs.into_iter().any(|attr| attr.path().is_ident("repr")),
"using `repr` attribute is not allowed with `ast_node`."
);
}

fn impl_traversable_test_trait(node: &NodeData) -> TokenStream2 {
Expand Down

0 comments on commit add6be0

Please sign in to comment.