-
-
Notifications
You must be signed in to change notification settings - Fork 538
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)!: generate ast_builder.rs
.
#3890
feat(ast)!: generate ast_builder.rs
.
#3890
Conversation
Your org has enabled the Graphite merge queue for merging into mainAdd the label “merge” to the PR and Graphite will automatically add it to the merge queue when it’s ready to merge. Or use the label “hotfix” to add to the merge queue as a hot fix. You must have a Graphite account and log in to Graphite in order to use the merge queue. Sign up using this link. |
This one is trickier, because all kinds of weird methods have been added to AST builder over time, and I don't think there's much consistency in:
I think we might need to standardize the methods in the existing manually-written impl first, before moving over to a codegen-ed version. There's also a danger of generating lots more code than we have at present, and hurting compile times, if we try to make the codegen-ed version cover all possible cases. If the amount of code generated is excessive, maybe we need attrs on the AST types which indicate which builders to generate? #[visited_node]
#[builder(Expression)]
struct BooleanLiteral {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub value: bool,
} This would generate: impl<'a> AstBuilder<'a> {
// Always generated by default
fn boolean_literal(self, span: Span, value: bool) -> BooleanLiteral {
BooleanLiteral { span, value }
}
// Generated because of `#[builder(Expression)]` attr
fn boolean_literal_expression(self, span: Span, value: bool) -> Expression<'a> {
Expression::BooleanLiteral(self.alloc(BooleanLiteral { span, value }))
}
} Other methods that we could have generated (but don't want to): impl<'a> AstBuilder<'a> {
fn boolean_literal_array_expression_element(self, span: Span, value: bool) -> ArrayExpressionElement<'a> {
ArrayExpressionElement::BooleanLiteral(self.alloc(BooleanLiteral { span, value }))
}
fn boolean_literal_property_key(self, span: Span, value: bool) -> PropertyKey<'a> {
PropertyKey::BooleanLiteral(self.alloc(BooleanLiteral { span, value }))
}
fn boolean_literal_argument(self, span: Span, value: bool) -> Argument<'a> {
Argument::BooleanLiteral(self.alloc(BooleanLiteral { span, value }))
}
} |
Probably what I suggested above is too complicated. Maybe better to tackle this incrementally? e.g. Start by replacing all the methods for For all impl BooleanLiteral {
#[inline]
fn new(span: Span, value: bool) -> BooleanLiteral {
BooleanLiteral { span, value }
}
#[inline]
fn new_expression<'a>(span: Span, value: bool, allocator: &'a Allocator) -> Expression<'a> {
Expression::BooleanLiteral(
Box::new_in(BooleanLiteral::new(span, value), allocator)
)
}
}
impl<'a> AstBuilder<'a> {
#[inline]
fn boolean_literal(self, span: Span, value: bool) -> Expression<'a> {
BooleanLiteral::new_expression(span, value, self.allocator)
}
} If consumer wants an As I see it, the main value of |
d82dab5
to
0f6e917
Compare
6fc357d
to
e5b612c
Compare
e5b612c
to
450ccb9
Compare
@overlookmotel let me mull this one for a little while. I'll come back when I have figured out a working plan to discuss. |
3d6ab82
to
abd819e
Compare
450ccb9
to
9ceae0a
Compare
abd819e
to
0755bdf
Compare
9ceae0a
to
707fd3d
Compare
0755bdf
to
86ae683
Compare
707fd3d
to
4aeb8fa
Compare
86ae683
to
8f78662
Compare
4aeb8fa
to
b5cce9d
Compare
CodSpeed Performance ReportMerging #3890 will not alter performanceComparing Summary
|
Related to backlog#29 Right now I can think of 3 options to unify all of our builder calls(both in terms of name and signature), 1. Let the user do some of the workHave a bunch of fn statement_block_statement(self, it: BlockStatement<'a>) -> Statement<'a> {
Statement::BlockStatement(self.alloc(it))
}
fn block_statement(
self,
span: Span,
body: Vec<'a, Statement<'a>>,
) -> BlockStatement<'a> {
BlockStatement {
span,
body,
scope_id: Default::default(),
}
} then we use it like this: let block = self.ast.block_statement(span, body);
let stmt = self.ast.statement_block_statement(block); 2. More methodsWe have methods like these: fn statement_block_statement(
self,
span: Span,
body: Vec<'a, Statement<'a>>,
) -> Statement<'a> {
Statement::BlockStatement(self.alloc(self.block_statement(span, body)))
}
fn block_statement(
self,
span: Span,
body: Vec<'a, Statement<'a>>,
) -> BlockStatement<'a> {
BlockStatement {
span,
body,
scope_id: Default::default(),
}
} and use like this: let stmt = self.ast.statement_block_statement(span, body); This is nice but it would mean that if you want to wrap an already existing let stmt = Statement::BlockStatement(self.alloc(block)); Or rename the method we previously called fn statement_block_statement(self, it: BlockExpression<'a>) -> Expression<'a> {
Statement::BlockStatement(self.alloc(it))
} 3. Using
|
There is actually a fourth and fifth option which @overlookmotel mentioned these are the 3 that I can think of. So don't forget to read the previous comments. |
8f78662
to
1e31594
Compare
921bb97
to
36a5ef7
Compare
d68c7ab
to
0e33504
Compare
b98e220
to
62bae25
Compare
0e33504
to
d780b85
Compare
62bae25
to
266b292
Compare
We can merge once @overlookmotel finishes the review, along with a branch in a rolldown fork with oxc pointing to this branch. |
d780b85
to
77a3542
Compare
266b292
to
97f265b
Compare
It is based on #4124, Give it a look and let me know if there is anything I should consider changing. I'm mainly not sure about the snapshot changes, I know the pure comments are a valid change(#4119) but for some reason, the snapshot path differs on my system. |
77a3542
to
30f1b17
Compare
97f265b
to
8d65e15
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do have some thoughts/potential changes to propose, but given the size of the PR, let's get it merged ASAP, and then iterate.
30f1b17
to
91c792a
Compare
Merge activity
|
8d65e15
to
b1615c8
Compare
### Every structure has 2 builder methods: 1. `xxx` e.g. `block_statement` ```rust #[inline] pub fn block_statement(self, span: Span, body: Vec<'a, Statement<'a>>) -> BlockStatement<'a> { BlockStatement { span, body, scope_id: Default::default() } } ``` 2. `alloc_xxx` e.g. `alloc_block_statement` ```rust #[inline] pub fn alloc_block_statement( self, span: Span, body: Vec<'a, Statement<'a>>, ) -> Box<'a, BlockStatement<'a>> { self.block_statement(span, body).into_in(self.allocator) } ``` ### We generate 3 types of methods for enums: 1. `yyy_xxx` e.g. `statement_block` ```rust #[inline] pub fn statement_block(self, span: Span, body: Vec<'a, Statement<'a>>) -> Statement<'a> { Statement::BlockStatement(self.alloc(self.block_statement(span, body))) } ``` 2. `yyy_from_xxx` e.g. `statement_from_block` ```rust #[inline] pub fn statement_from_block<T>(self, inner: T) -> Statement<'a> where T: IntoIn<'a, Box<'a, BlockStatement<'a>>>, { Statement::BlockStatement(inner.into_in(self.allocator)) } ``` 3. `yyy_xxx` where `xxx` is inherited e.g. `statement_declaration` ```rust #[inline] pub fn statement_declaration(self, inner: Declaration<'a>) -> Statement<'a> { Statement::from(inner) } ``` ------------ ### Generic parameters: We no longer accept `Box<'a, ADT>`, `Atom` or `&'a str`, Instead we use `IntoIn<'a, Box<'a, ADT>>`, `IntoIn<'a, Atom<'a>>` and `IntoIn<'a, &'a str>` respectively. It allows us to rewrite things like this: ```rust let ident = IdentifierReference::new(SPAN, Atom::from("require")); let number_literal_expr = self.ast.expression_numeric_literal( right_expr.span(), num, raw, self.ast.new_str(num.to_string().as_str()), NumberBase::Decimal, ); ``` As this: ```rust let ident = IdentifierReference::new(SPAN, "require"); let number_literal_expr = self.ast.expression_numeric_literal( right_expr.span(), num, raw, num.to_string(), NumberBase::Decimal, ); ```
b1615c8
to
d347aed
Compare
## [0.18.0] - 2024-07-09 - d347aed ast: [**BREAKING**] Generate `ast_builder.rs`. (#3890) (rzvxa) ### Features - c6c16a5 minifier: Dce all conditional expressions (#4135) (Boshen) - 365d9ba oxc_codegen: Generate annotation comments before `CallExpression` and `NewExpression` (#4119) (IWANABETHATGUY) - 3a0f2aa parser: Check for illegal modifiers in modules and namespaces (#4126) (DonIsaac) - 2f53bdf semantic: Check for abstract ClassElements in non-abstract classes (#4127) (DonIsaac) - c4ee9f8 semantic: Check for abstract initializations and implementations (#4125) (Don Isaac) - 44c7fe3 span: Add various implementations of `FromIn` for `Atom`. (#4090) (rzvxa) ### Bug Fixes - cb1af04 isolated-declarations: Remove the `async` and `generator` keywords from `MethodDefinition` (#4130) (Dunqing) Co-authored-by: Boshen <Boshen@users.noreply.github.com>
You can read about the new builder methods here: oxc-project/oxc#3890 We also provide the `IntoIn` and `FromIn` in the `oxc_allocator` crate so I've removed the rolldown helper's version. I didn't touch the snippets but now some of them can painlessly be replaced with builder methods since we accept generic arguments for things that can be allocated on the arena. So now you can pass `&str` where `Atom` or `&'ast str` is expected. Or pass in a stack ast type and have it boxed in the builder using `IntoIn` bounds.
You can read about the new builder methods here: oxc-project/oxc#3890 We also provide the `IntoIn` and `FromIn` in the `oxc_allocator` crate so I've removed the rolldown helper's version. I didn't touch the snippets but now some of them can painlessly be replaced with builder methods since we accept generic arguments for things that can be allocated on the arena. So now you can pass `&str` where `Atom` or `&'ast str` is expected. Or pass in a stack ast type and have it boxed in the builder using `IntoIn` bounds.
Every structure has 2 builder methods:
xxx
e.g.block_statement
alloc_xxx
e.g.alloc_block_statement
We generate 3 types of methods for enums:
yyy_xxx
e.g.statement_block
yyy_from_xxx
e.g.statement_from_block
yyy_xxx
wherexxx
is inherited e.g.statement_declaration
Generic parameters:
We no longer accept
Box<'a, ADT>
,Atom
or&'a str
, Instead we useIntoIn<'a, Box<'a, ADT>>
,IntoIn<'a, Atom<'a>>
andIntoIn<'a, &'a str>
respectively.It allows us to rewrite things like this:
As this: