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_tools): add dedicated Derive trait. #5278

Merged
merged 1 commit into from
Sep 3, 2024
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
4 changes: 2 additions & 2 deletions .github/.generated_ast_watch_list.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ src:
- 'crates/oxc_ast/src/generated/assert_layouts.rs'
- 'crates/oxc_ast/src/generated/ast_kind.rs'
- 'crates/oxc_ast/src/generated/ast_builder.rs'
- 'crates/oxc_ast/src/generated/visit.rs'
- 'crates/oxc_ast/src/generated/visit_mut.rs'
- 'crates/oxc_ast/src/generated/derive_clone_in.rs'
- 'crates/oxc_ast/src/generated/derive_get_span.rs'
- 'crates/oxc_ast/src/generated/derive_get_span_mut.rs'
- 'crates/oxc_ast/src/generated/visit.rs'
- 'crates/oxc_ast/src/generated/visit_mut.rs'
- 'tasks/ast_codegen/src/**'
10 changes: 5 additions & 5 deletions crates/oxc_ast/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@
//!
//! If you are seeing compile-time errors in `src/ast/macros.rs`, this will be the cause.

mod js;
mod jsx;
mod literal;
mod macros;
mod ts;
pub(crate) mod js;
pub(crate) mod jsx;
pub(crate) mod literal;
pub(crate) mod macros;
pub(crate) mod ts;

use macros::inherit_variants;

Expand Down
13 changes: 11 additions & 2 deletions crates/oxc_ast/src/generated/derive_clone_in.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
// Auto-generated code, DO NOT EDIT DIRECTLY!
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/derive_clone_in.rs`
// To edit this generated file you have to edit `tasks/ast_tools/src/derives/clone_in.rs`

#![allow(clippy::default_trait_access)]

use oxc_allocator::{Allocator, CloneIn};

#[allow(clippy::wildcard_imports)]
use crate::ast::*;
use crate::ast::js::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::jsx::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::literal::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::ts::*;

impl<'alloc> CloneIn<'alloc> for BooleanLiteral {
type Cloned = BooleanLiteral;
Expand Down
15 changes: 12 additions & 3 deletions crates/oxc_ast/src/generated/derive_get_span.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
// Auto-generated code, DO NOT EDIT DIRECTLY!
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/derive_get_span.rs`
// To edit this generated file you have to edit `tasks/ast_tools/src/derives/get_span.rs`

#![allow(clippy::match_same_arms)]

use oxc_span::GetSpan;
use oxc_span::{GetSpan, Span};

#[allow(clippy::wildcard_imports)]
use crate::ast::*;
use crate::ast::js::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::jsx::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::literal::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::ts::*;

