Skip to content

Commit e693ff3

Browse files
committed
feat(ast_tools): generate list of helper attributes in oxc_ast_macros crate (#8852)
Custom attributes used by generators (e.g. `#[visit]`) need to be added to the dummy `Ast` derive macro in `oxc_ast_macros`. Do this automatically, rather than requiring the person writing the generator to remember to do it.
1 parent 7b31849 commit e693ff3

6 files changed

Lines changed: 44 additions & 5 deletions

File tree

.github/.generated_ast_watch_list.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ src:
2020
- 'crates/oxc_ast/src/generated/get_id.rs'
2121
- 'crates/oxc_ast/src/generated/visit.rs'
2222
- 'crates/oxc_ast/src/generated/visit_mut.rs'
23+
- 'crates/oxc_ast_macros/src/lib.rs'
2324
- 'crates/oxc_regular_expression/src/ast.rs'
2425
- 'crates/oxc_regular_expression/src/generated/derive_clone_in.rs'
2526
- 'crates/oxc_regular_expression/src/generated/derive_content_eq.rs'

crates/oxc_ast_macros/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub fn ast(_args: TokenStream, input: TokenStream) -> TokenStream {
8484
/// Its only purpose is to allow the occurrence of helper attributes used in `tasks/ast_tools`.
8585
///
8686
/// Read [`macro@ast`] for further details.
87-
#[proc_macro_derive(Ast, attributes(scope, visit, span, generate_derive, clone_in, estree, ts))]
87+
#[proc_macro_derive(Ast, attributes(clone_in, estree, generate_derive, scope, span, ts, visit))]
8888
pub fn ast_derive(_input: TokenStream) -> TokenStream {
8989
TokenStream::new()
9090
}

tasks/ast_tools/src/codegen.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ impl Codegen {
7373
pub fn attr_processor(&self, attr_name: &str) -> Option<(AttrProcessor, AttrPositions)> {
7474
self.attr_processors.get(attr_name).copied()
7575
}
76+
77+
/// Get all attributes which derives and generators handle.
78+
pub fn attrs(&self) -> Vec<&'static str> {
79+
self.attr_processors.keys().copied().collect()
80+
}
7681
}
7782

7883
/// Runner trait.

tasks/ast_tools/src/main.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@
147147
//! * Implement [`Generator::attrs`] / [`Derive::attrs`] to declare the generator's custom attributes.
148148
//! * Implement [`Generator::parse_attr`] / [`Derive::parse_attr`] to parse those attributes
149149
//! and mutate the "extension" types in [`Schema`] as required.
150-
//! * Add the attributes' names to the list on `ast_derive` in `crates/oxc_ast_macros/src/lib.rs`.
151150
//!
152151
//! #### Attributes
153152
//!
@@ -170,7 +169,7 @@
170169
//! [`AttrLocation`]: parse::attr::AttrLocation
171170
//! [`AttrPart`]: parse::attr::AttrPart
172171
173-
use std::fmt::Write;
172+
use std::{fmt::Write, fs};
174173

175174
use bpaf::{Bpaf, Parser};
176175
use rayon::prelude::*;
@@ -209,6 +208,9 @@ static SOURCE_PATHS: &[&str] = &[
209208
/// Path to `oxc_ast` crate
210209
const AST_CRATE: &str = "crates/oxc_ast";
211210

211+
/// Path to `oxc_ast_macros` crate's `lib.rs` file
212+
const AST_MACROS_LIB_PATH: &str = "crates/oxc_ast_macros/src/lib.rs";
213+
212214
/// Path to write TS type definitions to
213215
const TYPESCRIPT_DEFINITIONS_PATH: &str = "npm/oxc-types/types.d.ts";
214216

@@ -288,6 +290,9 @@ fn main() {
288290

289291
logln!("All Derives and Generators... Done!");
290292

293+
// Edit `lib.rs` in `oxc_ast_macros` crate
294+
outputs.push(generate_updated_proc_macro(&codegen));
295+
291296
// Add CI filter file to outputs
292297
outputs.sort_unstable_by(|o1, o2| o1.path.cmp(&o2.path));
293298
outputs.push(generate_ci_filter(&outputs));
@@ -326,3 +331,26 @@ fn generate_ci_filter(outputs: &[RawOutput]) -> RawOutput {
326331

327332
Output::Yaml { path: GITHUB_WATCH_LIST_PATH.to_string(), code }.into_raw(file!())
328333
}
334+
335+
/// Update the list of helper attributes for `Ast` derive proc macro in `oxc_ast_macros` crate
336+
/// to include all attrs which generators/derives utilize.
337+
///
338+
/// Unfortunately we can't add a separate generated file for this, as proc macros can only be declared
339+
/// in the main `lib.rs` of a proc macro crate. So we have to edit the existing file.
340+
fn generate_updated_proc_macro(codegen: &Codegen) -> RawOutput {
341+
// Get all attrs which derives/generators use
342+
let mut attrs = codegen.attrs();
343+
attrs.push("generate_derive");
344+
attrs.sort_unstable();
345+
let attrs = attrs.join(", ");
346+
347+
// Load `oxc_ast_macros` crate's `lib.rs` file.
348+
// Substitute list of used attrs into `#[proc_macro_derive(Ast, attributes(...))]`.
349+
let code = fs::read_to_string(AST_MACROS_LIB_PATH).unwrap();
350+
let (start, end) = code.split_once("#[proc_macro_derive(").unwrap();
351+
let (_, end) = end.split_once(")]").unwrap();
352+
assert!(end.starts_with("\npub fn ast_derive("));
353+
let code = format!("{start}#[proc_macro_derive(Ast, attributes({attrs}))]{end}");
354+
355+
Output::RustString { path: AST_MACROS_LIB_PATH.to_string(), code }.into_raw("")
356+
}

tasks/ast_tools/src/output/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod javascript;
99
mod rust;
1010
mod yaml;
1111
use javascript::print_javascript;
12-
use rust::print_rust;
12+
use rust::{print_rust, rust_fmt};
1313
use yaml::print_yaml;
1414

1515
/// Get path for an output.
@@ -32,6 +32,7 @@ fn add_header(code: &str, generator_path: &str, comment_start: &str) -> String {
3232
#[expect(dead_code)]
3333
pub enum Output {
3434
Rust { path: String, tokens: TokenStream },
35+
RustString { path: String, code: String },
3536
Javascript { path: String, code: String },
3637
Yaml { path: String, code: String },
3738
Raw { path: String, code: String },
@@ -49,6 +50,10 @@ impl Output {
4950
let code = print_rust(tokens, &generator_path);
5051
(path, code)
5152
}
53+
Self::RustString { path, code } => {
54+
let code = rust_fmt(&code);
55+
(path, code)
56+
}
5257
Self::Javascript { path, code } => {
5358
let code = print_javascript(&code, &generator_path);
5459
(path, code)

tasks/ast_tools/src/output/rust.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn print_rust(tokens: TokenStream, generator_path: &str) -> String {
2121
/// Format Rust code with `rustfmt`.
2222
///
2323
/// Does not format on disk - interfaces with `rustfmt` via stdin/stdout.
24-
fn rust_fmt(source_text: &str) -> String {
24+
pub fn rust_fmt(source_text: &str) -> String {
2525
let mut rustfmt = Command::new("rustfmt")
2626
.stdin(Stdio::piped())
2727
.stdout(Stdio::piped())

0 commit comments

Comments
 (0)