Skip to content

Commit 6e766dd

Browse files
committed
feat(ast_codegen): add derive_clone_in generator.
1 parent fcfc553 commit 6e766dd

5 files changed

Lines changed: 151 additions & 1 deletion

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Auto-generated code, DO NOT EDIT DIRECTLY!
2+
// To edit this generated file you have to edit `tasks/ast_codegen/src/generators/derive_clone_in.rs`
3+
4+
use oxc_allocator::{Allocator, CloneIn};
5+
use crate::ast::*;
6+
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
use itertools::Itertools;
2+
use proc_macro2::TokenStream;
3+
use quote::{format_ident, quote};
4+
use syn::Ident;
5+
6+
use crate::{
7+
output,
8+
schema::{EnumDef, GetIdent, StructDef, TypeDef},
9+
GeneratorOutput, LateCtx,
10+
};
11+
12+
use super::{define_generator, generated_header, Generator};
13+
14+
define_generator! {
15+
pub struct DeriveCloneIn;
16+
}
17+
18+
impl Generator for DeriveCloneIn {
19+
fn name(&self) -> &'static str {
20+
stringify!(DeriveCloneIn)
21+
}
22+
23+
fn generate(&mut self, ctx: &LateCtx) -> GeneratorOutput {
24+
let impls: Vec<TokenStream> = ctx
25+
.schema
26+
.definitions
27+
.iter()
28+
.filter(|def| def.generates_derive("CloneIn"))
29+
.map(|def| match &def {
30+
TypeDef::Enum(it) => derive_enum(it),
31+
TypeDef::Struct(it) => derive_struct(it),
32+
})
33+
.collect();
34+
35+
let header = generated_header!();
36+
37+
GeneratorOutput::Stream((
38+
output(crate::AST_CRATE, "derive_clone_in.rs"),
39+
quote! {
40+
#header
41+
42+
use oxc_allocator::{Allocator, CloneIn};
43+
endl!();
44+
use crate::ast::*;
45+
endl!();
46+
47+
#(#impls)*
48+
},
49+
))
50+
}
51+
}
52+
53+
fn derive_enum(def: &EnumDef) -> TokenStream {
54+
let ty_ident = def.ident();
55+
let (alloc, body) = {
56+
let mut used_alloc = false;
57+
let matches = def
58+
.all_variants()
59+
.map(|var| {
60+
let ident = var.ident();
61+
if var.is_unit() {
62+
quote!(Self :: #ident => Self :: Cloned :: #ident)
63+
} else {
64+
used_alloc = true;
65+
quote!(Self :: #ident(it) => Self :: Cloned :: #ident(it.clone_in(alloc)))
66+
}
67+
})
68+
.collect_vec();
69+
let alloc_ident = if used_alloc { format_ident!("alloc") } else { format_ident!("_") };
70+
(
71+
alloc_ident,
72+
quote! {
73+
match self {
74+
#(#matches),*
75+
}
76+
},
77+
)
78+
};
79+
impl_clone_in(&ty_ident, def.has_lifetime, alloc, body)
80+
}
81+
82+
fn derive_struct(def: &StructDef) -> TokenStream {
83+
let ty_ident = def.ident();
84+
let (alloc, body) = {
85+
let (alloc_ident, body) = if def.fields.is_empty() {
86+
(format_ident!("_"), TokenStream::default())
87+
} else {
88+
let fields = def.fields.iter().map(|field| {
89+
let ident = field.ident();
90+
quote!(#ident: self.#ident.clone_in(alloc))
91+
});
92+
(format_ident!("alloc"), quote!({ #(#fields),* }))
93+
};
94+
(alloc_ident, quote!( #ty_ident #body ))
95+
};
96+
impl_clone_in(&ty_ident, def.has_lifetime, alloc, body)
97+
}
98+
99+
fn impl_clone_in(
100+
ty_ident: &Ident,
101+
has_lifetime: bool,
102+
alloc: Ident,
103+
body: TokenStream,
104+
) -> TokenStream {
105+
if has_lifetime {
106+
quote! {
107+
endl!();
108+
impl <'old_alloc, 'new_alloc> CloneIn<'new_alloc> for #ty_ident<'old_alloc> {
109+
type Cloned = #ty_ident<'new_alloc>;
110+
fn clone_in(&self, #alloc: &'new_alloc Allocator) -> Self::Cloned {
111+
#body
112+
}
113+
}
114+
}
115+
} else {
116+
quote! {
117+
endl!();
118+
impl <'alloc> CloneIn<'alloc> for #ty_ident {
119+
type Cloned = #ty_ident;
120+
fn clone_in(&self, #alloc: &'alloc Allocator) -> Self::Cloned {
121+
#body
122+
}
123+
}
124+
}
125+
}
126+
}

tasks/ast_codegen/src/generators/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod assert_layouts;
22
mod ast_builder;
33
mod ast_kind;
4+
mod derive_clone_in;
45
mod impl_get_span;
56
mod visit;
67

@@ -43,6 +44,7 @@ pub(crate) use insert;
4344
pub use assert_layouts::AssertLayouts;
4445
pub use ast_builder::AstBuilderGenerator;
4546
pub use ast_kind::AstKindGenerator;
47+
pub use derive_clone_in::DeriveCloneIn;
4648
pub use impl_get_span::ImplGetSpanGenerator;
4749
pub use visit::{VisitGenerator, VisitMutGenerator};
4850

tasks/ast_codegen/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ mod util;
1616

1717
use fmt::{cargo_fmt, pprint};
1818
use generators::{
19-
AssertLayouts, AstBuilderGenerator, AstKindGenerator, Generator, VisitGenerator,
19+
AssertLayouts, AstBuilderGenerator, AstKindGenerator, DeriveCloneIn, Generator, VisitGenerator,
2020
VisitMutGenerator,
2121
};
2222
use passes::{CalcLayout, Linker, Pass};
@@ -297,6 +297,7 @@ fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
297297
.gen(AssertLayouts)
298298
.gen(AstKindGenerator)
299299
.gen(AstBuilderGenerator)
300+
.gen(DeriveCloneIn)
300301
.gen(ImplGetSpanGenerator)
301302
.gen(VisitGenerator)
302303
.gen(VisitMutGenerator)

tasks/ast_codegen/src/schema/defs.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ impl EnumDef {
7979
pub fn all_variants(&self) -> impl Iterator<Item = &VariantDef> {
8080
self.variants.iter().chain(self.inherits.iter().flat_map(|it| it.variants.iter()))
8181
}
82+
83+
/// Are all the variants in this enum unit?
84+
/// Example:
85+
/// ```
86+
/// enum E { A, B, C, D }
87+
///
88+
/// ```
89+
///
90+
pub fn is_unit(&self) -> bool {
91+
self.all_variants().all(VariantDef::is_unit)
92+
}
8293
}
8394

8495
#[derive(Debug, Serialize)]
@@ -93,6 +104,10 @@ impl VariantDef {
93104
pub fn ident(&self) -> syn::Ident {
94105
self.name.to_ident()
95106
}
107+
108+
pub fn is_unit(&self) -> bool {
109+
self.fields.is_empty()
110+
}
96111
}
97112

98113
#[derive(Debug, Serialize)]

0 commit comments

Comments
 (0)