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:
강동윤 2018-12-01 22:24:26 +09:00 committed by GitHub
parent ea910a4dfb
commit 222bdc191f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1264 additions and 190 deletions

View File

@ -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

View 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
View 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);
}
}

View File

@ -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),

View File

@ -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
View 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)
}
}
}

View 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()
);
}

View File

@ -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(())
});
}

View File

@ -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" }

View 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(())
});
}

View 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 });
}

View 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
}

View File

@ -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 {

View File

@ -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) {

View File

@ -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>,
}

View File

@ -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 {

View File

@ -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));

View File

@ -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() {

View File

@ -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> {

View File

@ -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 = {

View File

@ -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>,

View File

@ -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,

View File

@ -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(),
)
}

View File

@ -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) {

View File

@ -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) {

View File

@ -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 {

View File

@ -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");

View File

@ -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(),

View File

@ -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)
}

View File

@ -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;
}

View File

@ -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;

View 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>,
}
}};
}

View 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)
}
}

View File

@ -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 {

View File

@ -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>>,

View File

@ -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(

View File

@ -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
}

View File

@ -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
}

View File

@ -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(()) => {

View File

@ -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 {