Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ast, ast_macros): apply stable repr to all #[ast] enums #4373

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 0 additions & 16 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -269,7 +268,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[serde(untagged)]
Expand Down Expand Up @@ -359,7 +357,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -436,7 +433,6 @@ pub struct TemplateElementValue<'a> {

/// <https://tc39.es/ecma262/#prod-MemberExpression>
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -597,7 +593,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -706,7 +701,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand All @@ -725,7 +719,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -780,7 +773,6 @@ macro_rules! match_simple_assignment_target {
pub use match_simple_assignment_target;

#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -846,7 +838,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -949,7 +940,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -979,7 +969,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -1050,7 +1039,6 @@ pub struct BlockStatement<'a> {

/// Declarations and the Variable Statement
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -1217,7 +1205,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -1251,7 +1238,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -2000,7 +1986,6 @@ pub struct StaticBlock<'a> {
/// export as namespace d; // TSNamespaceExportDeclaration
/// ```
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -2303,7 +2288,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down
1 change: 0 additions & 1 deletion crates/oxc_ast/src/ast/jsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down
4 changes: 2 additions & 2 deletions crates/oxc_ast/src/ast/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
///
/// ```
/// inherit_variants! {
/// #[repr(C, u8)]
/// #[ast]
/// enum Statement<'a> {
/// pub enum Statement<'a> {
/// BlockStatement(Box<'a, BlockStatement<'a>>) = 0,
Expand All @@ -35,7 +35,7 @@
/// expands to:
///
/// ```
/// #[repr(C, u8)]
/// #[ast]
/// enum Statement<'a> {
/// pub enum Statement<'a> {
/// BlockStatement(Box<'a, BlockStatement<'a>>) = 0,
Expand Down
6 changes: 0 additions & 6 deletions crates/oxc_ast/src/ast/ts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -191,7 +190,6 @@ pub enum TSLiteral<'a> {
/// This is the root-level type for TypeScript types, kind of like [`Expression`] is for
/// expressions.
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged, rename_all = "camelCase")]
Expand Down Expand Up @@ -483,7 +481,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged, rename_all = "camelCase")]
Expand Down Expand Up @@ -642,7 +639,6 @@ pub struct TSTypeReference<'a> {
/// IdentifierReference
/// NamespaceName . IdentifierReference
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -1035,7 +1031,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
Expand Down Expand Up @@ -1208,7 +1203,6 @@ inherit_variants! {
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged, rename_all = "camelCase")]
Expand Down
5 changes: 5 additions & 0 deletions crates/oxc_ast_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@ workspace = true
[lib]
proc-macro = true
doctest = false

[dependencies]
quote = { workspace = true }
syn = { workspace = true, features = ["full"] }
proc-macro2 = { workspace = true }
52 changes: 38 additions & 14 deletions crates/oxc_ast_macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,54 @@
use proc_macro::TokenStream;
use std::str::FromStr;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;

/// Attach to AST node type (struct or enum), to signal to codegen to create visitor for this type.
///
/// Macro's role is not to generate code - it's purely a means to communicate information to the codegen.
///
/// Only thing macro does is add `#[derive(Ast)]` to the item.
/// Deriving `Ast` does nothing, but supports `#[scope]`, `#[visit]`, and other attrs on struct fields.
/// These "helper" attributes are also signals to the codegen, and do nothing in themselves.
/// returns `#[repr(C, u8)]` if `enum_` has any non-unit variant,
/// Otherwise it would return `#[repr(u8)]`.
fn enum_repr(enum_: &syn::ItemEnum) -> TokenStream2 {
rzvxa marked this conversation as resolved.
Show resolved Hide resolved
if enum_.variants.iter().any(|var| !matches!(var.fields, syn::Fields::Unit)) {
quote!(#[repr(C, u8)])
} else {
quote!(#[repr(u8)])
}
}

/// This attribute serves two purposes,
/// First, it is a marker for our codegen to detect AST types. Furthermore.
/// It is also a lightweight macro; All of its computation is cached and
/// it only applies the following changes without any complex operation:
///
/// This is a workaround for Rust not supporting helper attributes for `proc_macro_attribute` macros,
/// so we need to use a derive macro to get that support.
/// * Prepend `#[repr(C, u8)]` to fieldful enums e.g. `enum E { X: u32, Y: u8 }`
/// * Prepend `#[repr(u8)]` to unit (fieldless) enums e.g. `enum E { X, Y, Z, }`
/// * Prepend `#[derive(oxc_ast_macros::Ast)]`
///
/// Use native Rust `TokenStream`, to avoid dependency on slow-compiling crates like `syn` and `quote`.
#[proc_macro_attribute]
#[allow(clippy::missing_panics_doc)]
pub fn ast(_args: TokenStream, input: TokenStream) -> TokenStream {
overlookmotel marked this conversation as resolved.
Show resolved Hide resolved
let mut stream = TokenStream::from_str("#[derive(::oxc_ast_macros::Ast)]").unwrap();
stream.extend(input);
stream
let input = syn::parse_macro_input!(input as syn::Item);

let repr = match input {
syn::Item::Enum(ref enum_) => enum_repr(enum_),
// In future, we'll add `#[repr(C)]` to structs, but at present this is disabled
syn::Item::Struct(_) => TokenStream2::default(),
rzvxa marked this conversation as resolved.
Show resolved Hide resolved

_ => {
unreachable!()
}
};

let expanded = quote! {
#[derive(::oxc_ast_macros::Ast)]
#repr
#input
};
TokenStream::from(expanded)
}

/// Dummy derive macro for a non-existent trait `Ast`.
///
/// Does not generate any code.
/// Only purpose is to allow using `#[scope]`, `#[visit]`, and other attrs in the AST node type defs.
/// These "marker" attributes are used in codegen.
#[proc_macro_derive(Ast, attributes(scope, visit, span, serde, tsify))]
pub fn ast_derive(_item: TokenStream) -> TokenStream {
TokenStream::new()
Expand Down
Loading