mirror of
https://github.com/swc-project/swc.git
synced 2024-09-11 08:45:34 +03:00
Performance (#82)
`Map<T>` adds a method named `map` which is actually `Box<T>` -> `Box<T>` without reallocation. swc_ecma_transforms: - chain_at!(Type, passes) This macro deeply joins path at 'Type' level.
This commit is contained in:
parent
ea910a4dfb
commit
222bdc191f
@ -26,10 +26,10 @@ features = [ "suggestions", "color" ]
|
||||
|
||||
|
||||
[profile.bench]
|
||||
lto = true
|
||||
# lto = true
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
# lto = true
|
||||
|
||||
[patch.crates-io]
|
||||
# This reduces compile time
|
||||
|
76
common/benches/and_then.rs
Normal file
76
common/benches/and_then.rs
Normal file
@ -0,0 +1,76 @@
|
||||
//! These benchmarks ensures that adding a Noop to chain! does not affect
|
||||
//! performance.
|
||||
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(specialization)]
|
||||
#![feature(test)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate swc_common;
|
||||
extern crate test;
|
||||
|
||||
use swc_common::FoldWith;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
fn mk_vec() -> Vec<Box<String>> {
|
||||
(0..1000).map(|s| box s.to_string()).collect()
|
||||
}
|
||||
|
||||
struct Noop;
|
||||
|
||||
#[bench]
|
||||
fn bench_vec_chain2(b: &mut Bencher) {
|
||||
let mut chain = chain!(Noop, Noop);
|
||||
b.iter(|| {
|
||||
let v = mk_vec();
|
||||
black_box(v.fold_with(&mut chain))
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_vec_chain3(b: &mut Bencher) {
|
||||
let mut chain = chain!(Noop, Noop, Noop);
|
||||
b.iter(|| {
|
||||
let v = mk_vec();
|
||||
black_box(v.fold_with(&mut chain))
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_vec_chain4(b: &mut Bencher) {
|
||||
let mut chain = chain!(Noop, Noop, Noop, Noop);
|
||||
b.iter(|| {
|
||||
let v = mk_vec();
|
||||
black_box(v.fold_with(&mut chain))
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_vec_chain5(b: &mut Bencher) {
|
||||
let mut chain = chain!(Noop, Noop, Noop, Noop, Noop);
|
||||
b.iter(|| {
|
||||
let v = mk_vec();
|
||||
black_box(v.fold_with(&mut chain))
|
||||
})
|
||||
}
|
||||
#[bench]
|
||||
fn bench_mk_vec(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
black_box(mk_vec());
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_vec_5(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let v = mk_vec();
|
||||
black_box(
|
||||
v.fold_with(&mut Noop)
|
||||
.fold_with(&mut Noop)
|
||||
.fold_with(&mut Noop)
|
||||
.fold_with(&mut Noop)
|
||||
.fold_with(&mut Noop),
|
||||
)
|
||||
});
|
||||
}
|
117
common/src/fold/and_then.rs
Normal file
117
common/src/fold/and_then.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use super::{Fold, FoldWith, Visit, VisitWith};
|
||||
use syntax::util::move_map::MoveMap;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! chain {
|
||||
($a:expr, $b:expr) => {{
|
||||
use $crate::fold::and_then::AndThen;
|
||||
|
||||
AndThen {
|
||||
first: $a,
|
||||
second: $b,
|
||||
}
|
||||
}};
|
||||
|
||||
($a:expr, $b:expr,) => {
|
||||
chain!($a, $b)
|
||||
};
|
||||
|
||||
($a:expr, $b:expr, $($rest:tt)+) => {{
|
||||
use $crate::fold::and_then::AndThen;
|
||||
|
||||
AndThen{
|
||||
first: $a,
|
||||
second: chain!($b, $($rest)*),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct AndThen<A, B> {
|
||||
pub first: A,
|
||||
pub second: B,
|
||||
}
|
||||
|
||||
// fn type_name<T>() -> String {
|
||||
// format!("{}", unsafe { std::intrinsics::type_name::<T>() })
|
||||
// }
|
||||
|
||||
impl<T, A, B> Fold<T> for AndThen<A, B>
|
||||
where
|
||||
T: FoldWith<Self>,
|
||||
{
|
||||
default fn fold(&mut self, node: T) -> T {
|
||||
// println!(
|
||||
// "Default<{}, {}>({})",
|
||||
// type_name::<A>(),
|
||||
// type_name::<B>(),
|
||||
// type_name::<T>()
|
||||
// );
|
||||
node.fold_children(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B> Fold<T> for AndThen<A, B>
|
||||
where
|
||||
T: FoldWith<Self>,
|
||||
A: Fold<T>,
|
||||
B: Fold<T>,
|
||||
{
|
||||
default fn fold(&mut self, node: T) -> T {
|
||||
// println!(
|
||||
// "Folding<{}, {}>({})",
|
||||
// type_name::<A>(),
|
||||
// type_name::<B>(),
|
||||
// type_name::<T>()
|
||||
// );
|
||||
self.second.fold(self.first.fold(node))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B> Fold<Box<T>> for AndThen<A, B>
|
||||
where
|
||||
Box<T>: FoldWith<Self>,
|
||||
Self: Fold<T>,
|
||||
A: Fold<T>,
|
||||
B: Fold<T>,
|
||||
{
|
||||
fn fold(&mut self, node: Box<T>) -> Box<T> {
|
||||
// println!(
|
||||
// "Box<{}, {}>({})",
|
||||
// type_name::<A>(),
|
||||
// type_name::<B>(),
|
||||
// type_name::<T>()
|
||||
// );
|
||||
box self.fold(*node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B> Fold<Vec<T>> for AndThen<A, B>
|
||||
where
|
||||
Vec<T>: FoldWith<Self>,
|
||||
Self: Fold<T>,
|
||||
A: Fold<T>,
|
||||
B: Fold<T>,
|
||||
{
|
||||
fn fold(&mut self, node: Vec<T>) -> Vec<T> {
|
||||
// println!(
|
||||
// "Vec<{}, {}>({})",
|
||||
// type_name::<A>(),
|
||||
// type_name::<B>(),
|
||||
// type_name::<T>()
|
||||
// );
|
||||
node.move_map(|node| self.fold(node))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A, B> Visit<T> for AndThen<A, B>
|
||||
where
|
||||
T: VisitWith<Self>,
|
||||
A: Visit<T>,
|
||||
B: Visit<T>,
|
||||
{
|
||||
fn visit(&mut self, node: &T) {
|
||||
self.first.visit(node);
|
||||
self.second.visit(node);
|
||||
}
|
||||
}
|
@ -1,5 +1,10 @@
|
||||
use self::and_then::AndThen;
|
||||
use crate::util::Map;
|
||||
use either::Either;
|
||||
use string_cache::{Atom, StaticAtomSet};
|
||||
use syntax::util::move_map::MoveMap;
|
||||
|
||||
pub mod and_then;
|
||||
|
||||
/// Folder based on a type system.
|
||||
///
|
||||
@ -10,7 +15,7 @@ pub trait Fold<T> {
|
||||
fn fold(&mut self, node: T) -> T;
|
||||
|
||||
/// Creates a folder which applies `folder` after `self`.
|
||||
#[inline(always)]
|
||||
|
||||
fn then<F>(self, folder: F) -> AndThen<Self, F>
|
||||
where
|
||||
Self: Sized,
|
||||
@ -30,7 +35,7 @@ pub trait Visit<T> {
|
||||
fn visit(&mut self, node: &T);
|
||||
|
||||
/// Creates a folder which applies `folder` after `self`.
|
||||
#[inline(always)]
|
||||
|
||||
fn then<F>(self, visitor: F) -> AndThen<Self, F>
|
||||
where
|
||||
Self: Sized,
|
||||
@ -48,7 +53,6 @@ where
|
||||
T: FoldWith<Self>,
|
||||
F: Fold<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn fold(&mut self, node: T) -> T {
|
||||
(**self).fold(node)
|
||||
}
|
||||
@ -59,7 +63,6 @@ where
|
||||
T: VisitWith<Self>,
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn visit(&mut self, node: &T) {
|
||||
(**self).visit(node)
|
||||
}
|
||||
@ -70,7 +73,6 @@ where
|
||||
T: FoldWith<Self>,
|
||||
F: Fold<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn fold(&mut self, node: T) -> T {
|
||||
(**self).fold(node)
|
||||
}
|
||||
@ -81,7 +83,6 @@ where
|
||||
T: VisitWith<Self>,
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn visit(&mut self, node: &T) {
|
||||
(**self).visit(node)
|
||||
}
|
||||
@ -91,7 +92,6 @@ impl<T, F> Fold<T> for F
|
||||
where
|
||||
T: FoldWith<F>,
|
||||
{
|
||||
#[inline(always)]
|
||||
default fn fold(&mut self, t: T) -> T {
|
||||
t.fold_children(self)
|
||||
}
|
||||
@ -101,44 +101,11 @@ impl<T, F> Visit<T> for F
|
||||
where
|
||||
T: VisitWith<F>,
|
||||
{
|
||||
#[inline(always)]
|
||||
default fn visit(&mut self, t: &T) {
|
||||
t.visit_children(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct AndThen<F1, F2> {
|
||||
first: F1,
|
||||
second: F2,
|
||||
}
|
||||
|
||||
impl<T, F1, F2> Fold<T> for AndThen<F1, F2>
|
||||
where
|
||||
T: FoldWith<Self>,
|
||||
F1: Fold<T>,
|
||||
F2: Fold<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn fold(&mut self, node: T) -> T {
|
||||
let node = self.first.fold(node);
|
||||
self.second.fold(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, F1, F2> Visit<T> for AndThen<F1, F2>
|
||||
where
|
||||
T: VisitWith<Self>,
|
||||
F1: Visit<T>,
|
||||
F2: Visit<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn visit(&mut self, node: &T) {
|
||||
self.first.visit(node);
|
||||
self.second.visit(node);
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait implemented for types which know how to fold itself.
|
||||
///
|
||||
///
|
||||
@ -157,8 +124,11 @@ pub trait FoldWith<F>: Sized {
|
||||
/// Call `f.fold(self)`.
|
||||
///
|
||||
/// This bypasses a type inference bug which is caused by specialization.
|
||||
#[inline(always)]
|
||||
fn fold_with(self, f: &mut F) -> Self {
|
||||
|
||||
fn fold_with(self, f: &mut F) -> Self
|
||||
where
|
||||
F: Fold<Self>,
|
||||
{
|
||||
f.fold(self)
|
||||
}
|
||||
}
|
||||
@ -181,7 +151,7 @@ pub trait VisitWith<F> {
|
||||
/// Call `f.visit(self)`.
|
||||
///
|
||||
/// This bypasses a type inference bug which is caused by specialization.
|
||||
#[inline(always)]
|
||||
|
||||
fn visit_with(&self, f: &mut F)
|
||||
where
|
||||
Self: Sized,
|
||||
@ -194,21 +164,18 @@ impl<'a, T, F> VisitWith<F> for &'a T
|
||||
where
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn visit_children(&self, f: &mut F) {
|
||||
f.visit(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> FoldWith<F> for ! {
|
||||
#[inline(always)]
|
||||
fn fold_children(self, _: &mut F) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> VisitWith<F> for ! {
|
||||
#[inline(always)]
|
||||
fn visit_children(&self, _: &mut F) {}
|
||||
}
|
||||
|
||||
@ -216,9 +183,8 @@ impl<T, F> FoldWith<F> for Box<T>
|
||||
where
|
||||
F: Fold<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn fold_children(self, f: &mut F) -> Self {
|
||||
box f.fold(*self)
|
||||
self.map(|node| f.fold(node))
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +192,6 @@ impl<T, F> VisitWith<F> for Box<T>
|
||||
where
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn visit_children(&self, f: &mut F) {
|
||||
f.visit(&**self)
|
||||
}
|
||||
@ -236,9 +201,9 @@ impl<T, F> FoldWith<F> for Vec<T>
|
||||
where
|
||||
F: Fold<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn fold_children(self, f: &mut F) -> Self {
|
||||
self.into_iter().map(|it| f.fold(it)).collect()
|
||||
self.move_map(|it| f.fold(it))
|
||||
// self.into_iter().map(|it| f.fold(it)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,7 +211,6 @@ impl<T, F> VisitWith<F> for Vec<T>
|
||||
where
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn visit_children(&self, f: &mut F) {
|
||||
self.iter().for_each(|node| f.visit(node))
|
||||
}
|
||||
@ -256,7 +220,6 @@ impl<T, F> VisitWith<F> for [T]
|
||||
where
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline]
|
||||
fn visit_children(&self, f: &mut F) {
|
||||
self.iter().for_each(|node| f.visit(node))
|
||||
}
|
||||
@ -266,7 +229,6 @@ impl<T, F> FoldWith<F> for Option<T>
|
||||
where
|
||||
F: Fold<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn fold_children(self, f: &mut F) -> Self {
|
||||
self.map(|t| f.fold(t))
|
||||
}
|
||||
@ -276,7 +238,6 @@ impl<T, F> VisitWith<F> for Option<T>
|
||||
where
|
||||
F: Visit<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn visit_children(&self, f: &mut F) {
|
||||
if let Some(ref node) = *self {
|
||||
f.visit(node)
|
||||
@ -286,7 +247,7 @@ where
|
||||
|
||||
impl<F> FoldWith<F> for String {
|
||||
/// No op.
|
||||
#[inline(always)]
|
||||
|
||||
fn fold_children(self, _: &mut F) -> Self {
|
||||
self
|
||||
}
|
||||
@ -294,13 +255,13 @@ impl<F> FoldWith<F> for String {
|
||||
|
||||
impl<F> VisitWith<F> for String {
|
||||
/// No op.
|
||||
#[inline(always)]
|
||||
|
||||
fn visit_children(&self, _: &mut F) {}
|
||||
}
|
||||
|
||||
impl<F, S: StaticAtomSet> FoldWith<F> for Atom<S> {
|
||||
/// No op.
|
||||
#[inline(always)]
|
||||
|
||||
fn fold_children(self, _: &mut F) -> Self {
|
||||
self
|
||||
}
|
||||
@ -308,7 +269,7 @@ impl<F, S: StaticAtomSet> FoldWith<F> for Atom<S> {
|
||||
|
||||
impl<F, S: StaticAtomSet> VisitWith<F> for Atom<S> {
|
||||
/// No op.
|
||||
#[inline(always)]
|
||||
|
||||
fn visit_children(&self, _: &mut F) {}
|
||||
}
|
||||
|
||||
@ -316,7 +277,6 @@ impl<A, B, F> FoldWith<F> for Either<A, B>
|
||||
where
|
||||
F: Fold<A> + Fold<B>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn fold_children(self, f: &mut F) -> Self {
|
||||
match self {
|
||||
Either::Left(a) => Either::Left(Fold::<A>::fold(f, a)),
|
||||
@ -329,7 +289,6 @@ impl<A, B, F> VisitWith<F> for Either<A, B>
|
||||
where
|
||||
F: Visit<A> + Visit<B>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn visit_children(&self, f: &mut F) {
|
||||
match *self {
|
||||
Either::Left(ref a) => f.visit(a),
|
@ -2,6 +2,7 @@
|
||||
#![feature(range_contains)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(never_type)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(specialization)]
|
||||
extern crate ast_node;
|
||||
extern crate either;
|
||||
@ -19,8 +20,9 @@ pub use self::{
|
||||
pub use ast_node::{ast_node, Fold, FromVariant, Spanned};
|
||||
pub use rustc_data_structures::sync;
|
||||
use std::fmt::Debug;
|
||||
pub use syntax::source_map::{
|
||||
FileLines, FileLoader, FileName, FilePathMapping, SourceMap, SpanSnippetError,
|
||||
pub use syntax::{
|
||||
source_map::{FileLines, FileLoader, FileName, FilePathMapping, SourceMap, SpanSnippetError},
|
||||
util::move_map::MoveMap,
|
||||
};
|
||||
|
||||
/// A marker trait for ast nodes.
|
||||
@ -29,6 +31,7 @@ pub trait AstNode: Debug + PartialEq + Clone + Spanned {}
|
||||
impl<N: Debug + PartialEq + Clone + Spanned> AstNode for N {}
|
||||
|
||||
pub mod errors;
|
||||
mod fold;
|
||||
pub mod fold;
|
||||
pub mod macros;
|
||||
mod pos;
|
||||
pub mod util;
|
||||
|
31
common/src/util.rs
Normal file
31
common/src/util.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use std::{mem, ptr};
|
||||
|
||||
/// Copied from `syntax::ptr::P`
|
||||
pub trait Map<T> {
|
||||
/// Transform the inner value, consuming `self` and producing a new `P<T>`.
|
||||
fn map<F>(self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(T) -> T;
|
||||
}
|
||||
|
||||
impl<T> Map<T> for Box<T> {
|
||||
fn map<F>(mut self, f: F) -> Self
|
||||
where
|
||||
F: FnOnce(T) -> T,
|
||||
{
|
||||
let p: *mut T = &mut *self;
|
||||
|
||||
// Leak self in case of panic.
|
||||
// FIXME(eddyb) Use some sort of "free guard" that
|
||||
// only deallocates, without dropping the pointee,
|
||||
// in case the call the `f` below ends in a panic.
|
||||
mem::forget(self);
|
||||
|
||||
unsafe {
|
||||
ptr::write(p, f(ptr::read(p)));
|
||||
|
||||
// Recreate self from the raw pointer.
|
||||
Box::from_raw(p)
|
||||
}
|
||||
}
|
||||
}
|
66
common/tests/fold_and_then.rs
Normal file
66
common/tests/fold_and_then.rs
Normal file
@ -0,0 +1,66 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(specialization)]
|
||||
#![feature(test)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate swc_common;
|
||||
extern crate test;
|
||||
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use swc_common::{Fold, FoldWith};
|
||||
|
||||
struct Named(&'static str, Rc<RefCell<Vec<(&'static str, String)>>>);
|
||||
impl Fold<String> for Named {
|
||||
fn fold(&mut self, v: String) -> String {
|
||||
let name = self.0;
|
||||
self.1.borrow_mut().push((name, v.clone()));
|
||||
|
||||
v
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Fold)]
|
||||
struct Nested<T>(#[fold(bound)] T);
|
||||
|
||||
#[test]
|
||||
fn vec_order() {
|
||||
let logger = Rc::new(RefCell::default());
|
||||
|
||||
vec![
|
||||
box String::from("foo"),
|
||||
box String::from("bar"),
|
||||
box String::from("baz"),
|
||||
]
|
||||
.into_iter()
|
||||
.map(Box::new)
|
||||
.map(Nested)
|
||||
.map(Box::new)
|
||||
.map(Nested)
|
||||
.map(Nested)
|
||||
.collect::<Vec<_>>()
|
||||
.fold_with(&mut chain!(
|
||||
Named("A", logger.clone()),
|
||||
Named("B", logger.clone()),
|
||||
Named("C", logger.clone())
|
||||
));
|
||||
|
||||
let result = Rc::try_unwrap(logger).unwrap();
|
||||
assert_eq!(
|
||||
vec![
|
||||
("A", "foo"),
|
||||
("B", "foo"),
|
||||
("C", "foo"),
|
||||
("A", "bar"),
|
||||
("B", "bar"),
|
||||
("C", "bar"),
|
||||
("A", "baz"),
|
||||
("B", "baz"),
|
||||
("C", "baz"),
|
||||
]
|
||||
.into_iter()
|
||||
.map(|(n, v)| (n, String::from(v)))
|
||||
.collect::<Vec<_>>(),
|
||||
result.into_inner()
|
||||
);
|
||||
}
|
@ -83,20 +83,23 @@ module.exports = {
|
||||
"#;
|
||||
|
||||
#[bench]
|
||||
fn bench_parse_module(b: &mut Bencher) {
|
||||
fn parse_module(b: &mut Bencher) {
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
|
||||
b.iter(|| test::black_box(parser.parse_module().unwrap()));
|
||||
b.iter(|| {
|
||||
test::black_box({
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let _ = parser.parse_module();
|
||||
})
|
||||
});
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ swc_common = { path ="../../common" }
|
||||
swc_ecma_ast = { path ="../ast" }
|
||||
swc_ecma_parser = { path ="../parser" }
|
||||
slog = "2"
|
||||
fnv = "1"
|
||||
|
||||
[dev-dependencies]
|
||||
testing = { path ="../../testing" }
|
||||
|
312
ecmascript/transforms/benches/base.rs
Normal file
312
ecmascript/transforms/benches/base.rs
Normal file
@ -0,0 +1,312 @@
|
||||
#![feature(test)]
|
||||
#![feature(specialization)]
|
||||
#![feature(box_syntax)]
|
||||
|
||||
extern crate swc_common;
|
||||
extern crate swc_ecma_ast;
|
||||
extern crate swc_ecma_parser;
|
||||
extern crate swc_ecma_transforms;
|
||||
extern crate test;
|
||||
extern crate testing;
|
||||
|
||||
use swc_common::{FileName, Fold, FoldWith, Visit, VisitWith, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_parser::{Parser, Session, SourceFileInput};
|
||||
use swc_ecma_transforms::util::ExprFactory;
|
||||
use test::Bencher;
|
||||
|
||||
static SOURCE: &'static str = r#"
|
||||
'use strict';
|
||||
/**
|
||||
* Extract red color out of a color integer:
|
||||
*
|
||||
* 0x00DEAD -> 0x00
|
||||
*
|
||||
* @param {Number} color
|
||||
* @return {Number}
|
||||
*/
|
||||
function red( color )
|
||||
{
|
||||
let foo = 3.14;
|
||||
return color >> 16;
|
||||
}
|
||||
/**
|
||||
* Extract green out of a color integer:
|
||||
*
|
||||
* 0x00DEAD -> 0xDE
|
||||
*
|
||||
* @param {Number} color
|
||||
* @return {Number}
|
||||
*/
|
||||
function green( color )
|
||||
{
|
||||
return ( color >> 8 ) & 0xFF;
|
||||
}
|
||||
/**
|
||||
* Extract blue color out of a color integer:
|
||||
*
|
||||
* 0x00DEAD -> 0xAD
|
||||
*
|
||||
* @param {Number} color
|
||||
* @return {Number}
|
||||
*/
|
||||
function blue( color )
|
||||
{
|
||||
return color & 0xFF;
|
||||
}
|
||||
/**
|
||||
* Converts an integer containing a color such as 0x00DEAD to a hex
|
||||
* string, such as '#00DEAD';
|
||||
*
|
||||
* @param {Number} int
|
||||
* @return {String}
|
||||
*/
|
||||
function intToHex( int )
|
||||
{
|
||||
const mask = '#000000';
|
||||
const hex = int.toString( 16 );
|
||||
return mask.substring( 0, 7 - hex.length ) + hex;
|
||||
}
|
||||
/**
|
||||
* Converts a hex string containing a color such as '#00DEAD' to
|
||||
* an integer, such as 0x00DEAD;
|
||||
*
|
||||
* @param {Number} num
|
||||
* @return {String}
|
||||
*/
|
||||
function hexToInt( hex )
|
||||
{
|
||||
return parseInt( hex.substring( 1 ), 16 );
|
||||
}
|
||||
module.exports = {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
intToHex,
|
||||
hexToInt,
|
||||
};"#;
|
||||
|
||||
#[bench]
|
||||
fn module_clone(b: &mut Bencher) {
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
|
||||
b.iter(|| test::black_box(module.clone()));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn fold_empty(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
let mut folder = Noop;
|
||||
|
||||
b.iter(|| test::black_box(module.clone().fold_with(&mut folder)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
/// Optimized out
|
||||
#[bench]
|
||||
fn fold_noop_impl_all(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
impl<T> Fold<T> for Noop
|
||||
where
|
||||
T: FoldWith<Self>,
|
||||
{
|
||||
fn fold(&mut self, node: T) -> T {
|
||||
node
|
||||
}
|
||||
}
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
let mut folder = Noop;
|
||||
|
||||
b.iter(|| test::black_box(module.clone().fold_with(&mut folder)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
/// Optimized out
|
||||
#[bench]
|
||||
fn fold_noop_impl_vec(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
impl<T> Fold<Vec<T>> for Noop
|
||||
where
|
||||
Vec<T>: FoldWith<Self>,
|
||||
{
|
||||
fn fold(&mut self, node: Vec<T>) -> Vec<T> {
|
||||
node
|
||||
}
|
||||
}
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
let mut folder = Noop;
|
||||
|
||||
b.iter(|| test::black_box(module.clone().fold_with(&mut folder)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
fn mk_expr() -> Expr {
|
||||
Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: Ident::new("foo".into(), DUMMY_SP).as_callee(),
|
||||
args: vec![],
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn boxing_boxed_clone(b: &mut Bencher) {
|
||||
let _ = ::testing::run_test(|_, _, _| {
|
||||
let expr = box mk_expr();
|
||||
|
||||
b.iter(|| test::black_box(expr.clone()));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn boxing_unboxed_clone(b: &mut Bencher) {
|
||||
let _ = ::testing::run_test(|_, _, _| {
|
||||
let expr = mk_expr();
|
||||
|
||||
b.iter(|| test::black_box(expr.clone()));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn boxing_boxed(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
|
||||
let _ = ::testing::run_test(|_, _, _| {
|
||||
let mut folder = Noop;
|
||||
let expr = box mk_expr();
|
||||
|
||||
b.iter(|| test::black_box(expr.clone().fold_with(&mut folder)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn boxing_unboxed(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
|
||||
let _ = ::testing::run_test(|_, _, _| {
|
||||
let mut folder = Noop;
|
||||
let expr = mk_expr();
|
||||
|
||||
b.iter(|| test::black_box(expr.clone().fold_with(&mut folder)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn visit_empty(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
let mut v = Noop;
|
||||
|
||||
b.iter(|| test::black_box(module.visit_with(&mut v)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn visit_contains_this(b: &mut Bencher) {
|
||||
fn contains_this_expr(body: &Module) -> bool {
|
||||
struct Visitor {
|
||||
found: bool,
|
||||
}
|
||||
|
||||
impl Visit<ThisExpr> for Visitor {
|
||||
fn visit(&mut self, _: &ThisExpr) {
|
||||
self.found = true;
|
||||
}
|
||||
}
|
||||
|
||||
impl Visit<FnExpr> for Visitor {
|
||||
/// Don't recurse into fn
|
||||
fn visit(&mut self, _: &FnExpr) {}
|
||||
}
|
||||
|
||||
impl Visit<FnDecl> for Visitor {
|
||||
/// Don't recurse into fn
|
||||
fn visit(&mut self, _: &FnDecl) {}
|
||||
}
|
||||
|
||||
let mut visitor = Visitor { found: false };
|
||||
body.visit_with(&mut visitor);
|
||||
visitor.found
|
||||
}
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
|
||||
b.iter(|| test::black_box(contains_this_expr(&module)));
|
||||
Ok(())
|
||||
});
|
||||
}
|
192
ecmascript/transforms/benches/bench.rs
Normal file
192
ecmascript/transforms/benches/bench.rs
Normal file
@ -0,0 +1,192 @@
|
||||
#![feature(test)]
|
||||
#![feature(specialization)]
|
||||
use std::alloc::System;
|
||||
|
||||
#[global_allocator]
|
||||
static GLOBAL: System = System;
|
||||
|
||||
extern crate swc_common;
|
||||
extern crate swc_ecma_ast;
|
||||
extern crate swc_ecma_parser;
|
||||
extern crate swc_ecma_transforms;
|
||||
extern crate test;
|
||||
extern crate testing;
|
||||
|
||||
use std::sync::Arc;
|
||||
use swc_common::{FileName, FoldWith};
|
||||
use swc_ecma_parser::{Parser, Session, SourceFileInput};
|
||||
use swc_ecma_transforms::compat;
|
||||
use test::Bencher;
|
||||
|
||||
static SOURCE: &'static str = r#"
|
||||
'use strict';
|
||||
/**
|
||||
* Extract red color out of a color integer:
|
||||
*
|
||||
* 0x00DEAD -> 0x00
|
||||
*
|
||||
* @param {Number} color
|
||||
* @return {Number}
|
||||
*/
|
||||
function red( color )
|
||||
{
|
||||
let foo = 3.14;
|
||||
return color >> 16;
|
||||
}
|
||||
/**
|
||||
* Extract green out of a color integer:
|
||||
*
|
||||
* 0x00DEAD -> 0xDE
|
||||
*
|
||||
* @param {Number} color
|
||||
* @return {Number}
|
||||
*/
|
||||
function green( color )
|
||||
{
|
||||
return ( color >> 8 ) & 0xFF;
|
||||
}
|
||||
/**
|
||||
* Extract blue color out of a color integer:
|
||||
*
|
||||
* 0x00DEAD -> 0xAD
|
||||
*
|
||||
* @param {Number} color
|
||||
* @return {Number}
|
||||
*/
|
||||
function blue( color )
|
||||
{
|
||||
return color & 0xFF;
|
||||
}
|
||||
/**
|
||||
* Converts an integer containing a color such as 0x00DEAD to a hex
|
||||
* string, such as '#00DEAD';
|
||||
*
|
||||
* @param {Number} int
|
||||
* @return {String}
|
||||
*/
|
||||
function intToHex( int )
|
||||
{
|
||||
const mask = '#000000';
|
||||
const hex = int.toString( 16 );
|
||||
return mask.substring( 0, 7 - hex.length ) + hex;
|
||||
}
|
||||
/**
|
||||
* Converts a hex string containing a color such as '#00DEAD' to
|
||||
* an integer, such as 0x00DEAD;
|
||||
*
|
||||
* @param {Number} num
|
||||
* @return {String}
|
||||
*/
|
||||
function hexToInt( hex )
|
||||
{
|
||||
return parseInt( hex.substring( 1 ), 16 );
|
||||
}
|
||||
module.exports = {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
intToHex,
|
||||
hexToInt,
|
||||
};"#;
|
||||
|
||||
/// Benchmark a folder
|
||||
macro_rules! tr {
|
||||
($b:expr, $tr:expr) => {
|
||||
let _ = ::testing::run_test(|logger, cm, handler| {
|
||||
let fm = cm.new_source_file(FileName::Anon, SOURCE.into());
|
||||
|
||||
let mut parser = Parser::new(
|
||||
Session {
|
||||
logger: &logger,
|
||||
handler: &handler,
|
||||
cfg: Default::default(),
|
||||
},
|
||||
SourceFileInput::from(&*fm),
|
||||
);
|
||||
let module = parser.parse_module().unwrap();
|
||||
let helpers = Arc::new(compat::helpers::Helpers::default());
|
||||
let mut tr = $tr(helpers);
|
||||
|
||||
$b.iter(|| {
|
||||
let module = module.clone();
|
||||
test::black_box(module.fold_with(&mut tr))
|
||||
});
|
||||
Ok(())
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015(b: &mut Bencher) {
|
||||
tr!(b, |helpers| compat::es2015(&helpers));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_arrow(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::arrow());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_classes(b: &mut Bencher) {
|
||||
tr!(b, |helpers| compat::es2015::Classes { helpers });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_computed_props(b: &mut Bencher) {
|
||||
tr!(b, compat::es2015::computed_properties);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_destructuring(b: &mut Bencher) {
|
||||
tr!(b, compat::es2015::destructuring);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_duplicate_keys(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::duplicate_keys());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_parameters(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::parameters());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_block_scoped_fn(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::BlockScopedFns);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_block_scoping(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::block_scoping());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_fn_name(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::function_name());
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_instanceof(b: &mut Bencher) {
|
||||
tr!(b, |helpers| compat::es2015::InstanceOf { helpers });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_shorthand_property(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::Shorthand);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_spread(b: &mut Bencher) {
|
||||
tr!(b, |helpers| compat::es2015::Spread { helpers });
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_sticky_regex(b: &mut Bencher) {
|
||||
tr!(b, |_| compat::es2015::StickyRegex);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn es2015_typeof_symbol(b: &mut Bencher) {
|
||||
tr!(b, |helpers| compat::es2015::TypeOfSymbol { helpers });
|
||||
}
|
82
ecmascript/transforms/benches/rust_vec.rs
Normal file
82
ecmascript/transforms/benches/rust_vec.rs
Normal file
@ -0,0 +1,82 @@
|
||||
#![feature(test)]
|
||||
#![feature(specialization)]
|
||||
|
||||
extern crate swc_common;
|
||||
extern crate swc_ecma_ast;
|
||||
extern crate swc_ecma_parser;
|
||||
extern crate swc_ecma_transforms;
|
||||
extern crate test;
|
||||
extern crate testing;
|
||||
|
||||
use swc_common::FoldWith;
|
||||
use test::{black_box, Bencher};
|
||||
|
||||
fn mk_vec() -> Vec<String> {
|
||||
vec![String::from("1"), String::from("2"), String::from("3")]
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_move_map(b: &mut Bencher) {
|
||||
struct Noop;
|
||||
b.iter(|| {
|
||||
let vec = mk_vec();
|
||||
|
||||
black_box(vec.fold_with(&mut Noop))
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_map_id_closure(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let vec = mk_vec();
|
||||
|
||||
black_box(vec.into_iter().map(|e| id(e)).collect::<Vec<_>>())
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_map_id(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let vec = mk_vec();
|
||||
|
||||
black_box(vec.into_iter().map(id).collect::<Vec<_>>())
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_map_id_inline_closure(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let vec = mk_vec();
|
||||
|
||||
black_box(vec.into_iter().map(|e| id_inline(e)).collect::<Vec<_>>())
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_map_id_inline(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let vec = mk_vec();
|
||||
|
||||
black_box(vec.into_iter().map(id_inline).collect::<Vec<_>>())
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_clone(b: &mut Bencher) {
|
||||
let v = mk_vec();
|
||||
b.iter(|| black_box(v.clone()))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_alloc(b: &mut Bencher) {
|
||||
b.iter(|| black_box(mk_vec()))
|
||||
}
|
||||
|
||||
fn id<T>(t: T) -> T {
|
||||
t
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn id_inline<T>(t: T) -> T {
|
||||
t
|
||||
}
|
@ -53,8 +53,12 @@ mod tests;
|
||||
/// };
|
||||
/// console.log(bob.printFriends());
|
||||
/// ```
|
||||
pub fn arrow() -> impl Fold<Expr> {
|
||||
Arrow
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Arrow;
|
||||
struct Arrow;
|
||||
|
||||
impl Fold<Expr> for Arrow {
|
||||
fn fold(&mut self, e: Expr) -> Expr {
|
||||
|
@ -1,16 +1,10 @@
|
||||
use ast::*;
|
||||
use swc_common::{Fold, FoldWith, DUMMY_SP};
|
||||
|
||||
pub fn block_scoped_functions() -> impl Fold<Module> {
|
||||
BlockScopedFns
|
||||
}
|
||||
|
||||
struct BlockScopedFns;
|
||||
pub struct BlockScopedFns;
|
||||
|
||||
impl Fold<Stmt> for BlockScopedFns {
|
||||
fn fold(&mut self, stmt: Stmt) -> Stmt {
|
||||
let stmt = stmt.fold_children(self);
|
||||
|
||||
match stmt {
|
||||
Stmt::Decl(Decl::Fn(decl)) => {
|
||||
return Stmt::Decl(Decl::Var(VarDecl {
|
||||
@ -26,7 +20,7 @@ impl Fold<Stmt> for BlockScopedFns {
|
||||
}],
|
||||
}))
|
||||
}
|
||||
_ => stmt,
|
||||
_ => stmt.fold_children(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -36,7 +30,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
test!(
|
||||
block_scoped_functions(),
|
||||
BlockScopedFns,
|
||||
basic,
|
||||
r#"{
|
||||
function name (n) {
|
||||
|
@ -3,11 +3,11 @@ use crate::scope::{Scope, ScopeKind};
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{Fold, FoldWith, Mark};
|
||||
|
||||
pub fn block_scoping() -> impl Fold<Module> {
|
||||
pub fn block_scoping() -> BlockFolder<'static> {
|
||||
BlockFolder::new(Mark::fresh(Mark::root()), Scope::new(ScopeKind::Fn, None))
|
||||
}
|
||||
|
||||
struct BlockFolder<'a> {
|
||||
pub struct BlockFolder<'a> {
|
||||
mark: Mark,
|
||||
current: Scope<'a>,
|
||||
}
|
||||
|
@ -166,10 +166,10 @@ impl Classes {
|
||||
|
||||
if let Some(ref super_class_ident) = super_class_ident {
|
||||
// inject helper methods
|
||||
self.helpers.inherits.store(true, Ordering::SeqCst);
|
||||
self.helpers.inherits.store(true, Ordering::Relaxed);
|
||||
self.helpers
|
||||
.possible_constructor_return
|
||||
.store(true, Ordering::SeqCst);
|
||||
.store(true, Ordering::Relaxed);
|
||||
|
||||
stmts.push(Stmt::Expr(box Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
@ -560,7 +560,7 @@ impl<'a> Fold<Expr> for SuperCallFolder<'a> {
|
||||
|
||||
let n = n.fold_with(&mut callee_folder);
|
||||
if callee_folder.did_work {
|
||||
self.helpers.get.store(true, Ordering::SeqCst);
|
||||
self.helpers.get.store(true, Ordering::Relaxed);
|
||||
|
||||
if was_call {
|
||||
match n {
|
||||
|
@ -40,12 +40,12 @@ mod tests;
|
||||
///
|
||||
/// TODO(kdy1): cache reference like (_f = f, mutatorMap[_f].get = function(){})
|
||||
/// instead of (mutatorMap[f].get = function(){}
|
||||
pub fn computed_properties(helpers: Arc<Helpers>) -> impl Fold<Module> {
|
||||
pub fn computed_properties(helpers: Arc<Helpers>) -> ComputedProps {
|
||||
ComputedProps { helpers }
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ComputedProps {
|
||||
pub struct ComputedProps {
|
||||
helpers: Arc<Helpers>,
|
||||
}
|
||||
|
||||
@ -277,7 +277,7 @@ where
|
||||
fn fold(&mut self, stmts: Vec<T>) -> Vec<T> {
|
||||
let stmts = stmts.fold_children(self);
|
||||
|
||||
let mut buf = vec![];
|
||||
let mut buf = Vec::with_capacity(stmts.len());
|
||||
|
||||
for stmt in stmts {
|
||||
match stmt.try_into_stmt() {
|
||||
@ -289,7 +289,7 @@ where
|
||||
// Add variable declaration
|
||||
// e.g. var ref
|
||||
if !folder.vars.is_empty() {
|
||||
self.helpers.define_property.store(true, Ordering::SeqCst);
|
||||
self.helpers.define_property.store(true, Ordering::Relaxed);
|
||||
buf.push(T::from_stmt(Stmt::Decl(Decl::Var(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Var,
|
||||
@ -299,7 +299,7 @@ where
|
||||
if folder.used_define_enum_props {
|
||||
self.helpers
|
||||
.define_enumerable_property
|
||||
.store(true, Ordering::SeqCst);
|
||||
.store(true, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
buf.push(T::from_stmt(stmt));
|
||||
|
@ -195,7 +195,7 @@ impl Fold<Vec<VarDeclarator>> for Destructuring {
|
||||
let ref_ident = make_ref_ident(&mut decls, decl.init);
|
||||
|
||||
let ref_ident = if can_be_null {
|
||||
self.helpers.throw.store(true, Ordering::SeqCst);
|
||||
self.helpers.throw.store(true, Ordering::Relaxed);
|
||||
make_ref_ident(
|
||||
&mut decls,
|
||||
Some(box Expr::Cond(CondExpr {
|
||||
@ -539,7 +539,7 @@ where
|
||||
fn fold(&mut self, stmts: Vec<T>) -> Vec<T> {
|
||||
let stmts = stmts.fold_children(self);
|
||||
|
||||
let mut buf = vec![];
|
||||
let mut buf = Vec::with_capacity(stmts.len());
|
||||
|
||||
for stmt in stmts {
|
||||
match stmt.try_into_stmt() {
|
||||
|
@ -1,19 +1,19 @@
|
||||
use ast::*;
|
||||
use std::collections::HashSet;
|
||||
use fnv::FnvHashSet;
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{Fold, FoldWith, Spanned};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn duplicate_keys() -> impl Fold<Module> {
|
||||
DupKeys
|
||||
pub fn duplicate_keys() -> impl Fold<Expr> {
|
||||
DuplicateKeys
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct DupKeys;
|
||||
struct DuplicateKeys;
|
||||
|
||||
impl Fold<Expr> for DupKeys {
|
||||
impl Fold<Expr> for DuplicateKeys {
|
||||
fn fold(&mut self, expr: Expr) -> Expr {
|
||||
let expr = expr.fold_children(self);
|
||||
|
||||
@ -34,8 +34,8 @@ impl Fold<Expr> for DupKeys {
|
||||
|
||||
#[derive(Default)]
|
||||
struct PropFolder {
|
||||
getter_props: HashSet<JsWord>,
|
||||
setter_props: HashSet<JsWord>,
|
||||
getter_props: FnvHashSet<JsWord>,
|
||||
setter_props: FnvHashSet<JsWord>,
|
||||
}
|
||||
|
||||
impl Fold<Prop> for PropFolder {
|
||||
@ -78,7 +78,7 @@ impl Fold<Prop> for PropFolder {
|
||||
}
|
||||
|
||||
struct PropNameFolder<'a> {
|
||||
props: &'a mut HashSet<JsWord>,
|
||||
props: &'a mut FnvHashSet<JsWord>,
|
||||
}
|
||||
|
||||
impl<'a> Fold<PropName> for PropNameFolder<'a> {
|
||||
|
@ -2,7 +2,7 @@ use super::*;
|
||||
|
||||
test!(
|
||||
ignore,
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
combination_dupes,
|
||||
r#"var x = { a: 5, a: 6 };"#,
|
||||
r#"var x = _defineProperty({
|
||||
@ -11,14 +11,14 @@ test!(
|
||||
);
|
||||
|
||||
test!(
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
combination_no_dupes,
|
||||
r#"var x = { a: 5, b: 6 };"#,
|
||||
r#"var x = { a: 5, b: 6 };"#
|
||||
);
|
||||
|
||||
test!(
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
dup_keys_both_quoted,
|
||||
r#"var x = { "a\n b": 5, "a\n b": 6 };"#,
|
||||
r#"var x = {
|
||||
@ -28,7 +28,7 @@ test!(
|
||||
);
|
||||
|
||||
test!(
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
dup_keys_dupes,
|
||||
r#"var x = { a: 5, a: 6 };"#,
|
||||
r#"var x = {
|
||||
@ -38,7 +38,7 @@ test!(
|
||||
);
|
||||
|
||||
test!(
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
dup_keys_getter,
|
||||
r#"var x = { a: 5, get a() {return 6;} };"#,
|
||||
r#"var x = {
|
||||
@ -52,7 +52,7 @@ test!(
|
||||
);
|
||||
|
||||
test!(
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
dup_keys_getter_and_setter,
|
||||
r#"var x = {
|
||||
get a() {},
|
||||
@ -102,7 +102,7 @@ test!(
|
||||
);
|
||||
|
||||
test!(
|
||||
DupKeys::default(),
|
||||
DuplicateKeys,
|
||||
dup_keys_one_quoted,
|
||||
r#"var x = { a: 5, "a": 6 };"#,
|
||||
r#"var x = {
|
||||
|
@ -16,11 +16,11 @@ use swc_common::{Fold, FoldWith};
|
||||
/// return x;
|
||||
/// }
|
||||
/// ```
|
||||
pub fn function_name() -> impl Fold<Module> {
|
||||
pub fn function_name() -> FnName {
|
||||
FnName
|
||||
}
|
||||
|
||||
struct FnName;
|
||||
pub struct FnName;
|
||||
|
||||
struct Renamer {
|
||||
name: Option<Ident>,
|
||||
|
@ -43,7 +43,7 @@ impl Fold<Expr> for InstanceOf {
|
||||
op: op!("instanceof"),
|
||||
right,
|
||||
}) => {
|
||||
self.helpers.instance_of.store(true, Ordering::SeqCst);
|
||||
self.helpers.instance_of.store(true, Ordering::Relaxed);
|
||||
|
||||
Expr::Call(CallExpr {
|
||||
span,
|
||||
|
@ -1,13 +1,12 @@
|
||||
pub use self::{
|
||||
arrow::Arrow, block_scoped_fn::block_scoped_functions, block_scoping::block_scoping,
|
||||
classes::Classes, computed_props::computed_properties, destructuring::destructuring,
|
||||
arrow::arrow, block_scoped_fn::BlockScopedFns, block_scoping::block_scoping, classes::Classes,
|
||||
computed_props::computed_properties, destructuring::destructuring,
|
||||
duplicate_keys::duplicate_keys, function_name::function_name, instanceof::InstanceOf,
|
||||
parameters::parameters, shorthand_property::Shorthand, spread::Spread,
|
||||
sticky_regex::StickyRegex, template_literal::TemplateLiteral, typeof_symbol::TypeOfSymbol,
|
||||
};
|
||||
|
||||
use super::helpers::Helpers;
|
||||
use ast::Module;
|
||||
use ast::{Expr, Module, Stmt};
|
||||
use std::sync::Arc;
|
||||
use swc_common::Fold;
|
||||
|
||||
@ -29,29 +28,46 @@ mod typeof_symbol;
|
||||
|
||||
/// Compiles es2015 to es5.
|
||||
pub fn es2015(helpers: &Arc<Helpers>) -> impl Fold<Module> {
|
||||
duplicate_keys()
|
||||
.then(Classes {
|
||||
helpers: helpers.clone(),
|
||||
})
|
||||
.then(Arrow)
|
||||
.then(block_scoped_functions())
|
||||
.then(parameters())
|
||||
.then(function_name())
|
||||
.then(Spread {
|
||||
helpers: helpers.clone(),
|
||||
})
|
||||
.then(StickyRegex)
|
||||
.then(Shorthand)
|
||||
.then(InstanceOf {
|
||||
helpers: helpers.clone(),
|
||||
})
|
||||
.then(TypeOfSymbol {
|
||||
helpers: helpers.clone(),
|
||||
})
|
||||
.then(TemplateLiteral {
|
||||
helpers: helpers.clone(),
|
||||
})
|
||||
.then(computed_properties(helpers.clone()))
|
||||
.then(destructuring(helpers.clone()))
|
||||
.then(block_scoping())
|
||||
fn exprs(helpers: &Arc<Helpers>) -> impl Fold<Expr> {
|
||||
chain_at!(
|
||||
Expr,
|
||||
arrow(),
|
||||
duplicate_keys(),
|
||||
Spread {
|
||||
helpers: helpers.clone(),
|
||||
},
|
||||
StickyRegex,
|
||||
InstanceOf {
|
||||
helpers: helpers.clone(),
|
||||
},
|
||||
TypeOfSymbol {
|
||||
helpers: helpers.clone(),
|
||||
},
|
||||
TemplateLiteral {
|
||||
helpers: helpers.clone(),
|
||||
},
|
||||
Shorthand,
|
||||
)
|
||||
}
|
||||
|
||||
fn stmts(helpers: &Arc<Helpers>) -> impl Fold<Stmt> {
|
||||
chain_at!(
|
||||
Stmt,
|
||||
exprs(helpers),
|
||||
Classes {
|
||||
helpers: helpers.clone(),
|
||||
},
|
||||
BlockScopedFns,
|
||||
function_name(),
|
||||
parameters(),
|
||||
)
|
||||
}
|
||||
|
||||
chain_at!(
|
||||
Module,
|
||||
stmts(helpers),
|
||||
computed_properties(helpers.clone()),
|
||||
destructuring(helpers.clone()),
|
||||
block_scoping(),
|
||||
)
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ use swc_common::{Fold, FoldWith, Mark, Spanned, DUMMY_SP};
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub fn parameters() -> impl Fold<Module> {
|
||||
pub fn parameters() -> Params {
|
||||
Params
|
||||
}
|
||||
|
||||
struct Params;
|
||||
pub struct Params;
|
||||
// prevent_recurse!(Params, Pat);
|
||||
|
||||
impl Params {
|
||||
fn fold_fn_like(&mut self, ps: Vec<Pat>, body: BlockStmt) -> (Vec<Pat>, BlockStmt) {
|
||||
|
@ -3,9 +3,12 @@ use crate::compat::{es2015::Classes, helpers::Helpers};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn tr(helpers: Arc<Helpers>) -> impl Fold<Module> {
|
||||
Params
|
||||
.then(crate::compat::es2015::destructuring(helpers.clone()))
|
||||
.then(crate::compat::es2015::block_scoping())
|
||||
chain_at!(
|
||||
Module,
|
||||
Params,
|
||||
crate::compat::es2015::destructuring(helpers.clone()),
|
||||
crate::compat::es2015::block_scoping()
|
||||
)
|
||||
}
|
||||
|
||||
test!(
|
||||
@ -105,7 +108,7 @@ foo(1, 2, 3);"#
|
||||
);
|
||||
|
||||
test!(
|
||||
Classes::default().then(tr(Default::default())),
|
||||
chain_at!(Module, Classes::default(), tr(Default::default())),
|
||||
default_iife_4253,
|
||||
r#"class Ref {
|
||||
constructor(id = ++Ref.nextID) {
|
||||
@ -141,7 +144,7 @@ expect(new Ref().id).toBe(2);"#
|
||||
);
|
||||
|
||||
test!(
|
||||
Classes::default().then(tr(Default::default())),
|
||||
chain_at!(Module, Classes::default(), tr(Default::default())),
|
||||
default_iife_self,
|
||||
r#"class Ref {
|
||||
constructor(ref = Ref) {
|
||||
@ -354,7 +357,8 @@ function t(x = "default", { a, b }, ...args) {
|
||||
function t(param, param1) {
|
||||
var tmp = param, x = tmp === void 0 ? 'default' : tmp, ref = param1 ? param1 :
|
||||
_throw(new TypeError("Cannot destructure 'undefined' or 'null'")), a = ref.a, b = ref.b;
|
||||
for(var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
|
||||
for(var _len = arguments.length, args = new Array(
|
||||
_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++){
|
||||
args[_key - 2] = arguments[_key];
|
||||
}
|
||||
console.log(x, a, b, args);
|
||||
@ -630,7 +634,11 @@ function () {
|
||||
);
|
||||
|
||||
test!(
|
||||
crate::compat::es2015::Arrow.then(tr(Default::default())),
|
||||
chain_at!(
|
||||
Module,
|
||||
crate::compat::es2015::arrow(),
|
||||
tr(Default::default())
|
||||
),
|
||||
rest_binding_deoptimisation,
|
||||
r#"const deepAssign = (...args) => args = [];
|
||||
"#,
|
||||
@ -1111,7 +1119,7 @@ function d(thing) {
|
||||
);
|
||||
|
||||
test!(
|
||||
Classes::default().then(tr(Default::default())).then(crate::compat::es2015::Spread::default()),
|
||||
chain_at!(Module, Classes::default(), tr(Default::default()), crate::compat::es2015::Spread::default()),
|
||||
rest_nested_iife,
|
||||
r#"function broken(x, ...foo) {
|
||||
if (true) {
|
||||
|
@ -129,7 +129,7 @@ fn concat_args(helpers: &Helpers, span: Span, args: Vec<ExprOrSpread>) -> Expr {
|
||||
//
|
||||
make_arr!();
|
||||
|
||||
helpers.to_consumable_array.store(true, Ordering::SeqCst);
|
||||
helpers.to_consumable_array.store(true, Ordering::Relaxed);
|
||||
|
||||
buf.push(
|
||||
Expr::Call(CallExpr {
|
||||
|
@ -27,7 +27,7 @@ impl Fold<Expr> for TemplateLiteral {
|
||||
Some(tag) => {
|
||||
self.helpers
|
||||
.tagged_template_literal
|
||||
.store(true, Ordering::SeqCst);
|
||||
.store(true, Ordering::Relaxed);
|
||||
|
||||
let mark = Mark::fresh(Mark::root());
|
||||
let fn_ident = quote_ident!(DUMMY_SP.apply_mark(mark), "_templateObject");
|
||||
|
@ -34,7 +34,7 @@ impl Fold<Expr> for TypeOfSymbol {
|
||||
op: op!("typeof"),
|
||||
arg,
|
||||
}) => {
|
||||
self.helpers.type_of.store(true, Ordering::SeqCst);
|
||||
self.helpers.type_of.store(true, Ordering::Relaxed);
|
||||
return Expr::Call(CallExpr {
|
||||
span,
|
||||
callee: quote_ident!(span, "_typeof").as_callee(),
|
||||
|
@ -1,15 +1,14 @@
|
||||
use ast::Module;
|
||||
use swc_common::Fold;
|
||||
|
||||
pub use self::{
|
||||
member_expr_lits::MemberExprLit, prop_lits::PropertyLiteral, reserved_word::ReservedWord,
|
||||
};
|
||||
use ast::Expr;
|
||||
use swc_common::Fold;
|
||||
|
||||
mod member_expr_lits;
|
||||
mod prop_lits;
|
||||
mod reserved_word;
|
||||
|
||||
/// Make output es3-compatible.
|
||||
pub fn es3() -> impl Fold<Module> {
|
||||
PropertyLiteral.then(MemberExprLit)
|
||||
pub fn es3() -> impl Fold<Expr> {
|
||||
chain_at!(Expr, PropertyLiteral, MemberExprLit)
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ impl InjectHelpers {
|
||||
};
|
||||
|
||||
let mut add = |name: &str, flag: &AtomicBool, code: &'static str| {
|
||||
let enable = flag.load(Ordering::SeqCst);
|
||||
let enable = flag.load(Ordering::Relaxed);
|
||||
if !enable {
|
||||
return;
|
||||
}
|
||||
|
@ -2,13 +2,16 @@
|
||||
#![feature(box_syntax)]
|
||||
#![feature(try_trait)]
|
||||
#![feature(specialization)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(nll)]
|
||||
#![feature(trace_macros)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
#[macro_use(js_word)]
|
||||
extern crate swc_atoms;
|
||||
extern crate fnv;
|
||||
extern crate swc_common;
|
||||
extern crate swc_ecma_ast as ast;
|
||||
#[cfg(test)]
|
||||
@ -22,6 +25,8 @@ extern crate sourcemap;
|
||||
#[cfg(test)]
|
||||
extern crate tempfile;
|
||||
#[cfg(test)]
|
||||
extern crate test;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate testing;
|
||||
|
||||
@ -32,10 +37,13 @@ pub use self::{hygiene::hygiene, inline_globals::InlineGlobals, simplify::simpli
|
||||
mod tests;
|
||||
#[macro_use]
|
||||
mod quote;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
pub mod compat;
|
||||
mod fixer;
|
||||
mod hygiene;
|
||||
mod inline_globals;
|
||||
pub mod pass;
|
||||
pub mod scope;
|
||||
mod simplify;
|
||||
pub mod util;
|
||||
|
26
ecmascript/transforms/src/macros.rs
Normal file
26
ecmascript/transforms/src/macros.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#[macro_export]
|
||||
macro_rules! chain_at {
|
||||
($T:ty, $a:expr, $b:expr) => {{
|
||||
use $crate::pass::JoinedPass;
|
||||
|
||||
JoinedPass {
|
||||
first: $a,
|
||||
second: $b,
|
||||
ty: ::std::marker::PhantomData::<$T>,
|
||||
}
|
||||
}};
|
||||
|
||||
($T:ty, $a:expr, $b:expr,) => {
|
||||
chain_at!($T, $a, $b)
|
||||
};
|
||||
|
||||
($T: ty, $a:expr, $b:expr, $($rest:tt)+) => {{
|
||||
use $crate::pass::JoinedPass;
|
||||
|
||||
JoinedPass {
|
||||
first: $a,
|
||||
second: chain_at!($T, $b, $($rest)*),
|
||||
ty: ::std::marker::PhantomData::<$T>,
|
||||
}
|
||||
}};
|
||||
}
|
168
ecmascript/transforms/src/pass.rs
Normal file
168
ecmascript/transforms/src/pass.rs
Normal file
@ -0,0 +1,168 @@
|
||||
use std::marker::PhantomData;
|
||||
use swc_common::{Fold, FoldWith};
|
||||
|
||||
// macro_rules! mk_impl {
|
||||
// ($T:ty) => {
|
||||
// // impl<A: Pass, B: Pass> Fold<$T> for JoinedPass<A, B> {
|
||||
// // fn fold(&mut self, node: $T) -> $T {
|
||||
// // self.second.fold(self.first.fold(node))
|
||||
// // }
|
||||
// // }
|
||||
// };
|
||||
// }
|
||||
|
||||
macro_rules! mk_trait {
|
||||
($($T:ty,)*) => {
|
||||
/// Crazy trait to make traversal fast again.
|
||||
pub trait Pass: $( ::swc_common::Fold<$T> + )* {}
|
||||
impl<P> Pass for P
|
||||
where P: ?Sized + $( ::swc_common::Fold<$T> +)*{
|
||||
|
||||
}
|
||||
|
||||
$(
|
||||
mk_impl!($T);
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
mk_trait!(
|
||||
// ArrayLit,
|
||||
// ArrayPat,
|
||||
// ArrowExpr,
|
||||
// AssignExpr,
|
||||
// AssignPat,
|
||||
// AssignPatProp,
|
||||
// AssignProp,
|
||||
// AwaitExpr,
|
||||
// BinExpr,
|
||||
// BlockStmt,
|
||||
// Bool,
|
||||
// BreakStmt,
|
||||
// CallExpr,
|
||||
// CatchClause,
|
||||
// Class,
|
||||
// ClassDecl,
|
||||
// ClassExpr,
|
||||
// ClassMethod,
|
||||
// CondExpr,
|
||||
// ContinueStmt,
|
||||
// DebuggerStmt,
|
||||
// DoWhileStmt,
|
||||
// EmptyStmt,
|
||||
// ExportAll,
|
||||
// ExportSpecifier,
|
||||
// ExprOrSpread,
|
||||
// FnDecl,
|
||||
// FnExpr,
|
||||
// ForInStmt,
|
||||
// ForOfStmt,
|
||||
// ForStmt,
|
||||
// Function,
|
||||
// GetterProp,
|
||||
// Ident,
|
||||
// IfStmt,
|
||||
// ImportDecl,
|
||||
// ImportDefault,
|
||||
// ImportSpecific,
|
||||
// ImportStarAs,
|
||||
// KeyValuePatProp,
|
||||
// KeyValueProp,
|
||||
// LabeledStmt,
|
||||
// MemberExpr,
|
||||
// MetaPropExpr,
|
||||
// MethodProp,
|
||||
// Module,
|
||||
// NamedExport,
|
||||
// NewExpr,
|
||||
// Null,
|
||||
// Number,
|
||||
// ObjectLit,
|
||||
// ObjectPat,
|
||||
// ParenExpr,
|
||||
// Regex,
|
||||
// RestPat,
|
||||
// ReturnStmt,
|
||||
// SeqExpr,
|
||||
// SetterProp,
|
||||
// SpreadElement,
|
||||
// Str,
|
||||
// SwitchCase,
|
||||
// SwitchStmt,
|
||||
// ThisExpr,
|
||||
// ThrowStmt,
|
||||
// TplElement,
|
||||
// TplLit,
|
||||
// TryStmt,
|
||||
// UnaryExpr,
|
||||
// UpdateExpr,
|
||||
// VarDecl,
|
||||
// VarDeclarator,
|
||||
// WhileStmt,
|
||||
// WithStmt,
|
||||
// YieldExpr,
|
||||
// // enums
|
||||
// AssignOp,
|
||||
// BinaryOp,
|
||||
// BlockStmtOrExpr,
|
||||
// ClassMethodKind,
|
||||
// Decl,
|
||||
// ExportDefaultDecl,
|
||||
// Expr,
|
||||
// ExprOrSuper,
|
||||
// ImportSpecifier,
|
||||
// Lit,
|
||||
// ModuleDecl,
|
||||
// ModuleItem,
|
||||
// ObjectPatProp,
|
||||
// Pat,
|
||||
// PatOrExpr,
|
||||
// Prop,
|
||||
// PropName,
|
||||
// PropOrSpread,
|
||||
// Stmt,
|
||||
// UnaryOp,
|
||||
// UpdateOp,
|
||||
// VarDeclKind,
|
||||
// VarDeclOrExpr,
|
||||
// VarDeclOrPat,
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct JoinedPass<A, B, N> {
|
||||
pub first: A,
|
||||
pub second: B,
|
||||
pub ty: PhantomData<N>,
|
||||
}
|
||||
|
||||
// fn type_name<T>() -> String {
|
||||
// format!("{}", unsafe { std::intrinsics::type_name::<T>() })
|
||||
// }
|
||||
|
||||
impl<A, B, T> Fold<T> for JoinedPass<A, B, T>
|
||||
where
|
||||
T: FoldWith<Self>,
|
||||
A: Fold<T>,
|
||||
B: Fold<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn fold(&mut self, node: T) -> T {
|
||||
// println!(
|
||||
// "Folding<{}><{}>({})",
|
||||
// type_name::<A>(),
|
||||
// type_name::<B>(),
|
||||
// type_name::<T>()
|
||||
// );
|
||||
self.second.fold(self.first.fold(node))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, T, N> Fold<T> for JoinedPass<A, B, N>
|
||||
where
|
||||
T: FoldWith<Self>,
|
||||
{
|
||||
#[inline(always)]
|
||||
default fn fold(&mut self, node: T) -> T {
|
||||
node.fold_children(self)
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ macro_rules! member_expr {
|
||||
member_expr!(@EXT, $span, obj, $($rest)* )
|
||||
}};
|
||||
|
||||
(@EXT, $span:expr, $obj:expr, $first:ident . $($rest:tt)* ) => {{
|
||||
(@EXT, $span:expr, $obj:expr, $first:ident . $($rest:tt)* ) => {{
|
||||
let prop = member_expr!($span, $first);
|
||||
|
||||
member_expr!(@EXT, $span, box Expr::Member(MemberExpr{
|
||||
@ -95,8 +95,10 @@ mod tests {
|
||||
use swc_common::DUMMY_SP as span;
|
||||
#[test]
|
||||
fn quote_member_expr() {
|
||||
let expr: Box<Expr> = member_expr!(span, Function.prototype.bind);
|
||||
|
||||
assert_eq_ignore_span!(
|
||||
member_expr!(span, Function.prototype.bind),
|
||||
expr,
|
||||
box Expr::Member(MemberExpr {
|
||||
span,
|
||||
obj: ExprOrSuper::Expr(box Expr::Member(MemberExpr {
|
||||
|
@ -1,8 +1,6 @@
|
||||
use ast::*;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
collections::HashSet,
|
||||
};
|
||||
use fnv::FnvHashSet;
|
||||
use std::cell::{Cell, RefCell};
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{Fold, FoldWith, SyntaxContext};
|
||||
|
||||
@ -34,12 +32,12 @@ pub struct Scope<'a> {
|
||||
pub used_this: Cell<bool>,
|
||||
|
||||
/// All references used in this scope
|
||||
pub used_refs: HashSet<Ident>,
|
||||
pub used_refs: FnvHashSet<Ident>,
|
||||
|
||||
/// All references declared in this scope
|
||||
pub declared_refs: HashSet<Ident>,
|
||||
pub declared_refs: FnvHashSet<Ident>,
|
||||
|
||||
pub declared_symbols: HashSet<JsWord>,
|
||||
pub declared_symbols: FnvHashSet<JsWord>,
|
||||
/* /// All children of the this scope
|
||||
* pub children: Vec<Scope<'a>>, */
|
||||
pub(crate) ops: RefCell<Vec<ScopeOp>>,
|
||||
|
@ -1,7 +1,6 @@
|
||||
#![feature(box_syntax)]
|
||||
|
||||
extern crate rayon;
|
||||
#[macro_use]
|
||||
pub extern crate slog;
|
||||
pub extern crate sourcemap;
|
||||
pub extern crate swc_atoms as atoms;
|
||||
@ -9,7 +8,7 @@ pub extern crate swc_common as common;
|
||||
pub extern crate swc_ecmascript as ecmascript;
|
||||
|
||||
use self::{
|
||||
common::{errors::Handler, sync::Lrc, SourceMap},
|
||||
common::{errors::Handler, sync::Lrc, FileName, SourceMap},
|
||||
ecmascript::{
|
||||
ast::Module,
|
||||
codegen::{self, Emitter},
|
||||
@ -24,7 +23,7 @@ use std::{
|
||||
};
|
||||
|
||||
pub struct Compiler {
|
||||
cm: Lrc<SourceMap>,
|
||||
pub cm: Lrc<SourceMap>,
|
||||
logger: Logger,
|
||||
handler: Handler,
|
||||
}
|
||||
@ -38,21 +37,27 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_js(&self, name: FileName, src: &str) -> Result<Module, ()> {
|
||||
let fm = self.cm.new_source_file(name, src.into());
|
||||
|
||||
let session = ParseSess {
|
||||
handler: &self.handler,
|
||||
logger: &self.logger,
|
||||
cfg: Default::default(),
|
||||
};
|
||||
Parser::new(session, SourceFileInput::from(&*fm)).parse_module()
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn parse_js(&self, path: &Path) -> Result<Module, ()> {
|
||||
pub fn parse_js_file(&self, path: &Path) -> Result<Module, ()> {
|
||||
let fm = self.cm.load_file(path).expect("failed to load file");
|
||||
|
||||
let logger = self
|
||||
.logger
|
||||
.new(o!("input" => format!("{}", path.display())));
|
||||
{
|
||||
let session = ParseSess {
|
||||
handler: &self.handler,
|
||||
logger: &logger,
|
||||
cfg: Default::default(),
|
||||
};
|
||||
Parser::new(session, SourceFileInput::from(&*fm)).parse_module()
|
||||
}
|
||||
let session = ParseSess {
|
||||
handler: &self.handler,
|
||||
logger: &self.logger,
|
||||
cfg: Default::default(),
|
||||
};
|
||||
Parser::new(session, SourceFileInput::from(&*fm)).parse_module()
|
||||
}
|
||||
|
||||
pub fn emit_module(
|
||||
|
@ -162,6 +162,7 @@ pub fn derive(input: DeriveInput) -> ItemImpl {
|
||||
},
|
||||
{
|
||||
impl<__Fold> swc_common::FoldWith<__Fold> for Type {
|
||||
#[inline]
|
||||
fn fold_children(self, _f: &mut __Fold) -> Self {
|
||||
body
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ pub fn derive(input: DeriveInput) -> ItemImpl {
|
||||
},
|
||||
{
|
||||
impl<__V> swc_common::VisitWith<__V> for Type {
|
||||
#[inline]
|
||||
fn visit_children(&self, _v: &mut __V) {
|
||||
body
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ fn run() -> Result<(), Box<Error>> {
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("jsc") {
|
||||
let input = matches.value_of("input file").unwrap();
|
||||
let res = comp.parse_js(Path::new(input));
|
||||
let res = comp.parse_js_file(Path::new(input));
|
||||
let module = match res {
|
||||
Ok(module) => module,
|
||||
Err(()) => {
|
||||
|
@ -56,6 +56,7 @@ where
|
||||
{
|
||||
Fold::<T>::fold(&mut DropSpan, t)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct DropSpan;
|
||||
impl Fold<Span> for DropSpan {
|
||||
|
Loading…
Reference in New Issue
Block a user