impl GetSpan for BooleanLiteral {
#[inline]
Expand Down
15 changes: 12 additions & 3 deletions crates/oxc_ast/src/generated/derive_get_span_mut.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
// Auto-generated code, DO NOT EDIT DIRECTLY!
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/derive_get_span.rs`
// To edit this generated file you have to edit `tasks/ast_tools/src/derives/get_span.rs`

#![allow(clippy::match_same_arms)]

use oxc_span::GetSpanMut;
use oxc_span::{GetSpanMut, Span};

#[allow(clippy::wildcard_imports)]
use crate::ast::*;
use crate::ast::js::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::jsx::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::literal::*;

#[allow(clippy::wildcard_imports)]
use crate::ast::ts::*;

impl GetSpanMut for BooleanLiteral {
#[inline]
Expand Down
83 changes: 78 additions & 5 deletions tasks/ast_tools/src/codegen.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use std::{cell::RefCell, collections::HashMap, path::PathBuf};

use itertools::Itertools;
use proc_macro2::TokenStream;

use crate::{
derives::{Derive, DeriveOutput},
fmt::pretty_print,
generators::{Generator, GeneratorOutput},
passes::Pass,
rust_ast::{self, AstRef},
schema::{lower_ast_types, Schema, TypeDef},
util::write_all_to,
Result, TypeId,
};

Expand All @@ -15,16 +19,51 @@ pub struct AstCodegen {
files: Vec<PathBuf>,
passes: Vec<Box<dyn Runner<Output = (), Context = EarlyCtx>>>,
generators: Vec<Box<dyn Runner<Output = GeneratorOutput, Context = LateCtx>>>,
derives: Vec<Box<dyn Runner<Output = DeriveOutput, Context = LateCtx>>>,
}

pub struct AstCodegenResult {
pub schema: Schema,
pub outputs: Vec<(/* generator name */ &'static str, /* output */ GeneratorOutput)>,
pub outputs: Vec<SideEffect>,
}

pub struct SideEffect(/* path */ pub PathBuf, /* output */ pub Vec<u8>);

impl SideEffect {
/// Apply the side-effect
pub fn apply(self) -> std::io::Result<()> {
let Self(path, data) = self;
let path = path.into_os_string();
let path = path.to_str().unwrap();
write_all_to(&data, path)?;
Ok(())
}

#[allow(clippy::unnecessary_wraps)]
pub fn path(&self) -> Option<String> {
let Self(path, _) = self;
let path = path.to_string_lossy();
Some(path.replace('\\', "/"))
}
}

impl From<(PathBuf, TokenStream)> for SideEffect {
fn from((path, stream): (PathBuf, TokenStream)) -> Self {
let content = pretty_print(&stream);
Self(path, content.as_bytes().into())
}
}

impl From<GeneratorOutput> for SideEffect {
fn from(output: GeneratorOutput) -> Self {
Self::from((output.0, output.1))
}
}

pub trait Runner {
type Context;
type Output;
#[allow(dead_code)]
fn name(&self) -> &'static str;
fn run(&mut self, ctx: &Self::Context) -> Result<Self::Output>;
}
Expand Down Expand Up @@ -116,15 +155,24 @@ impl AstCodegen {
}

#[must_use]
pub fn gen<G>(mut self, generator: G) -> Self
pub fn generate<G>(mut self, generator: G) -> Self
where
G: Generator + Runner<Output = GeneratorOutput, Context = LateCtx> + 'static,
{
self.generators.push(Box::new(generator));
self
}

pub fn generate(self) -> Result<AstCodegenResult> {
#[must_use]
pub fn derive<D>(mut self, derive: D) -> Self
where
D: Derive + Runner<Output = DeriveOutput, Context = LateCtx> + 'static,
{
self.derives.push(Box::new(derive));
self
}

pub fn run(self) -> Result<AstCodegenResult> {
let modules = self
.files
.into_iter()
Expand All @@ -140,17 +188,42 @@ impl AstCodegen {
_ = self
.passes
.into_iter()
.map(|mut runner| runner.run(&ctx).map(|res| (runner.name(), res)))
.map(|mut runner| runner.run(&ctx))
.collect::<Result<Vec<_>>>()?;
ctx.into_late_ctx()
};

let derives = self
.derives
.into_iter()
.map(|mut runner| runner.run(&ctx))
.map_ok(|output| output.0.into_iter().map(SideEffect::from))
.flatten_ok();

let outputs = self
.generators
.into_iter()
.map(|mut runner| runner.run(&ctx).map(|res| (runner.name(), res)))
.map(|mut runner| runner.run(&ctx))
.map_ok(SideEffect::from)
.chain(derives)
.collect::<Result<Vec<_>>>()?;

Ok(AstCodegenResult { outputs, schema: ctx.schema })
}
}

/// Creates a generated file warning + required information for a generated file.
macro_rules! generated_header {
() => {{
let file = file!().replace("\\", "/");
// TODO add generation date, AST source hash, etc here.
let edit_comment = format!("@ To edit this generated file you have to edit `{file}`");
quote::quote! {
//!@ Auto-generated code, DO NOT EDIT DIRECTLY!
#![doc = #edit_comment]
//!@@line_break
}
}};
}

pub(crate) use generated_header;
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,34 @@ use syn::Ident;
use crate::{
codegen::LateCtx,
markers::CloneInAttribute,
output,
schema::{EnumDef, GetIdent, StructDef, TypeDef},
GeneratorOutput,
};

use super::{define_generator, generated_header, Generator};
use super::{define_derive, Derive, DeriveOutput};

define_generator! {
define_derive! {
pub struct DeriveCloneIn;
}

impl Generator for DeriveCloneIn {
fn generate(&mut self, ctx: &LateCtx) -> GeneratorOutput {
let impls: Vec<TokenStream> = ctx
.schema()
.into_iter()
.filter(|def| def.generates_derive("CloneIn"))
.map(|def| match &def {
TypeDef::Enum(it) => derive_enum(it),
TypeDef::Struct(it) => derive_struct(it),
})
.collect();

let header = generated_header!();

GeneratorOutput::Stream((
output(crate::AST_CRATE, "derive_clone_in.rs"),
quote! {
#header

#![allow(clippy::default_trait_access)]
impl Derive for DeriveCloneIn {
fn trait_name() -> &'static str {
"CloneIn"
}

///@@line_break
use oxc_allocator::{Allocator, CloneIn};
fn derive(&mut self, def: &TypeDef, _: &LateCtx) -> TokenStream {
match &def {
TypeDef::Enum(it) => derive_enum(it),
TypeDef::Struct(it) => derive_struct(it),
}
}

///@@line_break
#[allow(clippy::wildcard_imports)]
use crate::ast::*;
fn prelude() -> TokenStream {
quote! {
#![allow(clippy::default_trait_access)]

///@@line_break
#(#impls)*
},
))
///@@line_break
use oxc_allocator::{Allocator, CloneIn};
}
}
}

Expand Down Expand Up @@ -106,7 +91,6 @@ fn impl_clone_in(
) -> TokenStream {
if has_lifetime {
quote! {
///@@line_break
impl <'old_alloc, 'new_alloc> CloneIn<'new_alloc> for #ty_ident<'old_alloc> {
type Cloned = #ty_ident<'new_alloc>;
fn clone_in(&self, #alloc_ident: &'new_alloc Allocator) -> Self::Cloned {
Expand All @@ -116,7 +100,6 @@ fn impl_clone_in(
}
} else {
quote! {
///@@line_break
impl <'alloc> CloneIn<'alloc> for #ty_ident {
type Cloned = #ty_ident;
fn clone_in(&self, #alloc_ident: &'alloc Allocator) -> Self::Cloned {
Expand Down
Loading