Skip to content
Draft
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
6 changes: 2 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//// [parserArrowFunctionExpression10.ts]
//// [fileJs.js]
a || ((e)=>f);
a;
//// [fileTs.ts]
a || ((e)=>f);
a;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//// [parserArrowFunctionExpression12.ts]
//// [fileJs.js]
a || ((d)=>e);
a;
//// [fileTs.ts]
a || ((d)=>e);
a;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//// [parserArrowFunctionExpression13.ts]
//// [fileJs.js]
a || (()=>null);
a;
//// [fileTs.ts]
a || (()=>null);
a;
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
//// [parserArrowFunctionExpression8.ts]
//// [fileJs.js]
x || ((z)=>({
z
}));
x;
//// [fileTs.ts]
x || ((z)=>({
z
}));
x;
13 changes: 5 additions & 8 deletions crates/swc_ecma_compat_es2016/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,11 @@ version = "30.0.0"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] }

[dependencies]
swc_common = { version = "17.0.1", path = "../swc_common" }
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
swc_ecma_transforms_base = { version = "30.0.0", path = "../swc_ecma_transforms_base" }
swc_ecma_transforms_macros = { version = "1.0.1", path = "../swc_ecma_transforms_macros" }
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
swc_ecma_visit = { version = "18.0.1", path = "../swc_ecma_visit" }
swc_trace_macro = { version = "2.0.2", path = "../swc_trace_macro" }
tracing = { workspace = true }
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
swc_ecma_transformer = { version = "1.0.0", path = "../swc_ecma_transformer" }
swc_ecma_transforms_base = { version = "30.0.0", path = "../swc_ecma_transforms_base" }
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
tracing = { workspace = true }

[dev-dependencies]
swc_ecma_parser = { version = "27.0.6", path = "../swc_ecma_parser" }
Expand Down
130 changes: 3 additions & 127 deletions crates/swc_ecma_compat_es2016/src/exponentiation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
use swc_common::{util::take::Take, Span, Spanned, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_transforms_base::perf::{ParExplode, Parallel};
use swc_ecma_transforms_macros::parallel;
use swc_ecma_utils::{member_expr, private_ident, ExprFactory};
use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
use swc_trace_macro::swc_trace;

/// `@babel/plugin-transform-exponentiation-operator`
///
Expand All @@ -26,127 +20,9 @@ use swc_trace_macro::swc_trace;
/// x = Math.pow(x, 3);
/// ```
pub fn exponentiation() -> impl Pass {
visit_mut_pass(Exponentiation::default())
}

#[derive(Default)]
struct Exponentiation {
vars: Vec<VarDeclarator>,
}

impl Parallel for Exponentiation {
fn create(&self) -> Self {
Self::default()
}

fn merge(&mut self, other: Self) {
self.vars.extend(other.vars);
}
}

#[swc_trace]
impl ParExplode for Exponentiation {
fn after_one_stmt(&mut self, stmts: &mut Vec<Stmt>) {
if !self.vars.is_empty() {
stmts.push(
VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
decls: self.vars.take(),
declare: false,
..Default::default()
}
.into(),
);
}
}

fn after_one_module_item(&mut self, stmts: &mut Vec<ModuleItem>) {
if !self.vars.is_empty() {
stmts.push(
VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Var,
decls: self.vars.take(),
declare: false,
..Default::default()
}
.into(),
);
}
}
}

#[swc_trace]
#[parallel(explode)]
impl VisitMut for Exponentiation {
noop_visit_mut_type!(fail);

fn visit_mut_expr(&mut self, e: &mut Expr) {
e.visit_mut_children_with(self);

match e {
Expr::Assign(AssignExpr {
span,
left,
op: op @ op!("**="),
right,
}) => {
let lhs: Ident = match left {
_ if left.as_ident().is_some() => left.as_ident().unwrap().clone().into(),

// unimplemented
AssignTarget::Simple(ref e) => {
let ref_ident = private_ident!(e.span(), "ref");

self.vars.push(VarDeclarator {
span: DUMMY_SP,
name: ref_ident.clone().into(),
init: Some(e.clone().into()),
definite: false,
});
ref_ident
}

left => {
*e = AssignExpr {
span: *span,
left: left.take(),
op: op!("="),
right: right.take(),
}
.into();
return;
}
};

*op = op!("=");
*right = Box::new(mk_call(*span, Box::new(lhs.into()), right.take()));
}
Expr::Bin(BinExpr {
span,
left,
op: op!("**"),
right,
}) => {
*e = mk_call(*span, left.take(), right.take());
}
_ => {}
}
}
}

#[tracing::instrument(level = "debug", skip_all)]
fn mk_call(span: Span, left: Box<Expr>, right: Box<Expr>) -> Expr {
// Math.pow()
CallExpr {
span,
callee: member_expr!(Default::default(), span, Math.pow).as_callee(),

args: vec![left.as_arg(), right.as_arg()],
..Default::default()
}
.into()
let mut options = swc_ecma_transformer::Options::default();
options.env.es2016.exponentiation_operator = true;
options.into_pass()
}

#[cfg(test)]
Expand Down
6 changes: 4 additions & 2 deletions crates/swc_ecma_preset_env/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use swc_ecma_transforms::{
bugfixes,
class_fields_use_set::class_fields_use_set,
es2015::{self, generator::generator},
es2016, es2017, es2018, es2019, es2020, es2022, es3,
es2017, es2018, es2019, es2020, es2022, es3,
},
Assumptions,
};
Expand Down Expand Up @@ -209,7 +209,9 @@ where
);

