diff --git a/crates/oxc_transformer/src/common/mod.rs b/crates/oxc_transformer/src/common/mod.rs new file mode 100644 index 000000000..412163ea0 --- /dev/null +++ b/crates/oxc_transformer/src/common/mod.rs @@ -0,0 +1,37 @@ +//! Utility transforms which are in common between other transforms. + +use oxc_allocator::Vec; +use oxc_ast::ast::*; +use oxc_traverse::{Traverse, TraverseCtx}; + +use crate::TransformCtx; + +mod var_declarations; + +use var_declarations::VarDeclarations; +pub use var_declarations::VarDeclarationsStore; + +pub struct Common<'a, 'ctx> { + var_declarations: VarDeclarations<'a, 'ctx>, +} + +impl<'a, 'ctx> Common<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { var_declarations: VarDeclarations::new(ctx) } + } +} + +impl<'a, 'ctx> Traverse<'a> for Common<'a, 'ctx> { + #[inline] // Inline because it's no-op in release mode + fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { + self.var_declarations.exit_program(program, ctx); + } + + fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.var_declarations.enter_statements(stmts, ctx); + } + + fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.var_declarations.exit_statements(stmts, ctx); + } +} diff --git a/crates/oxc_transformer/src/common/var_declarations.rs b/crates/oxc_transformer/src/common/var_declarations.rs new file mode 100644 index 000000000..161b4865d --- /dev/null +++ b/crates/oxc_transformer/src/common/var_declarations.rs @@ -0,0 +1,111 @@ +//! Utility transform to add `var` declarations to top of statement blocks. +//! +//! `VarDeclarationsStore` contains a stack of `Vec`s. +//! It is stored on `TransformCtx`. +//! +//! `VarDeclarations` transform pushes an empty entry onto this stack when entering a statement block, +//! and when exiting the block, writes a `var` statement to top of block containing the declarators. +//! +//! Other transforms can add declarators to the store by calling methods of `VarDeclarationsStore`: +//! +//! ```rs +//! self.ctx.var_declarations.insert_declarator(name, symbol_id, None, ctx); +//! ``` + +use std::cell::RefCell; + +use oxc_allocator::Vec; +use oxc_ast::{ast::*, NONE}; +use oxc_span::SPAN; +use oxc_syntax::symbol::SymbolId; +use oxc_traverse::{Traverse, TraverseCtx}; + +use crate::{context::TransformCtx, helpers::stack::SparseStack}; + +/// Transform that maintains the stack of `Vec`s, and adds a `var` statement +/// to top of a statement block if another transform has requested that. +/// +/// Must run after all other transforms. +pub struct VarDeclarations<'a, 'ctx> { + ctx: &'ctx TransformCtx<'a>, +} + +impl<'a, 'ctx> VarDeclarations<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { ctx } + } +} + +impl<'a, 'ctx> Traverse<'a> for VarDeclarations<'a, 'ctx> { + #[inline] // Inline because it's no-op in release mode + fn exit_program(&mut self, _program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) { + let declarators = self.ctx.var_declarations.declarators.borrow(); + debug_assert!(declarators.len() == 1); + debug_assert!(declarators.last().is_none()); + } + + fn enter_statements( + &mut self, + _stmts: &mut Vec<'a, Statement<'a>>, + _ctx: &mut TraverseCtx<'a>, + ) { + let mut declarators = self.ctx.var_declarations.declarators.borrow_mut(); + declarators.push(None); + } + + fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + let mut declarators = self.ctx.var_declarations.declarators.borrow_mut(); + if let Some(declarators) = declarators.pop() { + debug_assert!(!declarators.is_empty()); + let variable = ctx.ast.alloc_variable_declaration( + SPAN, + VariableDeclarationKind::Var, + declarators, + false, + ); + stmts.insert(0, Statement::VariableDeclaration(variable)); + } + } +} + +/// Store for `VariableDeclarator`s to be added to enclosing statement block. +pub struct VarDeclarationsStore<'a> { + declarators: RefCell>>>, +} + +impl<'a> VarDeclarationsStore<'a> { + pub fn new() -> Self { + Self { declarators: RefCell::new(SparseStack::new()) } + } +} + +impl<'a> VarDeclarationsStore<'a> { + /// Add a `VariableDeclarator` to be inserted at top of current enclosing statement block, + /// given `name` and `symbol_id`. + pub fn insert_declarator( + &self, + name: Atom<'a>, + symbol_id: SymbolId, + init: Option>, + ctx: &mut TraverseCtx<'a>, + ) { + let ident = BindingIdentifier::new_with_symbol_id(SPAN, name, symbol_id); + let ident = ctx.ast.binding_pattern_kind_from_binding_identifier(ident); + let ident = ctx.ast.binding_pattern(ident, NONE, false); + self.insert_declarator_binding_pattern(ident, init, ctx); + } + + /// Add a `VariableDeclarator` to be inserted at top of current enclosing statement block, + /// given a `BindingPattern`. + pub fn insert_declarator_binding_pattern( + &self, + ident: BindingPattern<'a>, + init: Option>, + ctx: &mut TraverseCtx<'a>, + ) { + let declarator = + ctx.ast.variable_declarator(SPAN, VariableDeclarationKind::Var, ident, init, false); + let mut declarators = self.declarators.borrow_mut(); + declarators.last_mut_or_init(|| ctx.ast.vec()).push(declarator); + } +} diff --git a/crates/oxc_transformer/src/context.rs b/crates/oxc_transformer/src/context.rs index 2941d8f42..9aa6d8739 100644 --- a/crates/oxc_transformer/src/context.rs +++ b/crates/oxc_transformer/src/context.rs @@ -9,7 +9,9 @@ use oxc_ast::{AstBuilder, Trivias}; use oxc_diagnostics::OxcDiagnostic; use oxc_span::SourceType; -use crate::{helpers::module_imports::ModuleImports, TransformOptions}; +use crate::{ + common::VarDeclarationsStore, helpers::module_imports::ModuleImports, TransformOptions, +}; pub struct TransformCtx<'a> { errors: RefCell>, @@ -31,6 +33,8 @@ pub struct TransformCtx<'a> { // Helpers /// Manage import statement globally pub module_imports: ModuleImports<'a>, + /// Manage inserting `var` statements globally + pub var_declarations: VarDeclarationsStore<'a>, } impl<'a> TransformCtx<'a> { @@ -59,6 +63,7 @@ impl<'a> TransformCtx<'a> { source_text, trivias, module_imports: ModuleImports::new(allocator), + var_declarations: VarDeclarationsStore::new(), } } diff --git a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs index 03412ee9b..d1ea2c5c6 100644 --- a/crates/oxc_transformer/src/es2016/exponentiation_operator.rs +++ b/crates/oxc_transformer/src/es2016/exponentiation_operator.rs @@ -37,7 +37,7 @@ use oxc_span::SPAN; use oxc_syntax::operator::{AssignmentOperator, BinaryOperator}; use oxc_traverse::{Traverse, TraverseCtx}; -use crate::helpers::stack::SparseStack; +use crate::TransformCtx; /// ES2016: Exponentiation Operator /// @@ -45,8 +45,8 @@ use crate::helpers::stack::SparseStack; /// * /// * /// * -pub struct ExponentiationOperator<'a> { - var_declarations: SparseStack>>, +pub struct ExponentiationOperator<'a, 'ctx> { + ctx: &'ctx TransformCtx<'a>, } #[derive(Debug)] @@ -55,44 +55,13 @@ struct Exploded<'a> { uid: Expression<'a>, } -impl<'a> ExponentiationOperator<'a> { - pub fn new() -> Self { - Self { var_declarations: SparseStack::new() } +impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { ctx } } } -impl<'a> Traverse<'a> for ExponentiationOperator<'a> { - #[inline] // Inline because it's no-op in release mode - fn exit_program(&mut self, _program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) { - debug_assert!(self.var_declarations.len() == 1); - debug_assert!(self.var_declarations.last().is_none()); - } - - fn enter_statements( - &mut self, - _statements: &mut Vec<'a, Statement<'a>>, - _ctx: &mut TraverseCtx<'a>, - ) { - self.var_declarations.push(None); - } - - fn exit_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if let Some(declarations) = self.var_declarations.pop() { - debug_assert!(!declarations.is_empty()); - let variable = ctx.ast.alloc_variable_declaration( - SPAN, - VariableDeclarationKind::Var, - declarations, - false, - ); - statements.insert(0, Statement::VariableDeclaration(variable)); - } - } - +impl<'a, 'ctx> Traverse<'a> for ExponentiationOperator<'a, 'ctx> { // NOTE: Bail bigint arguments to `Math.pow`, which are runtime errors. fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { match expr { @@ -139,7 +108,7 @@ impl<'a> Traverse<'a> for ExponentiationOperator<'a> { } } -impl<'a> ExponentiationOperator<'a> { +impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> { fn clone_expression(expr: &Expression<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { match expr { Expression::Identifier(ident) => ctx.ast.expression_from_identifier_reference( @@ -325,17 +294,8 @@ impl<'a> ExponentiationOperator<'a> { ctx.generate_uid_in_current_scope(name, SymbolFlags::FunctionScopedVariable); let symbol_name = ctx.ast.atom(ctx.symbols().get_name(symbol_id)); - { - // var _name; - let binding_identifier = - BindingIdentifier::new_with_symbol_id(SPAN, symbol_name.clone(), symbol_id); - let kind = VariableDeclarationKind::Var; - let id = ctx.ast.binding_pattern_kind_from_binding_identifier(binding_identifier); - let id = ctx.ast.binding_pattern(id, NONE, false); - self.var_declarations - .last_mut_or_init(|| ctx.ast.vec()) - .push(ctx.ast.variable_declarator(SPAN, kind, id, None, false)); - } + // var _name; + self.ctx.var_declarations.insert_declarator(symbol_name.clone(), symbol_id, None, ctx); let ident = ctx.create_reference_id(SPAN, symbol_name, Some(symbol_id), ReferenceFlags::Read); diff --git a/crates/oxc_transformer/src/es2016/mod.rs b/crates/oxc_transformer/src/es2016/mod.rs index 39bcb10f4..ddbc9ce58 100644 --- a/crates/oxc_transformer/src/es2016/mod.rs +++ b/crates/oxc_transformer/src/es2016/mod.rs @@ -3,51 +3,25 @@ mod options; pub use exponentiation_operator::ExponentiationOperator; pub use options::ES2016Options; -use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_traverse::{Traverse, TraverseCtx}; -pub struct ES2016<'a> { +use crate::TransformCtx; + +pub struct ES2016<'a, 'ctx> { options: ES2016Options, // Plugins - exponentiation_operator: ExponentiationOperator<'a>, + exponentiation_operator: ExponentiationOperator<'a, 'ctx>, } -impl<'a> ES2016<'a> { - pub fn new(options: ES2016Options) -> Self { - Self { exponentiation_operator: ExponentiationOperator::new(), options } +impl<'a, 'ctx> ES2016<'a, 'ctx> { + pub fn new(options: ES2016Options, ctx: &'ctx TransformCtx<'a>) -> Self { + Self { exponentiation_operator: ExponentiationOperator::new(ctx), options } } } -impl<'a> Traverse<'a> for ES2016<'a> { - #[inline] // Inline because it's no-op in release mode - fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { - if self.options.exponentiation_operator { - self.exponentiation_operator.exit_program(program, ctx); - } - } - - fn enter_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.exponentiation_operator { - self.exponentiation_operator.enter_statements(statements, ctx); - } - } - - fn exit_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.exponentiation_operator { - self.exponentiation_operator.exit_statements(statements, ctx); - } - } - +impl<'a, 'ctx> Traverse<'a> for ES2016<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if self.options.exponentiation_operator { self.exponentiation_operator.enter_expression(expr, ctx); diff --git a/crates/oxc_transformer/src/es2020/mod.rs b/crates/oxc_transformer/src/es2020/mod.rs index 094bf02d8..e8ca8c761 100644 --- a/crates/oxc_transformer/src/es2020/mod.rs +++ b/crates/oxc_transformer/src/es2020/mod.rs @@ -3,51 +3,25 @@ mod options; pub use nullish_coalescing_operator::NullishCoalescingOperator; pub use options::ES2020Options; -use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_traverse::{Traverse, TraverseCtx}; -pub struct ES2020<'a> { +use crate::TransformCtx; + +pub struct ES2020<'a, 'ctx> { options: ES2020Options, // Plugins - nullish_coalescing_operator: NullishCoalescingOperator<'a>, + nullish_coalescing_operator: NullishCoalescingOperator<'a, 'ctx>, } -impl<'a> ES2020<'a> { - pub fn new(options: ES2020Options) -> Self { - Self { nullish_coalescing_operator: NullishCoalescingOperator::new(), options } +impl<'a, 'ctx> ES2020<'a, 'ctx> { + pub fn new(options: ES2020Options, ctx: &'ctx TransformCtx<'a>) -> Self { + Self { nullish_coalescing_operator: NullishCoalescingOperator::new(ctx), options } } } -impl<'a> Traverse<'a> for ES2020<'a> { - #[inline] // Inline because it's no-op in release mode - fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { - if self.options.nullish_coalescing_operator { - self.nullish_coalescing_operator.exit_program(program, ctx); - } - } - - fn enter_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.nullish_coalescing_operator { - self.nullish_coalescing_operator.enter_statements(statements, ctx); - } - } - - fn exit_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.nullish_coalescing_operator { - self.nullish_coalescing_operator.exit_statements(statements, ctx); - } - } - +impl<'a, 'ctx> Traverse<'a> for ES2020<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if self.options.nullish_coalescing_operator { self.nullish_coalescing_operator.enter_expression(expr, ctx); diff --git a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs index 41613b8a4..66e6a4fcf 100644 --- a/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs +++ b/crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs @@ -28,57 +28,26 @@ //! * Babel plugin implementation: //! * Nullish coalescing TC39 proposal: -use oxc_allocator::{CloneIn, Vec}; +use oxc_allocator::CloneIn; use oxc_ast::{ast::*, NONE}; use oxc_semantic::{ReferenceFlags, ScopeFlags, ScopeId, SymbolFlags}; use oxc_span::SPAN; use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator}; use oxc_traverse::{Ancestor, Traverse, TraverseCtx}; -use crate::helpers::stack::SparseStack; +use crate::TransformCtx; -pub struct NullishCoalescingOperator<'a> { - var_declarations: SparseStack>>, +pub struct NullishCoalescingOperator<'a, 'ctx> { + ctx: &'ctx TransformCtx<'a>, } -impl<'a> NullishCoalescingOperator<'a> { - pub fn new() -> Self { - Self { var_declarations: SparseStack::new() } +impl<'a, 'ctx> NullishCoalescingOperator<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { ctx } } } -impl<'a> Traverse<'a> for NullishCoalescingOperator<'a> { - #[inline] // Inline because it's no-op in release mode - fn exit_program(&mut self, _program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) { - debug_assert!(self.var_declarations.len() == 1); - debug_assert!(self.var_declarations.last().is_none()); - } - - fn enter_statements( - &mut self, - _stmts: &mut Vec<'a, Statement<'a>>, - _ctx: &mut TraverseCtx<'a>, - ) { - self.var_declarations.push(None); - } - - fn exit_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if let Some(declarations) = self.var_declarations.pop() { - debug_assert!(!declarations.is_empty()); - let variable = ctx.ast.alloc_variable_declaration( - SPAN, - VariableDeclarationKind::Var, - declarations, - false, - ); - statements.insert(0, Statement::VariableDeclaration(variable)); - } - } - +impl<'a, 'ctx> Traverse<'a> for NullishCoalescingOperator<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { // left ?? right if !matches!(expr, Expression::LogicalExpression(logical_expr) if logical_expr.operator == LogicalOperator::Coalesce) @@ -156,17 +125,14 @@ impl<'a> Traverse<'a> for NullishCoalescingOperator<'a> { // `(x) => x;` -> `((x) => x)();` new_expr = ctx.ast.expression_call(SPAN, arrow_function, NONE, ctx.ast.vec(), false); } else { - let kind = VariableDeclarationKind::Var; - self.var_declarations - .last_mut_or_init(|| ctx.ast.vec()) - .push(ctx.ast.variable_declarator(SPAN, kind, id, None, false)); + self.ctx.var_declarations.insert_declarator_binding_pattern(id, None, ctx); } *expr = new_expr; } } -impl<'a> NullishCoalescingOperator<'a> { +impl<'a, 'ctx> NullishCoalescingOperator<'a, 'ctx> { fn clone_expression(expr: &Expression<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> { match expr { Expression::Identifier(ident) => ctx.ast.expression_from_identifier_reference( diff --git a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs index 93d81632c..1676cf560 100644 --- a/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs +++ b/crates/oxc_transformer/src/es2021/logical_assignment_operators.rs @@ -53,57 +53,26 @@ //! * Babel plugin implementation: //! * Logical Assignment TC39 proposal: -use oxc_allocator::{CloneIn, Vec}; -use oxc_ast::{ast::*, NONE}; +use oxc_allocator::CloneIn; +use oxc_ast::ast::*; use oxc_semantic::{ReferenceFlags, SymbolFlags}; use oxc_span::SPAN; use oxc_syntax::operator::{AssignmentOperator, LogicalOperator}; use oxc_traverse::{Traverse, TraverseCtx}; -use crate::helpers::stack::SparseStack; +use crate::TransformCtx; -pub struct LogicalAssignmentOperators<'a> { - var_declarations: SparseStack>>, +pub struct LogicalAssignmentOperators<'a, 'ctx> { + ctx: &'ctx TransformCtx<'a>, } -impl<'a> LogicalAssignmentOperators<'a> { - pub fn new() -> Self { - Self { var_declarations: SparseStack::new() } +impl<'a, 'ctx> LogicalAssignmentOperators<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { ctx } } } -impl<'a> Traverse<'a> for LogicalAssignmentOperators<'a> { - #[inline] // Inline because it's no-op in release mode - fn exit_program(&mut self, _program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) { - debug_assert!(self.var_declarations.len() == 1); - debug_assert!(self.var_declarations.last().is_none()); - } - - fn enter_statements( - &mut self, - _stmts: &mut Vec<'a, Statement<'a>>, - _ctx: &mut TraverseCtx<'a>, - ) { - self.var_declarations.push(None); - } - - fn exit_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if let Some(declarations) = self.var_declarations.pop() { - debug_assert!(!declarations.is_empty()); - let variable = ctx.ast.alloc_variable_declaration( - SPAN, - VariableDeclarationKind::Var, - declarations, - false, - ); - statements.insert(0, Statement::VariableDeclaration(variable)); - } - } - +impl<'a, 'ctx> Traverse<'a> for LogicalAssignmentOperators<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { let Expression::AssignmentExpression(assignment_expr) = expr else { return }; @@ -154,7 +123,7 @@ impl<'a> Traverse<'a> for LogicalAssignmentOperators<'a> { } } -impl<'a> LogicalAssignmentOperators<'a> { +impl<'a, 'ctx> LogicalAssignmentOperators<'a, 'ctx> { fn convert_identifier( ident: &IdentifierReference<'a>, ctx: &mut TraverseCtx<'a>, @@ -390,15 +359,7 @@ impl<'a> LogicalAssignmentOperators<'a> { let symbol_name = ctx.ast.atom(ctx.symbols().get_name(symbol_id)); // var _name; - let binding_identifier = - BindingIdentifier::new_with_symbol_id(SPAN, symbol_name.clone(), symbol_id); - - let kind = VariableDeclarationKind::Var; - let id = ctx.ast.binding_pattern_kind_from_binding_identifier(binding_identifier); - let id = ctx.ast.binding_pattern(id, NONE, false); - self.var_declarations - .last_mut_or_init(|| ctx.ast.vec()) - .push(ctx.ast.variable_declarator(SPAN, kind, id, None, false)); + self.ctx.var_declarations.insert_declarator(symbol_name.clone(), symbol_id, None, ctx); // _name = name Some(ctx.create_reference_id(SPAN, symbol_name, Some(symbol_id), ReferenceFlags::Write)) diff --git a/crates/oxc_transformer/src/es2021/mod.rs b/crates/oxc_transformer/src/es2021/mod.rs index c8d1f7b95..f90cb9ebb 100644 --- a/crates/oxc_transformer/src/es2021/mod.rs +++ b/crates/oxc_transformer/src/es2021/mod.rs @@ -3,51 +3,25 @@ mod options; pub use logical_assignment_operators::LogicalAssignmentOperators; pub use options::ES2021Options; -use oxc_allocator::Vec; use oxc_ast::ast::*; use oxc_traverse::{Traverse, TraverseCtx}; -pub struct ES2021<'a> { +use crate::TransformCtx; + +pub struct ES2021<'a, 'ctx> { options: ES2021Options, // Plugins - logical_assignment_operators: LogicalAssignmentOperators<'a>, + logical_assignment_operators: LogicalAssignmentOperators<'a, 'ctx>, } -impl<'a> ES2021<'a> { - pub fn new(options: ES2021Options) -> Self { - Self { logical_assignment_operators: LogicalAssignmentOperators::new(), options } +impl<'a, 'ctx> ES2021<'a, 'ctx> { + pub fn new(options: ES2021Options, ctx: &'ctx TransformCtx<'a>) -> Self { + Self { logical_assignment_operators: LogicalAssignmentOperators::new(ctx), options } } } -impl<'a> Traverse<'a> for ES2021<'a> { - #[inline] // Inline because it's no-op in release mode - fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { - if self.options.logical_assignment_operators { - self.logical_assignment_operators.exit_program(program, ctx); - } - } - - fn enter_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.logical_assignment_operators { - self.logical_assignment_operators.enter_statements(statements, ctx); - } - } - - fn exit_statements( - &mut self, - statements: &mut Vec<'a, Statement<'a>>, - ctx: &mut TraverseCtx<'a>, - ) { - if self.options.logical_assignment_operators { - self.logical_assignment_operators.exit_statements(statements, ctx); - } - } - +impl<'a, 'ctx> Traverse<'a> for ES2021<'a, 'ctx> { fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if self.options.logical_assignment_operators { self.logical_assignment_operators.enter_expression(expr, ctx); diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index e1c1f655e..159017bb9 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -9,6 +9,7 @@ //! * // Core +mod common; mod compiler_assumptions; mod context; mod options; @@ -32,6 +33,7 @@ mod helpers { use std::path::Path; +use common::Common; use es2016::ES2016; use es2018::ES2018; use es2019::ES2019; @@ -91,13 +93,14 @@ impl<'a> Transformer<'a> { let mut transformer = TransformerImpl { x0_typescript: TypeScript::new(self.options.typescript, &self.ctx), x1_react: React::new(self.options.react, &self.ctx), - x2_es2021: ES2021::new(self.options.es2021), - x2_es2020: ES2020::new(self.options.es2020), + x2_es2021: ES2021::new(self.options.es2021, &self.ctx), + x2_es2020: ES2020::new(self.options.es2020, &self.ctx), x2_es2019: ES2019::new(self.options.es2019), x2_es2018: ES2018::new(self.options.es2018), - x2_es2016: ES2016::new(self.options.es2016), + x2_es2016: ES2016::new(self.options.es2016, &self.ctx), x3_es2015: ES2015::new(self.options.es2015), x4_regexp: RegExp::new(self.options.regexp, &self.ctx), + common: Common::new(&self.ctx), }; let (symbols, scopes) = traverse_mut(&mut transformer, allocator, program, symbols, scopes); @@ -109,13 +112,14 @@ struct TransformerImpl<'a, 'ctx> { // NOTE: all callbacks must run in order. x0_typescript: TypeScript<'a, 'ctx>, x1_react: React<'a, 'ctx>, - x2_es2021: ES2021<'a>, - x2_es2020: ES2020<'a>, + x2_es2021: ES2021<'a, 'ctx>, + x2_es2020: ES2020<'a, 'ctx>, x2_es2019: ES2019, x2_es2018: ES2018, - x2_es2016: ES2016<'a>, + x2_es2016: ES2016<'a, 'ctx>, x3_es2015: ES2015<'a>, x4_regexp: RegExp<'a, 'ctx>, + common: Common<'a, 'ctx>, } impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { @@ -127,10 +131,8 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { self.x1_react.exit_program(program, ctx); self.x0_typescript.exit_program(program, ctx); - self.x2_es2021.exit_program(program, ctx); - self.x2_es2020.exit_program(program, ctx); - self.x2_es2016.exit_program(program, ctx); self.x3_es2015.exit_program(program, ctx); + self.common.exit_program(program, ctx); } // ALPHASORT @@ -300,11 +302,9 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { } fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { + self.common.enter_statements(stmts, ctx); self.x0_typescript.enter_statements(stmts, ctx); self.x1_react.enter_statements(stmts, ctx); - self.x2_es2021.enter_statements(stmts, ctx); - self.x2_es2020.enter_statements(stmts, ctx); - self.x2_es2016.enter_statements(stmts, ctx); } fn exit_arrow_function_expression( @@ -334,9 +334,7 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { self.x0_typescript.exit_statements(stmts, ctx); self.x1_react.exit_statements(stmts, ctx); - self.x2_es2021.exit_statements(stmts, ctx); - self.x2_es2020.exit_statements(stmts, ctx); - self.x2_es2016.exit_statements(stmts, ctx); + self.common.exit_statements(stmts, ctx); } fn enter_tagged_template_expression( diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index ad7d6e54a..58d136f04 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1456,7 +1456,12 @@ after transform: SymbolId(21): [ReferenceId(132), ReferenceId(133), ReferenceId( rebuilt : SymbolId(14): [ReferenceId(123), ReferenceId(127)] * logical-assignment/null-coalescing/input.js -x Output mismatch +Symbol reference IDs mismatch: +after transform: SymbolId(17): [ReferenceId(86), ReferenceId(87), ReferenceId(90)] +rebuilt : SymbolId(10): [ReferenceId(73), ReferenceId(79)] +Symbol reference IDs mismatch: +after transform: SymbolId(20): [ReferenceId(94), ReferenceId(95), ReferenceId(98)] +rebuilt : SymbolId(13): [ReferenceId(88), ReferenceId(94)] * logical-assignment/null-coalescing-without-other/input.js Symbol reference IDs mismatch: