Skip to content
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
38 changes: 37 additions & 1 deletion crates/oxc_ast/src/ast_builder_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
clippy::too_many_arguments,
clippy::unused_self,
)]
#![warn(missing_docs)]

use std::mem;

Expand All @@ -27,43 +28,54 @@ impl<'a, T> FromIn<'a, NONE> for Option<Box<'a, T>> {
}

impl<'a> AstBuilder<'a> {
/// Create a new AST builder that will allocate nodes in the given allocator.
#[inline]
pub fn new(allocator: &'a Allocator) -> Self {
Self { allocator }
}

/// Move a value into the memory arena.
#[inline]
pub fn alloc<T>(self, value: T) -> Box<'a, T> {
Box::new_in(value, self.allocator)
}

/// Create a new empty [`Vec`] that stores its elements in the memory arena.
#[inline]
pub fn vec<T>(self) -> Vec<'a, T> {
Vec::new_in(self.allocator)
}

/// Create a new empty [`Vec`] that stores its elements in the memory arena.
/// Enough memory will be pre-allocated to store at least `capacity`
/// elements.
#[inline]
pub fn vec_with_capacity<T>(self, capacity: usize) -> Vec<'a, T> {
Vec::with_capacity_in(capacity, self.allocator)
}

/// Create a new arena-allocated [`Vec`] initialized with a single element.
#[inline]
pub fn vec1<T>(self, value: T) -> Vec<'a, T> {
let mut vec = self.vec_with_capacity(1);
vec.push(value);
vec
}

/// Collect an iterator into a new arena-allocated [`Vec`].
#[inline]
pub fn vec_from_iter<T, I: IntoIterator<Item = T>>(self, iter: I) -> Vec<'a, T> {
Vec::from_iter_in(iter, self.allocator)
}

/// Move a string slice into the memory arena, returning a reference to the slice
/// in the heap.
#[inline]
pub fn str(self, value: &str) -> &'a str {
String::from_str_in(value, self.allocator).into_bump_str()
}

/// Allocate an [`Atom`] from a string slice.
#[inline]
pub fn atom(self, value: &str) -> Atom<'a> {
Atom::from(String::from_str_in(value, self.allocator).into_bump_str())
Expand All @@ -80,26 +92,33 @@ impl<'a> AstBuilder<'a> {
unsafe { std::mem::transmute_copy(src) }
}

