Skip to content

Commit

Permalink
refactor(transformer): add TransformerCtx struct for easier access to…
Browse files Browse the repository at this point in the history
… symbols and scopes
  • Loading branch information
Boshen committed Oct 19, 2023
1 parent 94792e9 commit 46a5c42
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 43 deletions.
5 changes: 3 additions & 2 deletions crates/oxc_transformer/examples/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ fn main() {
println!("{printed}");

let semantic = SemanticBuilder::new(&source_text, source_type).build(&ret.program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));

let program = allocator.alloc(ret.program);
let transform_options =
TransformOptions { target: TransformTarget::ES2015, ..TransformOptions::default() };
Transformer::new(&allocator, source_type, &symbols, transform_options).build(program);
Transformer::new(&allocator, source_type, &symbols, &scopes, transform_options).build(program);
let printed = Codegen::<false>::new(source_text.len(), codegen_options).build(program);
println!("Transformed:\n");
println!("{printed}");
Expand Down
11 changes: 11 additions & 0 deletions crates/oxc_transformer/src/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use std::{cell::RefCell, rc::Rc};

use oxc_ast::AstBuilder;
use oxc_semantic::{ScopeTree, SymbolTable};

#[derive(Clone)]
pub struct TransformerCtx<'a> {
pub ast: Rc<AstBuilder<'a>>,
pub symbols: Rc<RefCell<SymbolTable>>,
pub scopes: Rc<RefCell<ScopeTree>>,
}
18 changes: 9 additions & 9 deletions crates/oxc_transformer/src/es2016/exponentiation_operator.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::{cell::RefCell, rc::Rc};
use std::rc::Rc;

use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder};
use oxc_semantic::SymbolTable;
use oxc_span::{Atom, Span};
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};

use crate::{
context::TransformerCtx,
options::{TransformOptions, TransformTarget},
utils::CreateVars,
};
Expand All @@ -19,7 +19,7 @@ use crate::{
/// * <https://github.com/babel/babel/blob/main/packages/babel-helper-builder-binary-assignment-operator-visitor>
pub struct ExponentiationOperator<'a> {
ast: Rc<AstBuilder<'a>>,
symbols: Rc<RefCell<SymbolTable>>,
ctx: TransformerCtx<'a>,
vars: Vec<'a, VariableDeclarator<'a>>,
}

Expand All @@ -29,8 +29,8 @@ struct Exploded<'a> {
}

impl<'a> CreateVars<'a> for ExponentiationOperator<'a> {
fn ast(&self) -> &AstBuilder<'a> {
&self.ast
fn ctx(&self) -> &TransformerCtx<'a> {
&self.ctx
}