// ES2016
let pass = add!(pass, ExponentiationOperator, es2016::exponentiation());
if !caniuse(Feature::ExponentiationOperator) {
options.env.es2016.exponentiation_operator = true;
}

// Single-pass compiler
let pass = (pass, options.into_pass());
Expand Down
17 changes: 10 additions & 7 deletions crates/swc_ecma_transformer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ version = "1.0.0"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] }

[dependencies]
swc_atoms = { version = "9.0.0", path = "../swc_atoms" }
swc_common = { version = "17.0.1", path = "../swc_common" }
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
swc_ecma_hooks = { version = "0.2.0", path = "../swc_ecma_hooks" }
rustc-hash = { workspace = true }
swc_atoms = { version = "9.0.0", path = "../swc_atoms" }
swc_common = { version = "17.0.1", path = "../swc_common" }
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
swc_ecma_hooks = { version = "0.2.0", path = "../swc_ecma_hooks" }
swc_ecma_transforms_base = { version = "30.0.0", path = "../swc_ecma_transforms_base" }
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
swc_ecma_visit = { version = "18.0.1", path = "../swc_ecma_visit" }
tracing = { workspace = true }
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
swc_ecma_visit = { version = "18.0.1", path = "../swc_ecma_visit", features = [
"path",
] }
tracing = { workspace = true }
3 changes: 3 additions & 0 deletions crates/swc_ecma_transformer/src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub use self::statement_injector::*;

mod statement_injector;
126 changes: 126 additions & 0 deletions crates/swc_ecma_transformer/src/common/statement_injector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//! Utility transform to add new statements before or after the specified
//! statement.
//!
//! `StatementInjectorStore` contains a `FxHashMap<Address,
//! Vec<AdjacentStatement>>`. It is stored on `TransformCtx`.
//!
//! `StatementInjector` transform inserts new statements before or after a
//! statement which is determined by the address of the statement.
//!
//! Other transforms can add statements to the store with following methods:
//!
//! ```rs
//! self.ctx.statement_injector.insert_before(address, statement);
//! self.ctx.statement_injector.insert_after(address, statement);
//! self.ctx.statement_injector.insert_many_after(address, statements);
//! ```

use rustc_hash::FxHashMap;
use swc_ecma_ast::*;
use swc_ecma_hooks::VisitMutHook;

use crate::TraverseCtx;

#[derive(Debug, Default)]
pub struct StmtInjector {}

#[derive(Debug)]
enum Direction {
Before,
After,
}

#[derive(Debug)]
struct AdjacentStmt {
stmt: Stmt,
direction: Direction,
}

/// Store for Stmts to be added to the Stmts.
///
/// The key is the address of the statement in the AST, represented as a
/// pointer.
#[derive(Default)]
pub struct StmtInjectorStore {
/// Map from statement address to adjacent statements to insert
stmts: FxHashMap<usize, Vec<AdjacentStmt>>,
}

impl StmtInjectorStore {
/// Insert a statement before the statement at the given address
pub fn insert_before(&mut self, address: usize, stmt: Stmt) {
self.stmts.entry(address).or_default().push(AdjacentStmt {
stmt,
direction: Direction::Before,
});
}

/// Insert a statement after the statement at the given address
pub fn insert_after(&mut self, address: usize, stmt: Stmt) {
self.stmts.entry(address).or_default().push(AdjacentStmt {
stmt,
direction: Direction::After,
});
}

/// Insert multiple statements after the statement at the given address
pub fn insert_many_after(&mut self, address: usize, stmts: Vec<Stmt>) {
let entry = self.stmts.entry(address).or_default();
for stmt in stmts {
entry.push(AdjacentStmt {
stmt,
direction: Direction::After,
});
}
}

/// Get all statements to be inserted at the given address
fn take_stmts(&mut self, address: usize) -> Option<Vec<AdjacentStmt>> {
self.stmts.remove(&address)
}
}

impl VisitMutHook<TraverseCtx> for StmtInjector {
fn enter_stmts(&mut self, stmts: &mut Vec<Stmt>, ctx: &mut TraverseCtx) {
let mut i = 0;
while i < stmts.len() {
let stmt = &stmts[i];
let address = stmt as *const Stmt as usize;

// Check if there are any statements to insert at this address
if let Some(adjacent_stmts) = ctx.statement_injector.take_stmts(address) {
let mut before_stmts = Vec::new();
let mut after_stmts = Vec::new();

// Separate statements by direction
for adjacent in adjacent_stmts {
match adjacent.direction {
Direction::Before => before_stmts.push(adjacent.stmt),
Direction::After => after_stmts.push(adjacent.stmt),
}
}

// Insert statements before
let before_count = before_stmts.len();
if before_count > 0 {
// Insert all before statements at position i
for (offset, stmt) in before_stmts.into_iter().enumerate() {
stmts.insert(i + offset, stmt);
}
// Move index forward by the number of inserted statements
i += before_count;
}

// Insert statements after
if !after_stmts.is_empty() {
// Insert all after statements at position i + 1
for (offset, stmt) in after_stmts.into_iter().enumerate() {
stmts.insert(i + 1 + offset, stmt);
}
}
}

i += 1;
}
}
}
Loading
Loading