/// Moves the expression out by replacing it with a null expression.
/// Moves the expression out by replacing it with a [null
/// expression](Expression::NullLiteral).
#[inline]
pub fn move_expression(self, expr: &mut Expression<'a>) -> Expression<'a> {
let null_expr = self.expression_null_literal(expr.span());
mem::replace(expr, null_expr)
}

/// Moves the statement out by replacing it with an [empty
/// statement](Statement::EmptyStatement).
#[inline]
pub fn move_statement(self, stmt: &mut Statement<'a>) -> Statement<'a> {
let empty_stmt = self.empty_statement(stmt.span());
mem::replace(stmt, Statement::EmptyStatement(self.alloc(empty_stmt)))
}

/// Moves the assignment target out by replacing it with a dummy target with
/// no name and an empty [`Span`].
#[inline]
pub fn move_assignment_target(self, target: &mut AssignmentTarget<'a>) -> AssignmentTarget<'a> {
let dummy =
self.simple_assignment_target_identifier_reference(Span::default(), Atom::from(""));
mem::replace(target, dummy.into())
}

/// Move a declaration out by replacing it with an empty [variable
/// declaration](Declaration::VariableDeclaration).
#[inline]
pub fn move_declaration(self, decl: &mut Declaration<'a>) -> Declaration<'a> {
let empty_decl = self.variable_declaration(
Expand All @@ -112,6 +131,8 @@ impl<'a> AstBuilder<'a> {
mem::replace(decl, empty_decl)
}

/// Move a variable declaration out by replacing it with an empty [variable
/// declaration](VariableDeclaration).
#[inline]
pub fn move_variable_declaration(
self,
Expand All @@ -126,6 +147,8 @@ impl<'a> AstBuilder<'a> {
mem::replace(decl, empty_decl)
}

/// Move an array element out by replacing it with an
/// [elision](ArrayExpressionElement::Elision).
pub fn move_array_expression_element(
self,
element: &mut ArrayExpressionElement<'a>,
Expand All @@ -134,6 +157,8 @@ impl<'a> AstBuilder<'a> {
mem::replace(element, empty_element)
}

/// Take the contents of a arena-allocated [`Vec`], leaving an empty vec in
/// its place. This is akin to [`std::mem::take`].
#[inline]
pub fn move_vec<T>(self, vec: &mut Vec<'a, T>) -> Vec<'a, T> {
mem::replace(vec, self.vec())
Expand All @@ -160,6 +185,8 @@ impl<'a> AstBuilder<'a> {

/* ---------- Functions ---------- */

/// Create a [`FormalParameter`] with no type annotations, modifiers,
/// decorators, or initializer.
#[inline]
pub fn plain_formal_parameter(
self,
Expand All @@ -169,6 +196,8 @@ impl<'a> AstBuilder<'a> {
self.formal_parameter(span, self.vec(), pattern, None, false, false)
}

/// Create a [`Function`] with no "extras", i.e. decorators, type
/// annotations, accessibility modifiers, etc.
#[inline]
pub fn plain_function(
self,
Expand All @@ -195,6 +224,7 @@ impl<'a> AstBuilder<'a> {

/* ---------- Modules ---------- */

/// Create an empty [`ExportNamedDeclaration`] with no modifiers
#[inline]
pub fn plain_export_named_declaration_declaration(
self,
Expand All @@ -211,6 +241,8 @@ impl<'a> AstBuilder<'a> {
))
}

/// Create an [`ExportNamedDeclaration`] with no modifiers that contains a
/// set of [exported symbol names](ExportSpecifier).
#[inline]
pub fn plain_export_named_declaration(
self,
Expand All @@ -230,6 +262,8 @@ impl<'a> AstBuilder<'a> {

/* ---------- TypeScript ---------- */

/// Create a [`TSInterfaceHeritage`] that extends from the given list of
/// other interfaces.
#[inline]
pub fn ts_interface_heritages(
self,
Expand All @@ -245,11 +279,13 @@ impl<'a> AstBuilder<'a> {
)
}

/// Create an [`JSXOpeningElement`].
#[inline]
pub fn jsx_opening_fragment(self, span: Span) -> JSXOpeningFragment {
JSXOpeningFragment { span }
}

/// Create an [`JSXClosingElement`].
#[inline]
pub fn jsx_closing_fragment(self, span: Span) -> JSXClosingFragment {
JSXClosingFragment { span }
Expand Down
22 changes: 22 additions & 0 deletions crates/oxc_ast/src/generated/ast_builder.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! AST node factories
// Auto-generated code, DO NOT EDIT DIRECTLY!
// To edit this generated file you have to edit `tasks/ast_tools/src/generators/ast_builder.rs`

Expand All @@ -6,6 +7,7 @@
clippy::too_many_arguments,
clippy::fn_params_excessive_bools
)]
#![warn(missing_docs)]

use oxc_allocator::{Allocator, Box, IntoIn, Vec};

Expand All @@ -15,6 +17,7 @@ use crate::ast::*;
/// AST builder for creating AST nodes
#[derive(Clone, Copy)]
pub struct AstBuilder<'a> {
/// The memory allocator used to allocate AST nodes in the arena.
pub allocator: &'a Allocator,
}

Expand Down Expand Up @@ -1484,6 +1487,7 @@ impl<'a> AstBuilder<'a> {
Expression::TSInstantiationExpression(inner.into_in(self.allocator))
}

/// Convert a [`MemberExpression`] into the corresponding variant of [`Expression`] without copying or re-allocating memory.
#[inline]
pub fn expression_member(self, inner: MemberExpression<'a>) -> Expression<'a> {
Expression::from(inner)
Expand Down Expand Up @@ -1725,6 +1729,7 @@ impl<'a> AstBuilder<'a> {
ArrayExpressionElement::Elision(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`ArrayExpressionElement`] without copying or re-allocating memory.
#[inline]
pub fn array_expression_element_expression(
self,
Expand Down Expand Up @@ -1964,6 +1969,7 @@ impl<'a> AstBuilder<'a> {
PropertyKey::PrivateIdentifier(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`PropertyKey`] without copying or re-allocating memory.
#[inline]
pub fn property_key_expression(self, inner: Expression<'a>) -> PropertyKey<'a> {
PropertyKey::from(inner)
Expand Down Expand Up @@ -2509,6 +2515,7 @@ impl<'a> AstBuilder<'a> {
Argument::SpreadElement(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`Argument`] without copying or re-allocating memory.
#[inline]
pub fn argument_expression(self, inner: Expression<'a>) -> Argument<'a> {
Argument::from(inner)
Expand Down Expand Up @@ -2790,6 +2797,7 @@ impl<'a> AstBuilder<'a> {
Box::new_in(self.assignment_expression(span, operator, left, right), self.allocator)
}

/// Convert a [`SimpleAssignmentTarget`] into the corresponding variant of [`AssignmentTarget`] without copying or re-allocating memory.
#[inline]
pub fn assignment_target_simple(
self,
Expand All @@ -2798,6 +2806,7 @@ impl<'a> AstBuilder<'a> {
AssignmentTarget::from(inner)
}

/// Convert a [`AssignmentTargetPattern`] into the corresponding variant of [`AssignmentTarget`] without copying or re-allocating memory.
#[inline]
pub fn assignment_target_assignment_target_pattern(
self,
Expand Down Expand Up @@ -3006,6 +3015,7 @@ impl<'a> AstBuilder<'a> {
SimpleAssignmentTarget::TSInstantiationExpression(inner.into_in(self.allocator))
}

/// Convert a [`MemberExpression`] into the corresponding variant of [`SimpleAssignmentTarget`] without copying or re-allocating memory.
#[inline]
pub fn simple_assignment_target_member_expression(
self,
Expand Down Expand Up @@ -3226,6 +3236,7 @@ impl<'a> AstBuilder<'a> {
AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(inner.into_in(self.allocator))
}

/// Convert a [`AssignmentTarget`] into the corresponding variant of [`AssignmentTargetMaybeDefault`] without copying or re-allocating memory.
#[inline]
pub fn assignment_target_maybe_default_assignment_target(
self,
Expand Down Expand Up @@ -3556,6 +3567,7 @@ impl<'a> AstBuilder<'a> {
ChainElement::CallExpression(inner.into_in(self.allocator))
}

/// Convert a [`MemberExpression`] into the corresponding variant of [`ChainElement`] without copying or re-allocating memory.
#[inline]
pub fn chain_element_member_expression(self, inner: MemberExpression<'a>) -> ChainElement<'a> {
ChainElement::from(inner)
Expand Down Expand Up @@ -4054,11 +4066,13 @@ impl<'a> AstBuilder<'a> {
Statement::WithStatement(inner.into_in(self.allocator))
}

/// Convert a [`Declaration`] into the corresponding variant of [`Statement`] without copying or re-allocating memory.
#[inline]
pub fn statement_declaration(self, inner: Declaration<'a>) -> Statement<'a> {
Statement::from(inner)
}

/// Convert a [`ModuleDeclaration`] into the corresponding variant of [`Statement`] without copying or re-allocating memory.
#[inline]
pub fn statement_module_declaration(self, inner: ModuleDeclaration<'a>) -> Statement<'a> {
Statement::from(inner)
Expand Down Expand Up @@ -4832,6 +4846,7 @@ impl<'a> AstBuilder<'a> {
ForStatementInit::VariableDeclaration(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`ForStatementInit`] without copying or re-allocating memory.
#[inline]
pub fn for_statement_init_expression(self, inner: Expression<'a>) -> ForStatementInit<'a> {
ForStatementInit::from(inner)
Expand Down Expand Up @@ -4911,6 +4926,7 @@ impl<'a> AstBuilder<'a> {
ForStatementLeft::VariableDeclaration(inner.into_in(self.allocator))
}

/// Convert a [`AssignmentTarget`] into the corresponding variant of [`ForStatementLeft`] without copying or re-allocating memory.
#[inline]
pub fn for_statement_left_assignment_target(
self,
Expand Down Expand Up @@ -7866,6 +7882,7 @@ impl<'a> AstBuilder<'a> {
ExportDefaultDeclarationKind::TSInterfaceDeclaration(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`ExportDefaultDeclarationKind`] without copying or re-allocating memory.
#[inline]
pub fn export_default_declaration_kind_expression(
self,
Expand Down Expand Up @@ -8183,6 +8200,7 @@ impl<'a> AstBuilder<'a> {
TSEnumMemberName::StaticNumericLiteral(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`TSEnumMemberName`] without copying or re-allocating memory.
#[inline]
pub fn ts_enum_member_name_expression(self, inner: Expression<'a>) -> TSEnumMemberName<'a> {
TSEnumMemberName::from(inner)
Expand Down Expand Up @@ -9879,6 +9897,7 @@ impl<'a> AstBuilder<'a> {
TSTupleElement::TSRestType(inner.into_in(self.allocator))
}

/// Convert a [`TSType`] into the corresponding variant of [`TSTupleElement`] without copying or re-allocating memory.
#[inline]
pub fn ts_tuple_element_type(self, inner: TSType<'a>) -> TSTupleElement<'a> {
TSTupleElement::from(inner)
Expand Down Expand Up @@ -11755,6 +11774,7 @@ impl<'a> AstBuilder<'a> {
TSTypeQueryExprName::TSImportType(inner.into_in(self.allocator))
}

/// Convert a [`TSTypeName`] into the corresponding variant of [`TSTypeQueryExprName`] without copying or re-allocating memory.
#[inline]
pub fn ts_type_query_expr_name_type_name(
self,
Expand Down Expand Up @@ -12383,6 +12403,7 @@ impl<'a> AstBuilder<'a> {
TSModuleReference::ExternalModuleReference(inner.into_in(self.allocator))
}

/// Convert a [`TSTypeName`] into the corresponding variant of [`TSModuleReference`] without copying or re-allocating memory.
#[inline]
pub fn ts_module_reference_type_name(self, inner: TSTypeName<'a>) -> TSModuleReference<'a> {
TSModuleReference::from(inner)
Expand Down Expand Up @@ -13212,6 +13233,7 @@ impl<'a> AstBuilder<'a> {
JSXExpression::EmptyExpression(inner.into_in(self.allocator))
}

/// Convert a [`Expression`] into the corresponding variant of [`JSXExpression`] without copying or re-allocating memory.
#[inline]
pub fn jsx_expression_expression(self, inner: Expression<'a>) -> JSXExpression<'a> {
JSXExpression::from(inner)
Expand Down
9 changes: 9 additions & 0 deletions tasks/ast_tools/src/generators/ast_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ impl Generator for AstBuilderGenerator {
GeneratorOutput::Rust {
path: output(crate::AST_CRATE, "ast_builder.rs"),
tokens: quote! {
//! AST node factories
#header

#![allow(
clippy::default_trait_access,
clippy::too_many_arguments,
clippy::fn_params_excessive_bools,
)]
#![warn(missing_docs)]

///@@line_break
use oxc_allocator::{Allocator, Box, IntoIn, Vec};
Expand All @@ -56,6 +58,7 @@ impl Generator for AstBuilderGenerator {
/// AST builder for creating AST nodes
#[derive(Clone, Copy)]
pub struct AstBuilder<'a> {
/// The memory allocator used to allocate AST nodes in the arena.
pub allocator: &'a Allocator,
}

Expand Down Expand Up @@ -121,8 +124,14 @@ fn generate_enum_inherit_builder_fn(
let fn_name =
enum_builder_name(enum_ident.to_string(), inherit.super_.name().inner_name().to_string());

let docs = DocComment::new(format!(
"Convert a [`{}`] into the corresponding variant of [`{}`] without copying or re-allocating memory.",
inherit.super_.name(),
enum_ident
));
quote! {
///@@line_break
#docs
#[inline]
pub fn #fn_name(self, inner: #super_type) -> #enum_as_type {
#enum_ident::from(inner)
Expand Down
Loading