fn vars_mut(&mut self) -> &mut Vec<'a, VariableDeclarator<'a>> {
Expand All @@ -41,12 +41,12 @@ impl<'a> CreateVars<'a> for ExponentiationOperator<'a> {
impl<'a> ExponentiationOperator<'a> {
pub fn new(
ast: Rc<AstBuilder<'a>>,
symbols: Rc<RefCell<SymbolTable>>,
ctx: TransformerCtx<'a>,
options: &TransformOptions,
) -> Option<Self> {
(options.target < TransformTarget::ES2016 || options.exponentiation_operator).then(|| {
let vars = ast.new_vec();
Self { ast, symbols, vars }
Self { ast, ctx, vars }
})
}

Expand Down Expand Up @@ -163,7 +163,7 @@ impl<'a> ExponentiationOperator<'a> {
if ident
.reference_id
.get()
.is_some_and(|reference_id| self.symbols.borrow().has_binding(reference_id))
.is_some_and(|reference_id| self.ctx.symbols.borrow().has_binding(reference_id))
{
// this variable is declared in scope so we can be 100% sure
// that evaluating it multiple times won't trigger a getter
Expand All @@ -185,7 +185,7 @@ impl<'a> ExponentiationOperator<'a> {
// Super cannot be directly assigned so lets return it also
if matches!(expr, Expression::Super(_))
|| matches!(&expr, Expression::Identifier(ident) if
ident.reference_id.get().is_some_and(|reference_id| self.symbols.borrow().has_binding(reference_id)))
ident.reference_id.get().is_some_and(|reference_id| self.ctx.symbols.borrow().has_binding(reference_id)))
{
return Some(expr);
}
Expand Down
21 changes: 12 additions & 9 deletions crates/oxc_transformer/src/es2020/nullish_coalescing_operator.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use serde::Deserialize;
use std::{cell::RefCell, rc::Rc};
use std::rc::Rc;

use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder};
use oxc_semantic::SymbolTable;
use oxc_span::Span;
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator};

use crate::{utils::CreateVars, TransformOptions, TransformTarget};
use crate::{
context::TransformerCtx,
options::{TransformOptions, TransformTarget},
utils::CreateVars,
};

#[derive(Debug, Default, Clone, Copy, Deserialize)]
pub struct NullishCoalescingOperatorOptions {
Expand All @@ -26,13 +29,13 @@ pub struct NullishCoalescingOperator<'a> {
no_document_all: bool,

ast: Rc<AstBuilder<'a>>,
symbols: Rc<RefCell<SymbolTable>>,
ctx: TransformerCtx<'a>,
vars: Vec<'a, VariableDeclarator<'a>>,
}

impl<'a> CreateVars<'a> for NullishCoalescingOperator<'a> {
fn ast(&self) -> &AstBuilder<'a> {
&self.ast
fn ctx(&self) -> &TransformerCtx<'a> {
&self.ctx
}

fn vars_mut(&mut self) -> &mut Vec<'a, VariableDeclarator<'a>> {
Expand All @@ -43,15 +46,15 @@ impl<'a> CreateVars<'a> for NullishCoalescingOperator<'a> {
impl<'a> NullishCoalescingOperator<'a> {
pub fn new(
ast: Rc<AstBuilder<'a>>,
symbols: Rc<RefCell<SymbolTable>>,
ctx: TransformerCtx<'a>,
options: &TransformOptions,
) -> Option<Self> {
(options.target < TransformTarget::ES2020 || options.nullish_coalescing_operator.is_some())
.then(|| {
let no_document_all = options.assumptions.no_document_all
|| options.nullish_coalescing_operator.is_some_and(|o| o.loose);
let vars = ast.new_vec();
Self { no_document_all, ast, symbols, vars }
Self { no_document_all, ast, ctx, vars }
})
}

Expand All @@ -67,7 +70,7 @@ impl<'a> NullishCoalescingOperator<'a> {
let assignment;

// skip creating extra reference when `left` is static
if self.symbols.borrow().is_static(&logical_expr.left) {
if self.ctx.symbols.borrow().is_static(&logical_expr.left) {
reference = self.ast.copy(&logical_expr.left);
assignment = self.ast.copy(&logical_expr.left);
} else {
Expand Down
22 changes: 14 additions & 8 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//! * <https://babel.dev/docs/presets>
//! * <https://github.com/microsoft/TypeScript/blob/main/src/compiler/transformer.ts>

mod context;
mod es2015;
mod es2016;
mod es2019;
Expand All @@ -25,14 +26,14 @@ use std::{cell::RefCell, rc::Rc};

use oxc_allocator::{Allocator, Vec};
use oxc_ast::{ast::*, AstBuilder, VisitMut};
use oxc_semantic::SymbolTable;
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_span::SourceType;

use crate::{
es2015::ShorthandProperties, es2016::ExponentiationOperator, es2019::OptionalCatchBinding,
es2020::NullishCoalescingOperator, es2021::LogicalAssignmentOperators,
es2022::ClassStaticBlock, react_jsx::ReactJsx, regexp::RegexpFlags, typescript::TypeScript,
utils::CreateVars,
context::TransformerCtx, es2015::ShorthandProperties, es2016::ExponentiationOperator,
es2019::OptionalCatchBinding, es2020::NullishCoalescingOperator,
es2021::LogicalAssignmentOperators, es2022::ClassStaticBlock, react_jsx::ReactJsx,
regexp::RegexpFlags, typescript::TypeScript, utils::CreateVars,
};

pub use crate::{
Expand All @@ -41,7 +42,6 @@ pub use crate::{
react_jsx::{ReactJsxOptions, ReactJsxRuntime},
};

#[derive(Default)]
pub struct Transformer<'a> {
#[allow(unused)]
typescript: Option<TypeScript<'a>>,
Expand All @@ -68,18 +68,24 @@ impl<'a> Transformer<'a> {
allocator: &'a Allocator,
source_type: SourceType,
symbols: &Rc<RefCell<SymbolTable>>,
scopes: &Rc<RefCell<ScopeTree>>,
options: TransformOptions,
) -> Self {
let ast = Rc::new(AstBuilder::new(allocator));
let ctx = TransformerCtx {
ast: Rc::clone(&ast),
symbols: Rc::clone(symbols),
scopes: Rc::clone(scopes),
};
Self {
typescript: source_type.is_typescript().then(|| TypeScript::new(Rc::clone(&ast))),
react_jsx: options.react_jsx.map(|options| ReactJsx::new(Rc::clone(&ast), options)),
regexp_flags: RegexpFlags::new(Rc::clone(&ast), &options),
es2022_class_static_block: es2022::ClassStaticBlock::new(Rc::clone(&ast), &options),
es2021_logical_assignment_operators: LogicalAssignmentOperators::new(Rc::clone(&ast), &options),
es2020_nullish_coalescing_operators: NullishCoalescingOperator::new(Rc::clone(&ast), Rc::clone(symbols), &options),
es2020_nullish_coalescing_operators: NullishCoalescingOperator::new(Rc::clone(&ast), ctx.clone(), &options),
es2019_optional_catch_binding: OptionalCatchBinding::new(Rc::clone(&ast), &options),
es2016_exponentiation_operator: ExponentiationOperator::new(Rc::clone(&ast), Rc::clone(symbols), &options),
es2016_exponentiation_operator: ExponentiationOperator::new(Rc::clone(&ast), ctx.clone(), &options),
es2015_shorthand_properties: ShorthandProperties::new(Rc::clone(&ast), &options),
}
}
Expand Down
6 changes: 4 additions & 2 deletions crates/oxc_transformer/src/tester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ impl Tester {
let program = Parser::new(&self.allocator, source_text, self.source_type).parse().program;

let semantic = SemanticBuilder::new(source_text, self.source_type).build(&program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));

let program = self.allocator.alloc(program);
Transformer::new(&self.allocator, self.source_type, &symbols, self.options).build(program);
Transformer::new(&self.allocator, self.source_type, &symbols, &scopes, self.options)
.build(program);
Codegen::<false>::new(source_text.len(), CodegenOptions).build(program)
}

Expand Down
16 changes: 9 additions & 7 deletions crates/oxc_transformer/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::mem;

use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder};
use oxc_ast::ast::*;
use oxc_span::{Atom, Span};

use crate::context::TransformerCtx;

// TODO:
// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L543>
pub fn generate_uid_based_on_node(expr: &Expression) -> Atom {
Expand Down Expand Up @@ -52,19 +54,19 @@ impl GatherNodeParts for PrivateIdentifier {
}

pub trait CreateVars<'a> {
fn ast(&self) -> &AstBuilder<'a>;
fn ctx(&self) -> &TransformerCtx<'a>;

fn vars_mut(&mut self) -> &mut Vec<'a, VariableDeclarator<'a>>;

fn add_vars_to_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
if self.vars_mut().is_empty() {
return;
}
let new_vec = self.ast().new_vec();
let new_vec = self.ctx().ast.new_vec();
let decls = mem::replace(self.vars_mut(), new_vec);
let kind = VariableDeclarationKind::Var;
let decl =
self.ast().variable_declaration(Span::default(), kind, decls, Modifiers::empty());
self.ctx().ast.variable_declaration(Span::default(), kind, decls, Modifiers::empty());
let stmt = Statement::Declaration(Declaration::VariableDeclaration(decl));
stmts.insert(0, stmt);
}
Expand All @@ -75,10 +77,10 @@ pub trait CreateVars<'a> {

// Add `var name` to scope
let binding_identifier = BindingIdentifier::new(Span::default(), name.clone());
let binding_pattern_kind = self.ast().binding_pattern_identifier(binding_identifier);
let binding = self.ast().binding_pattern(binding_pattern_kind, None, false);
let binding_pattern_kind = self.ctx().ast.binding_pattern_identifier(binding_identifier);
let binding = self.ctx().ast.binding_pattern(binding_pattern_kind, None, false);
let kind = VariableDeclarationKind::Var;
let decl = self.ast().variable_declarator(Span::default(), kind, binding, None, false);
let decl = self.ctx().ast.variable_declarator(Span::default(), kind, binding, None, false);
self.vars_mut().push(decl);
name
}
Expand Down
5 changes: 3 additions & 2 deletions crates/oxc_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,12 @@ impl Oxc {
// FIXME: this should not be duplicated with the linter semantic,
// we need to fix the API so symbols and scopes can be shared.
let semantic = SemanticBuilder::new(source_text, source_type).build(program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let options =
TransformOptions { target: TransformTarget::ES2015, ..TransformOptions::default() };
Transformer::new(&allocator, source_type, &symbols, options).build(program);
Transformer::new(&allocator, source_type, &symbols, &scopes, options).build(program);
}

let program = allocator.alloc(program);
Expand Down
5 changes: 3 additions & 2 deletions tasks/benchmark/benches/transformer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ fn bench_transformer(criterion: &mut Criterion) {
let program = Parser::new(&allocator, source_text, source_type).parse().program;
let semantic =
SemanticBuilder::new(source_text, source_type).build(&program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let program = allocator.alloc(program);
let transform_options = TransformOptions::default();
Transformer::new(&allocator, source_type, &symbols, transform_options)
Transformer::new(&allocator, source_type, &symbols, &scopes, transform_options)
.build(black_box(program));
allocator
});
Expand Down
5 changes: 3 additions & 2 deletions tasks/transform_conformance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,11 @@ impl TestCase {
// Transform input.js
let program = Parser::new(&allocator, &input, source_type).parse().program;
let semantic = SemanticBuilder::new(&input, source_type).build(&program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let (symbols, scopes) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let scopes = Rc::new(RefCell::new(scopes));
let program = allocator.alloc(program);
Transformer::new(&allocator, source_type, &symbols, self.transform_options())
Transformer::new(&allocator, source_type, &symbols, &scopes, self.transform_options())
.build(program);
let transformed_code = Codegen::<false>::new(input.len(), CodegenOptions).build(program);

Expand Down

0 comments on commit 46a5c42

Please sign in to comment.