Skip to content

Commit 440b391

Browse files
authored
perf(es/compat): Merge regexp pass into Transformer (#11307)
1 parent 45827fa commit 440b391

File tree

10 files changed

+121
-93
lines changed

10 files changed

+121
-93
lines changed

Cargo.lock

Lines changed: 3 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/swc_ecma_compat_common/Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ version = "24.0.0"
1212
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1313

1414
[dependencies]
15-
swc_common = { version = "17.0.1", path = "../swc_common" }
16-
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
17-
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
18-
swc_ecma_visit = { version = "18.0.1", path = "../swc_ecma_visit" }
15+
swc_common = { version = "17.0.1", path = "../swc_common" }
16+
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
17+
swc_ecma_transformer = { version = "0.1.0", path = "../swc_ecma_transformer" }
18+
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1-
use swc_common::util::take::Take;
2-
use swc_ecma_ast::{CallExpr, Expr, Lit, Pass, Regex};
3-
use swc_ecma_utils::{quote_ident, ExprFactory};
4-
use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
1+
use swc_ecma_ast::Pass;
52

63
pub fn regexp(config: Config) -> impl Pass {
7-
visit_mut_pass(RegExp { config })
4+
let mut options = swc_ecma_transformer::Options::default();
5+
6+
let t = &mut options.env.regexp;
7+
t.dot_all_regex = config.dot_all_regex;
8+
t.has_indices = config.has_indices;
9+
t.lookbehind_assertion = config.lookbehind_assertion;
10+
t.named_capturing_groups_regex = config.named_capturing_groups_regex;
11+
t.sticky_regex = config.sticky_regex;
12+
t.unicode_property_regex = config.unicode_property_regex;
13+
t.unicode_regex = config.unicode_regex;
14+
t.unicode_sets_regex = config.unicode_sets_regex;
15+
16+
options.into_pass()
817
}
918

1019
#[derive(Default, Clone, Copy)]
@@ -26,47 +35,3 @@ pub struct Config {
2635
// [RegExp.prototype.unicodeSets](https://github.com/tc39/proposal-regexp-v-flag)
2736
pub unicode_sets_regex: bool,
2837
}
29-
30-
struct RegExp {
31-
config: Config,
32-
}
33-
34-
impl VisitMut for RegExp {
35-
noop_visit_mut_type!(fail);
36-
37-
fn visit_mut_expr(&mut self, expr: &mut Expr) {
38-
expr.visit_mut_children_with(self);
39-
40-
if let Expr::Lit(Lit::Regex(regex)) = expr {
41-
if (self.config.dot_all_regex && regex.flags.contains('s'))
42-
|| (self.config.sticky_regex && regex.flags.contains('y'))
43-
|| (self.config.unicode_regex && regex.flags.contains('u'))
44-
|| (self.config.unicode_sets_regex && regex.flags.contains('v'))
45-
|| (self.config.has_indices && regex.flags.contains('d'))
46-
|| (self.config.named_capturing_groups_regex && regex.exp.contains("(?<"))
47-
|| (self.config.lookbehind_assertion && regex.exp.contains("(?<=")
48-
|| regex.exp.contains("(?<!"))
49-
|| (self.config.unicode_property_regex
50-
&& (regex.exp.contains("\\p{") || regex.exp.contains("\\P{")))
51-
{
52-
let Regex { exp, flags, span } = regex.take();
53-
54-
let exp: Expr = exp.into();
55-
let mut args = vec![exp.into()];
56-
57-
if !flags.is_empty() {
58-
let flags: Expr = flags.into();
59-
args.push(flags.into());
60-
}
61-
62-
*expr = CallExpr {
63-
span,
64-
callee: quote_ident!("RegExp").as_callee(),
65-
args,
66-
..Default::default()
67-
}
68-
.into()
69-
}
70-
}
71-
}
72-
}

crates/swc_ecma_preset_env/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ swc_atoms = { version = "9.0.0", path = "../swc_atoms" }
3939
swc_common = { version = "17.0.1", path = "../swc_common" }
4040
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
4141
swc_ecma_compiler = { version = "8.0.0", path = "../swc_ecma_compiler" }
42+
swc_ecma_transformer = { version = "0.1.0", path = "../swc_ecma_transformer" }
4243
swc_ecma_transforms = { version = "38.0.0", path = "../swc_ecma_transforms", features = [
4344
"compat",
4445
"proposal",

crates/swc_ecma_preset_env/src/lib.rs

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use swc_ecma_transforms::{
1717
class_fields_use_set::class_fields_use_set,
1818
es2015::{self, generator::generator},
1919
es2016, es2017, es2018, es2019, es2020, es2022, es3,
20-
regexp::{self, regexp},
2120
},
2221
Assumptions,
2322
};
@@ -51,6 +50,7 @@ where
5150
C: Comments + Clone,
5251
{
5352
let pass = noop_pass();
53+
let mut options = swc_ecma_transformer::Options::default();
5454

5555
macro_rules! add {
5656
($prev:expr, $feature:ident, $pass:expr) => {{
@@ -114,39 +114,20 @@ where
114114
),
115115
);
116116

117-
let pass = {
118-
let enable_dot_all_regex = !caniuse(Feature::DotAllRegex);
119-
let enable_named_capturing_groups_regex = !caniuse(Feature::NamedCapturingGroupsRegex);
120-
let enable_sticky_regex = !caniuse(Feature::StickyRegex);
121-
let enable_unicode_property_regex = !caniuse(Feature::UnicodePropertyRegex);
122-
let enable_unicode_regex = !caniuse(Feature::UnicodeRegex);
123-
let enable_unicode_sets_regex = !caniuse(Feature::UnicodeSetsRegex);
124-
125-
let enable = enable_dot_all_regex
126-
|| enable_named_capturing_groups_regex
127-
|| enable_sticky_regex
128-
|| enable_unicode_property_regex
129-
|| enable_unicode_regex;
130-
131-
(
132-
pass,
133-
Optional::new(
134-
regexp(regexp::Config {
135-
dot_all_regex: enable_dot_all_regex,
136-
// TODO: add Feature:HasIndicesRegex
137-
has_indices: false,
138-
// TODO: add Feature::LookbehindAssertion
139-
lookbehind_assertion: false,
140-
named_capturing_groups_regex: enable_named_capturing_groups_regex,
141-
sticky_regex: enable_sticky_regex,
142-
unicode_property_regex: enable_unicode_property_regex,
143-
unicode_regex: enable_unicode_regex,
144-
unicode_sets_regex: enable_unicode_sets_regex,
145-
}),
146-
enable,
147-
),
148-
)
149-
};
117+
{
118+
let t = &mut options.env.regexp;
119+
120+
t.dot_all_regex = !caniuse(Feature::DotAllRegex);
121+
t.named_capturing_groups_regex = !caniuse(Feature::NamedCapturingGroupsRegex);
122+
t.sticky_regex = !caniuse(Feature::StickyRegex);
123+
t.unicode_property_regex = !caniuse(Feature::UnicodePropertyRegex);
124+
t.unicode_regex = !caniuse(Feature::UnicodeRegex);
125+
t.unicode_sets_regex = !caniuse(Feature::UnicodeSetsRegex);
126+
// TODO: add Feature:HasIndicesRegex
127+
t.has_indices = false;
128+
// TODO: add Feature::LookbehindAssertion
129+
t.lookbehind_assertion = false;
130+
}
150131

151132
// Proposals
152133

@@ -344,11 +325,13 @@ where
344325
bugfixes::template_literal_caching()
345326
);
346327

347-
add!(
328+
let pass = add!(
348329
pass,
349330
BugfixSafariIdDestructuringCollisionInFunctionExpression,
350331
bugfixes::safari_id_destructuring_collision_in_function_expression()
351-
)
332+
);
333+
334+
(pass, options.into_pass())
352335
}
353336

354337
pub fn transform_from_env<C>(

crates/swc_ecma_preset_env/tests/fixtures/corejs3/usage-regexp/output.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import "core-js/modules/es.regexp.exec.js";
33
import "core-js/modules/es.regexp.to-string.js";
44
var a = RegExp("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})", "u");
55
var b = RegExp(".", "s");
6-
var c = RegExp(".", "imsuy");
6+
var c = new RegExp(".", "imsuy");
77
console.log(a.unicode);
88
console.log(b.dotAll);
99
console.log(c.sticky);

crates/swc_ecma_transformer/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ version = "0.1.0"
1313
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(swc_ast_unknown)'] }
1414

1515
[dependencies]
16-
tracing = { workspace = true }
16+
swc_common = { version = "17.0.1", path = "../swc_common" }
1717
swc_ecma_ast = { version = "18.0.0", path = "../swc_ecma_ast" }
1818
swc_ecma_hooks = { version = "0.2.0", path = "../swc_ecma_hooks" }
1919
swc_ecma_transforms_base = { version = "30.0.0", path = "../swc_ecma_transforms_base" }
2020
swc_ecma_utils = { version = "24.0.0", path = "../swc_ecma_utils" }
2121
swc_ecma_visit = { version = "18.0.1", path = "../swc_ecma_visit" }
22+
tracing = { workspace = true }

crates/swc_ecma_transformer/src/hook_utils.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use swc_ecma_ast::*;
12
use swc_ecma_hooks::{CompositeHook, VisitMutHook};
23

34
use crate::TraverseCtx;
@@ -6,11 +7,41 @@ pub(crate) struct OptionalHook<H>(pub Option<H>)
67
where
78
H: VisitMutHook<TraverseCtx>;
89

10+
macro_rules! optional_method {
11+
($enter_name:ident, $exit_name:ident, $T:ty) => {
12+
fn $enter_name(&mut self, node: &mut $T, ctx: &mut TraverseCtx) {
13+
if let Some(hook) = &mut self.0 {
14+
hook.$enter_name(node, ctx);
15+
}
16+
}
17+
18+
fn $exit_name(&mut self, node: &mut $T, ctx: &mut TraverseCtx) {
19+
if let Some(hook) = &mut self.0 {
20+
hook.$exit_name(node, ctx);
21+
}
22+
}
23+
};
24+
}
25+
926
impl<H> VisitMutHook<TraverseCtx> for OptionalHook<H>
1027
where
1128
H: VisitMutHook<TraverseCtx>,
1229
{
1330
// TODO: Implement lots of hooks, or move it to `swc_ecma_hooks`
31+
32+
optional_method!(enter_expr, exit_expr, Expr);
33+
34+
optional_method!(enter_pat, exit_pat, Pat);
35+
36+
optional_method!(enter_stmt, exit_stmt, Stmt);
37+
38+
optional_method!(enter_module_item, exit_module_item, ModuleItem);
39+
40+
optional_method!(enter_module, exit_module, Module);
41+
42+
optional_method!(enter_script, exit_script, Script);
43+
44+
optional_method!(enter_program, exit_program, Program);
1445
}
1546

1647
pub(crate) struct NoopHook;

crates/swc_ecma_transformer/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,11 @@ pub fn hook_pass<H: VisitMutHook<TraverseCtx>>(hook: H) -> impl Pass {
5353

5454
visit_mut_pass(VisitMutWithHook { hook, context: ctx })
5555
}
56+
57+
impl Options {
58+
pub fn into_pass(self) -> impl Pass {
59+
let hook = transform_hook(self);
60+
61+
hook_pass(hook)
62+
}
63+
}

crates/swc_ecma_transformer/src/regexp.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
use swc_common::util::take::Take;
2+
use swc_ecma_ast::*;
13
use swc_ecma_hooks::VisitMutHook;
4+
use swc_ecma_utils::{quote_ident, ExprFactory};
25

36
use crate::TraverseCtx;
47

@@ -44,4 +47,38 @@ struct RegexpPass {
4447
options: RegExpOptions,
4548
}
4649

47-
impl VisitMutHook<TraverseCtx> for RegexpPass {}
50+
impl VisitMutHook<TraverseCtx> for RegexpPass {
51+
fn exit_expr(&mut self, expr: &mut Expr, _: &mut TraverseCtx) {
52+
if let Expr::Lit(Lit::Regex(regex)) = expr {
53+
if (self.options.dot_all_regex && regex.flags.contains('s'))
54+
|| (self.options.sticky_regex && regex.flags.contains('y'))
55+
|| (self.options.unicode_regex && regex.flags.contains('u'))
56+
|| (self.options.unicode_sets_regex && regex.flags.contains('v'))
57+
|| (self.options.has_indices && regex.flags.contains('d'))
58+
|| (self.options.named_capturing_groups_regex && regex.exp.contains("(?<"))
59+
|| (self.options.lookbehind_assertion && regex.exp.contains("(?<=")
60+
|| regex.exp.contains("(?<!"))
61+
|| (self.options.unicode_property_regex
62+
&& (regex.exp.contains("\\p{") || regex.exp.contains("\\P{")))
63+
{
64+
let Regex { exp, flags, span } = regex.take();
65+
66+
let exp: Expr = exp.into();
67+
let mut args = vec![exp.into()];
68+
69+
if !flags.is_empty() {
70+
let flags: Expr = flags.into();
71+
args.push(flags.into());
72+
}
73+
74+
*expr = CallExpr {
75+
span,
76+
callee: quote_ident!("RegExp").as_callee(),
77+
args,
78+
..Default::default()
79+
}
80+
.into()
81+
}
82+
}
83+
}
84+
}

0 commit comments

Comments
 (0)