mirror of
https://github.com/swc-project/swc.git
synced 2024-11-28 11:13:43 +03:00
2374 lines
53 KiB
Rust
2374 lines
53 KiB
Rust
//! Copied from https://github.com/google/closure-compiler/blob/6ca3b62990064488074a1a8931b9e8dc39b148b3/test/com/google/javascript/jscomp/InlineVariablesTest.java
|
|
|
|
use swc_common::{chain, Mark};
|
|
use swc_ecma_parser::{Syntax, TsConfig};
|
|
use swc_ecma_transforms_base::resolver;
|
|
use swc_ecma_transforms_compat::es2022::class_properties;
|
|
use swc_ecma_transforms_optimization::simplify::inlining::inlining;
|
|
use swc_ecma_transforms_testing::test;
|
|
use swc_ecma_transforms_typescript::strip;
|
|
use swc_ecma_visit::Fold;
|
|
|
|
fn simple_strip(top_level_mark: Mark) -> impl Fold {
|
|
strip::strip_with_config(
|
|
strip::Config {
|
|
no_empty_export: true,
|
|
..Default::default()
|
|
},
|
|
top_level_mark,
|
|
)
|
|
}
|
|
|
|
macro_rules! to {
|
|
($name:ident, $src:expr, $expected:expr) => {
|
|
test!(
|
|
Default::default(),
|
|
|_| chain!(
|
|
resolver(Mark::new(), Mark::new(), false),
|
|
inlining(Default::default())
|
|
),
|
|
$name,
|
|
$src,
|
|
$expected
|
|
);
|
|
};
|
|
|
|
(ignore, $name:ident, $src:expr, $expected:expr) => {
|
|
test!(
|
|
ignore,
|
|
Default::default(),
|
|
|_| chain!(
|
|
resolver(Mark::new(), Mark::new(), false),
|
|
inlining(Default::default())
|
|
),
|
|
$name,
|
|
$src,
|
|
$expected
|
|
);
|
|
};
|
|
}
|
|
|
|
macro_rules! identical {
|
|
($name:ident, $src:expr) => {
|
|
to!($name, $src, $src);
|
|
};
|
|
}
|
|
|
|
#[track_caller]
|
|
fn test(src: &str, expected: &str) {
|
|
swc_ecma_transforms_testing::test_transform(
|
|
::swc_ecma_parser::Syntax::default(),
|
|
|_| {
|
|
let unresolved_mark = Mark::new();
|
|
let top_level_mark = Mark::new();
|
|
|
|
chain!(
|
|
resolver(unresolved_mark, top_level_mark, false),
|
|
inlining(Default::default())
|
|
)
|
|
},
|
|
src,
|
|
expected,
|
|
true,
|
|
)
|
|
}
|
|
|
|
/// Should not modify expression.
|
|
fn test_same(s: &str) {
|
|
test(s, s)
|
|
}
|
|
|
|
to!(
|
|
top_level_simple_var,
|
|
"var a = 1; var b = a;",
|
|
"var a; var b;"
|
|
);
|
|
|
|
to!(
|
|
function_scope_simple_var,
|
|
"var a = 1;
|
|
var b = a;
|
|
use(b);",
|
|
"var a;
|
|
var b;
|
|
use(1);"
|
|
);
|
|
|
|
identical!(top_level_increment, "var x = 1; x++;");
|
|
|
|
identical!(top_level_decrement, "var x = 1; x--;");
|
|
|
|
identical!(top_level_assign_op, "var x = 1; x += 3;");
|
|
|
|
to!(
|
|
simple_inline_in_fn,
|
|
"var x = 1; var z = x; use(z)",
|
|
"var x; var z; use(1)"
|
|
);
|
|
|
|
to!(
|
|
ignore,
|
|
unresolved_inline_in_fn,
|
|
"var a = new obj();
|
|
result = a;",
|
|
"result = new obj()"
|
|
);
|
|
|
|
// GitHub issue #1234: https://github.com/google/closure-compiler/issues/1234
|
|
identical!(
|
|
closure_compiler_1234,
|
|
"var x;
|
|
switch ('a') {
|
|
case 'a':
|
|
break;
|
|
default:
|
|
x = 1;
|
|
break;
|
|
}
|
|
use(x);"
|
|
);
|
|
|
|
to!(
|
|
let_1,
|
|
"function f(x) {
|
|
if (true) {
|
|
let y = x;
|
|
y;
|
|
y;
|
|
}
|
|
}",
|
|
"function f(x) {
|
|
if (true) {
|
|
let y;
|
|
x;
|
|
x;
|
|
}
|
|
}"
|
|
);
|
|
|
|
to!(
|
|
const_1,
|
|
"function f(x) {
|
|
if (true) {
|
|
const y = x;
|
|
y;
|
|
y;
|
|
}
|
|
}",
|
|
"function f(x) {
|
|
if (true) {
|
|
const y = x;
|
|
x;
|
|
x;
|
|
}
|
|
}"
|
|
);
|
|
|
|
to!(
|
|
let_2,
|
|
"let y;
|
|
{
|
|
let y = x;
|
|
y;
|
|
}
|
|
y;
|
|
",
|
|
"let y;
|
|
{
|
|
let y1;
|
|
x;
|
|
}
|
|
y;"
|
|
);
|
|
|
|
to!(
|
|
let_const_1,
|
|
"
|
|
const g = 3;
|
|
let y = g;
|
|
y;
|
|
",
|
|
"const g = 3;
|
|
let y;
|
|
3;
|
|
"
|
|
);
|
|
|
|
to!(
|
|
let_const_2,
|
|
"let y = x;
|
|
y;
|
|
const g = 2;
|
|
{
|
|
const g = 3;
|
|
let y = g;
|
|
y;
|
|
}
|
|
y;
|
|
g;
|
|
",
|
|
"let y;
|
|
x;
|
|
const g = 2;
|
|
{
|
|
const g1 = 3;
|
|
let y1;
|
|
3;
|
|
}
|
|
x;
|
|
2;
|
|
"
|
|
);
|
|
|
|
to!(
|
|
regex,
|
|
"var b;b=/ab/;(b)?x=1:x=2;",
|
|
"var b;b=/ab/;/ab/?x=1:x=2;"
|
|
);
|
|
|
|
to!(
|
|
generator_let_yield,
|
|
"function* f() { let x = 1; yield x; }",
|
|
"function* f() { let x; yield 1; }"
|
|
);
|
|
|
|
// TODO: Inline single use
|
|
identical!(
|
|
generator_let_increment,
|
|
"function* f(x) { let y = x++; yield y; }"
|
|
);
|
|
|
|
identical!(for_of_1, "var i = 0; for(i of n) {}");
|
|
|
|
identical!(for_of_2, "for( var i of n) { var x = i; }");
|
|
|
|
to!(
|
|
tpl_lit_1,
|
|
"var name = 'Foo'; `Hello ${name}`",
|
|
"var name; `Hello ${'Foo'}`"
|
|
);
|
|
|
|
to!(
|
|
tpl_lit_2,
|
|
"var name = 'Foo'; var foo = name; `Hello ${foo}`",
|
|
"var name; var foo; `Hello ${'Foo'}`"
|
|
);
|
|
|
|
to!(
|
|
tpl_lit_3,
|
|
"var age = 3; `Age: ${age}`",
|
|
"var age; `Age: ${3}`"
|
|
);
|
|
|
|
to!(
|
|
ignore,
|
|
tagged_tpl_lit_1,
|
|
concat!(
|
|
"var name = 'Foo';",
|
|
"function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}",
|
|
"var output = myTag`My name is ${name} ${3}`;",
|
|
),
|
|
concat!(
|
|
"var output = function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}`My name is ${'Foo'} ${3}`;",
|
|
)
|
|
);
|
|
|
|
to!(
|
|
tagged_tpl_lit_2,
|
|
concat!(
|
|
"var name = 'Foo';",
|
|
"function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}",
|
|
"var output = myTag`My name is ${name} ${3}`;",
|
|
"output = myTag`My name is ${name} ${2}`;",
|
|
),
|
|
concat!(
|
|
"var name;",
|
|
"function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}",
|
|
"var output = myTag`My name is ${'Foo'} ${3}`;",
|
|
"output = myTag`My name is ${'Foo'} ${2}`;",
|
|
)
|
|
);
|
|
|
|
identical!(
|
|
function_scope_var_1,
|
|
"var x = 1;
|
|
function foo(){
|
|
x = 2;
|
|
}
|
|
use(x);
|
|
"
|
|
);
|
|
|
|
identical!(
|
|
function_scope_var_2,
|
|
"(function(){
|
|
var x = 1;
|
|
function foo(){
|
|
x = 2;
|
|
}
|
|
use(x);
|
|
})();"
|
|
);
|
|
|
|
identical!(
|
|
top_level_does_not_inline_fn_decl,
|
|
"function foo(){}
|
|
use(foo);"
|
|
);
|
|
|
|
to!(
|
|
custom_loop_1,
|
|
"
|
|
let b = 2;
|
|
|
|
let a = 1;
|
|
if (b) {
|
|
a = 2;
|
|
}
|
|
|
|
let c;
|
|
if (a) {
|
|
c = 3;
|
|
}
|
|
",
|
|
"let b;
|
|
|
|
let a = 1;
|
|
if (2) {
|
|
a = 2;
|
|
}
|
|
|
|
let c;
|
|
if (a) {
|
|
c = 3;
|
|
}"
|
|
);
|
|
|
|
to!(
|
|
custom_loop_2,
|
|
"let b = 2;
|
|
|
|
let a = 1;
|
|
a = 2;
|
|
|
|
let c;
|
|
if (a) c = 3",
|
|
"let b;
|
|
|
|
let a;
|
|
a = 2;
|
|
|
|
let c;
|
|
if (2) c = 3"
|
|
);
|
|
|
|
to!(
|
|
custom_loop_3,
|
|
"let c;
|
|
c = 3;
|
|
console.log(c);",
|
|
"let c;
|
|
c = 3;
|
|
console.log(3);"
|
|
);
|
|
|
|
#[test]
|
|
fn test_pass_doesnt_produce_invalid_code1() {
|
|
test_same(concat!(
|
|
"function f(x = void 0) {",
|
|
" var z;",
|
|
" {",
|
|
" const y = {};",
|
|
" x && (y['x'] = x);",
|
|
" z = y;",
|
|
" }",
|
|
" return z;",
|
|
"}",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_pass_doesnt_produce_invalid_code2() {
|
|
test_same(concat!(
|
|
"function f(x = void 0) {",
|
|
" {",
|
|
" var z;",
|
|
" const y = {};",
|
|
" x && (y['x'] = x);",
|
|
" z = y;",
|
|
" }",
|
|
" return z;",
|
|
"}",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_pass_doesnt_produce_invalid_code3() {
|
|
test(
|
|
concat!(
|
|
"function f(x = void 0) {",
|
|
" var z;",
|
|
" const y = {};",
|
|
" x && (y['x'] = x);",
|
|
" z = y;",
|
|
" {",
|
|
" return z;",
|
|
" }",
|
|
"}",
|
|
),
|
|
concat!(
|
|
"function f(x = void 0) {",
|
|
" var z;",
|
|
" const y = {};",
|
|
" x && (y['x'] = x);",
|
|
" z = y;",
|
|
" {",
|
|
" return y;",
|
|
" }",
|
|
"}",
|
|
),
|
|
);
|
|
}
|
|
|
|
// Test respect for scopes and blocks
|
|
|
|
#[test]
|
|
fn test_inline_global() {
|
|
test("var x = 1; var z = x;", "var x; var z;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_inline_increment() {
|
|
test_same("var x = 1; x++;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_inline_decrement() {
|
|
test_same("var x = 1; x--;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_inline_into_lhs_of_assign() {
|
|
test_same("var x = 1; x += 3;");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inline_into_rhs_of_assign() {
|
|
test("var x = foo(); var y = x;", "var x; var y = foo();");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_into_rhs_of_assign() {
|
|
test("var x = foo(); var y = x;", "var x = foo(); var y = x;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_in_function1() {
|
|
test(
|
|
"function baz() { var x = 1; var z = x; }",
|
|
"function baz() { var x; var z; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_in_function2() {
|
|
test(
|
|
"function baz() { var a = new obj(); result = a; }",
|
|
"function baz() { result = new obj() }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_in_function3() {
|
|
test_same("function baz() { var a = new obj(); (function(){a;})(); result = a; }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_in_function4() {
|
|
test_same("function baz() { var a = new obj(); foo.result = a; }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_in_function5() {
|
|
test(
|
|
"function baz() { var a = (foo = new obj()); foo.x(); result = a; }",
|
|
"function baz() { var a = foo = new obj(); foo.x(); result = a; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inline_in_function6() {
|
|
test(
|
|
"function baz() { { var x = foo(); var z = x; } }",
|
|
"function baz() { { var x; var z = foo(); } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_in_function6() {
|
|
test(
|
|
"function baz() { { var x = foo(); var z = x; } }",
|
|
"function baz() { { var x = foo(); var z = x; } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_in_function7() {
|
|
test(
|
|
"function baz() { var x = 1; { var z = x; } }",
|
|
"function baz() { var x; { var z; } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_arrow_function1() {
|
|
test("var x = 0; var f = () => x + 1;", "var f = () => 0 + 1;");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_arrow_function2() {
|
|
test(
|
|
"var x = 0; var f = () => { return x + 1; }",
|
|
"var f = () => { return 0 + 1; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_exit_conditional1() {
|
|
test_same("if (true) { var x = 1; } var z = x;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_exit_conditional2() {
|
|
test_same("if (true) var x = 1; var z = x;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_exit_conditional3() {
|
|
test_same("var x; if (true) x=1; var z = x;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_exit_loop() {
|
|
test_same("while (z) { var x = 3; } var y = x;");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_do_not_exit_for_loop() {
|
|
test(
|
|
"for (var i = 1; false; false) var z = i;",
|
|
"for (;false;false) var z = 1;",
|
|
);
|
|
test_same("for (; false; false) var i = 1; var z = i;");
|
|
test_same("for (var i in {}); var z = i;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_exit_for_loop() {
|
|
test(
|
|
"for (var i = 1; false; false) var z = i;",
|
|
"for (var i = 1;false;false) var z = i;",
|
|
);
|
|
test_same("for (; false; false) var i = 1; var z = i;");
|
|
test_same("for (var i in {}); var z = i;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_enter_subscope() {
|
|
test_same(concat!(
|
|
"var x = function() {",
|
|
" var self = this; ",
|
|
" return function() { var y = self; };",
|
|
"}"
|
|
));
|
|
test_same("var x = function() { var y = [1]; return function() { var z = y; }; }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_exit_try() {
|
|
test(
|
|
"try { var x = y; } catch (e) {} var z = y; ",
|
|
"try { var x = y; } catch (e) {} var z = y; ",
|
|
);
|
|
test_same("try { throw e; var x = 1; } catch (e1) {} var z = x; ");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_enter_catch() {
|
|
test_same("try { } catch (e) { var z = e; } ");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_enter_finally() {
|
|
test_same("try { throw e; var x = 1; } catch (e1) {} finally { var z = x; } ");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inside_if_conditional() {
|
|
test(
|
|
"var a = foo(); if (a) { alert(3); }",
|
|
"var a; if (foo()) { alert(3); }",
|
|
);
|
|
test(
|
|
"var a; a = foo(); if (a) { alert(3); }",
|
|
"var a; if (foo()) { alert(3); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_if_conditional() {
|
|
test(
|
|
"var a = foo(); if (a) { alert(3); }",
|
|
"var a = foo(); if (a) { alert(3); }",
|
|
);
|
|
test(
|
|
"var a; a = foo(); if (a) { alert(3); }",
|
|
"var a; a = foo(); if (a) { alert(3); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_only_read_at_initialization() {
|
|
test("var a; a = foo();", "foo();");
|
|
test(
|
|
"var a; if (a = foo()) { alert(3); }",
|
|
"if (foo()) { alert(3); }",
|
|
);
|
|
test("var a; switch (a = foo()) {}", "switch(foo()) {}");
|
|
test(
|
|
"var a; function f(){ return a = foo(); }",
|
|
"function f(){ return foo(); }",
|
|
);
|
|
test(
|
|
"function f(){ var a; return a = foo(); }",
|
|
"function f(){ return foo(); }",
|
|
);
|
|
test(
|
|
"var a; with (a = foo()) { alert(3); }",
|
|
"with (foo()) { alert(3); }",
|
|
);
|
|
|
|
test("var a; b = (a = foo());", "b = foo();");
|
|
test(
|
|
"var a; while(a = foo()) { alert(3); }",
|
|
"while(foo()) { alert(3); }",
|
|
);
|
|
test(
|
|
"var a; for(;a = foo();) { alert(3); }",
|
|
"for(;foo();) { alert(3); }",
|
|
);
|
|
test(
|
|
"var a; do {} while(a = foo()) { alert(3); }",
|
|
"do {} while(foo()) { alert(3); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_immutable_with_single_reference_after_initialzation() {
|
|
test("var a; a = 1;", "var a; a = 1;");
|
|
test("var a; if (a = 1) { alert(3); }", "if (1) { alert(3); }");
|
|
test("var a; switch (a = 1) {}", "switch(1) {}");
|
|
test(
|
|
"var a; function f(){ return a = 1; }",
|
|
"function f(){ return 1; }",
|
|
);
|
|
test(
|
|
"function f(){ var a; return a = 1; }",
|
|
"function f(){ return 1; }",
|
|
);
|
|
test(
|
|
"var a; with (a = 1) { alert(3); }",
|
|
"with (1) { alert(3); }",
|
|
);
|
|
|
|
test("var a; b = (a = 1);", "b = 1;");
|
|
test(
|
|
"var a; while(a = 1) { alert(3); }",
|
|
"while(1) { alert(3); }",
|
|
);
|
|
test(
|
|
"var a; for(;a = 1;) { alert(3); }",
|
|
"for(;1;) { alert(3); }",
|
|
);
|
|
test(
|
|
"var a; do {} while(a = 1) { alert(3); }",
|
|
"do {} while(1) { alert(3); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_single_reference_after_initialzation() {
|
|
test("var a; a = foo();a;", "foo();");
|
|
test_same("var a; if (a = foo()) { alert(3); } a;");
|
|
test_same("var a; switch (a = foo()) {} a;");
|
|
test_same("var a; function f(){ return a = foo(); } a;");
|
|
test_same("function f(){ var a; return a = foo(); a;}");
|
|
test_same("var a; with (a = foo()) { alert(3); } a;");
|
|
test_same("var a; b = (a = foo()); a;");
|
|
test_same("var a; while(a = foo()) { alert(3); } a;");
|
|
test_same("var a; for(;a = foo();) { alert(3); } a;");
|
|
test_same("var a; do {} while(a = foo()) { alert(3); } a;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_if_branch() {
|
|
test_same("var a = foo(); if (1) { alert(a); }");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inside_and_conditional() {
|
|
test("var a = foo(); a && alert(3);", "foo() && alert(3);");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_and_conditional() {
|
|
test(
|
|
"var a = foo(); a && alert(3);",
|
|
"var a = foo(); a && alert(3);",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_and_branch() {
|
|
test_same("var a = foo(); 1 && alert(a);");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_or_branch() {
|
|
test_same("var a = foo(); 1 || alert(a);");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_hook_branch() {
|
|
test_same("var a = foo(); 1 ? alert(a) : alert(3)");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inside_hook_conditional() {
|
|
test(
|
|
"var a = foo(); a ? alert(1) : alert(3)",
|
|
"foo() ? alert(1) : alert(3)",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_hook_conditional() {
|
|
test(
|
|
"var a = foo(); a ? alert(1) : alert(3)",
|
|
"var a = foo(); a ? alert(1) : alert(3)",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_or_branch_inside_if_conditional() {
|
|
test_same("var a = foo(); if (x || a) {}");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inside_or_branch_inside_if_conditional_with_constant() {
|
|
// We don't inline non-immutable constants into branches.
|
|
test_same("var a = [false]; if (x || a) {}");
|
|
}
|
|
|
|
// Test movement of constant values
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_do_cross_function() {
|
|
// We know foo() does not affect x because we require that x is only
|
|
// referenced twice.
|
|
test("var x = 1; foo(); var z = x;", "foo(); var z = 1;");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_do_not_cross_referencing_function() {
|
|
test_same("var f = function() { var z = x; }; var x = 1; f(); var z = x; f();");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_cross_referencing_function() {
|
|
test(
|
|
"var f = function() { var z = foo(); }; var x = 1; f(); var z = x; f();",
|
|
"var f = function() { var z = foo(); }; var x = 1; f(); var z = x; f();",
|
|
);
|
|
}
|
|
|
|
// Test tricky declarations and references
|
|
|
|
#[test]
|
|
fn test_chained_assignment() {
|
|
test("var a = 2, b = 2; var c = b;", "var a, b; var c;");
|
|
test("var a = 2, b = 2; var c = a;", "var a, b; var c;");
|
|
test(
|
|
"var a = b = 2; var f = 3; var c = a;",
|
|
"var a; var f; var c = b = 2;",
|
|
);
|
|
test_same("var a = b = 2; var c;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_for_in() {
|
|
test(
|
|
"for (var i in j) { var c = i; }",
|
|
"for (var i in j) { var c = i; }",
|
|
);
|
|
test_same("var i = 0; for (i in j) ;");
|
|
test_same("var i = 0; for (i in j) { var c = i; }");
|
|
test_same("i = 0; for (var i in j) { var c = i; }");
|
|
test_same("var j = {'key':'value'}; for (var i in j) {print(i)};");
|
|
}
|
|
|
|
// Test movement of values that have (may) side effects
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_do_cross_new_variables() {
|
|
test("var x = foo(); var z = x;", "var z = foo();");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_cross_function_calls() {
|
|
test_same("var x = foo(); bar(); var z = x;");
|
|
}
|
|
|
|
// Test movement of values that are complex but lack side effects
|
|
|
|
#[test]
|
|
fn test_do_not_cross_assignment() {
|
|
test_same("var x = {}; var y = x.a; x.a = 1; var z = y;");
|
|
test_same("var a = this.id; foo(this.id = 3, a);");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_cross_delete() {
|
|
test_same("var x = {}; var y = x.a; delete x.a; var z = y;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_cross_assignment_plus() {
|
|
test_same("var a = b; b += 2; var c = a;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_cross_increment() {
|
|
test_same("var a = b.c; b.c++; var d = a;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_do_not_cross_constructor() {
|
|
test_same("var a = b; new Foo(); var c = a;");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_do_cross_var() {
|
|
// Assumes we do not rely on undefined variables (not technically correct!)
|
|
test("var a = b; var b = 3; alert(a)", "alert(3);");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_overlapping_in_lines() {
|
|
test(
|
|
concat!(
|
|
"a = function(el, x, opt_y) { ",
|
|
" var cur = bar(el); ",
|
|
" opt_y = x.y; ",
|
|
" x = x.x; ",
|
|
" var dx = x - cur.x; ",
|
|
" var dy = opt_y - cur.y;",
|
|
" foo(el, el.offsetLeft + dx, el.offsetTop + dy); ",
|
|
"};"
|
|
),
|
|
concat!(
|
|
"a = function(el, x, opt_y) { ",
|
|
" var cur = bar(el); ",
|
|
" opt_y = x.y; ",
|
|
" x = x.x; ",
|
|
" foo(el, el.offsetLeft + (x - cur.x),",
|
|
" el.offsetTop + (opt_y - cur.y)); ",
|
|
"};"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_loops() {
|
|
test(
|
|
"var x = true; while (true) alert(x);",
|
|
"var x; while (true) alert(true);",
|
|
);
|
|
test(
|
|
"var x = true; while (true) for (var i in {}) alert(x);",
|
|
"var x; while (true) for (var i in {}) alert(true);",
|
|
);
|
|
test_same("var x = [true]; while (true) alert(x);");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_function() {
|
|
test(
|
|
"var x = false; var f = function() { alert(x); };",
|
|
"var f = function() { alert(false); };",
|
|
);
|
|
test_same("var x = [false]; var f = function() { alert(x); };");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_into_named_function() {
|
|
test_same("f(); var x = false; function f() { alert(x); };");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_nested_non_hoisted_named_functions() {
|
|
test(
|
|
"f(); var x = false; if (false) function f() { alert(x); };",
|
|
"f(); if (false) function f() { alert(false); };",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_into_nested_named_functions() {
|
|
test_same("f(); var x = false; function f() { if (false) { alert(x); } };");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_mutated_variable() {
|
|
test_same("var x = false; if (true) { var y = x; x = true; }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_immutable_multiple_times() {
|
|
test("var x = null; var y = x, z = x;", "var x; var y, z;");
|
|
test("var x = 3; var y = x, z = x;", "var x; var y, z;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_string_multiple_times_when_aliasing_all_strings() {
|
|
test(
|
|
"var x = 'abcdefghijklmnopqrstuvwxyz'; var y = x, z = x;",
|
|
"var x; var y, z;",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_backwards() {
|
|
test_same("var y = x; var x = foo();");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_out_of_branch() {
|
|
test_same("if (true) var x = foo(); var y = x;");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_interfering_in_lines() {
|
|
test(
|
|
"var a = 3; var f = function() { var x = a; alert(x); };",
|
|
"var a; var f = function() { var x; alert(3); };",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_interfering_in_lines() {
|
|
test(
|
|
"var a = 3; var f = function() { var x = a; alert(x); };",
|
|
"var a = 3; var f = function() { var x = a; alert(x); };",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_try_catch() {
|
|
test(
|
|
concat!(
|
|
"var a = true; ",
|
|
"try { var b = a; } ",
|
|
"catch (e) { var c = a + b; var d = true; } ",
|
|
"finally { var f = a + b + c + d; }"
|
|
),
|
|
concat!(
|
|
"try { var b = true; } ",
|
|
"catch (e) { var c = true + b; var d = true; } ",
|
|
"finally { var f = true + b + c + d; }"
|
|
),
|
|
);
|
|
}
|
|
|
|
// Make sure that we still inline constants that are not provably
|
|
// written before they're read.
|
|
#[test]
|
|
fn test_inline_constants() {
|
|
test(
|
|
"function foo() { return XXX; } var XXX = true;",
|
|
"function foo() { return XXX; } var XXX = true;",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_string_when_worthwhile() {
|
|
test("var x = 'a'; foo(x, x, x);", "var x; foo('a', 'a', 'a');");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_constant_alias() {
|
|
test(
|
|
"var XXX = new Foo(); q(XXX); var YYY = XXX; bar(YYY)",
|
|
"var XXX = new Foo(); q(XXX); var YYY = XXX; bar(YYY)",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inline_constant_alias_with_non_constant() {
|
|
test(
|
|
"var XXX = new Foo(); q(XXX); var y = XXX; bar(y); baz(y)",
|
|
"var XXX = new Foo(); q(XXX); var y; bar(XXX); baz(XXX)",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_constant_alias_with_non_constant() {
|
|
test(
|
|
"var XXX = new Foo(); q(XXX); var y = XXX; bar(y); baz(y)",
|
|
"var XXX = new Foo(); q(XXX); var y = XXX; bar(y); baz(y)",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_cascading_in_lines() {
|
|
test(
|
|
"var XXX = 4; function f() { var YYY = XXX; bar(YYY); baz(YYY); }",
|
|
"var XXX; function f() { var YYY; bar(4); baz(4); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cascading_in_lines() {
|
|
test(
|
|
"var XXX = 4; function f() { var YYY = XXX; bar(YYY); baz(YYY); }",
|
|
"var XXX = 4; function f() { var YYY = XXX; bar(YYY); baz(YYY); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_getprop_into_call_1() {
|
|
test("var a = b; a();", "var a; b();");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_getprop_into_call_2() {
|
|
test("var a = b.c; f(a);", "var a; f(b.c);");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_getprop_into_call_3() {
|
|
test_same("var a = b.c; a();");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_function_declaration() {
|
|
test(
|
|
"var f = function () {}; var a = f;",
|
|
"var f; var a = function () {};",
|
|
);
|
|
test(
|
|
"var f = function () {}; foo(); var a = f;",
|
|
"foo(); var a = function () {};",
|
|
);
|
|
test("var f = function () {}; foo(f);", "foo(function () {});");
|
|
|
|
test_same("var f = function () {}; function g() {var a = f;}");
|
|
test_same("var f = function () {}; function g() {h(f);}");
|
|
}
|
|
|
|
#[test]
|
|
fn test_recursive_function1() {
|
|
test(
|
|
"var x = 0; (function x() { return x ? x() : 3; })();",
|
|
"var x; (function x() { return x? x() : 3; })();",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_recursive_function2() {
|
|
test_same("function y() { return y(); }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_unreferenced_bleeding_function() {
|
|
test_same("var x = function y() {}");
|
|
}
|
|
|
|
#[test]
|
|
fn test_referenced_bleeding_function() {
|
|
test_same("var x = function y() { return y(); }");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases1() {
|
|
test(
|
|
"var x = this.foo(); this.bar(); var y = x; this.baz(y);",
|
|
"var x = this.foo(); this.bar(); var y; this.baz(x);",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases1b() {
|
|
test(
|
|
"var x = this.foo(); this.bar(); var y; y = x; this.baz(y);",
|
|
"var x = this.foo(); this.bar(); var y; x; this.baz(x);",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases1c() {
|
|
test(
|
|
"var x; x = this.foo(); this.bar(); var y = x; this.baz(y);",
|
|
"var x; x = this.foo(); this.bar(); var y; this.baz(x);",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases1d() {
|
|
test(
|
|
"var x; x = this.foo(); this.bar(); var y; y = x; this.baz(y);",
|
|
"var x; x = this.foo(); this.bar(); var y; x; this.baz(x);",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases2() {
|
|
test(
|
|
"var x = this.foo(); this.bar(); function f() { var y = x; this.baz(y); }",
|
|
"var x = this.foo(); this.bar(); function f() { var y; this.baz(x); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases2b() {
|
|
test(
|
|
"var x = this.foo(); this.bar(); function f() { var y; y = x; this.baz(y); }",
|
|
"var x = this.foo(); this.bar(); function f() { var y; x; this.baz(x); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases2c() {
|
|
test(
|
|
"var x; x = this.foo(); this.bar(); function f() { var y = x; this.baz(y); }",
|
|
"var x; x = this.foo(); this.bar(); function f() { var y = x; this.baz(x); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases2d() {
|
|
test(
|
|
"var x; x = this.foo(); this.bar(); function f() { var y; y = x; this.baz(y); }",
|
|
"var x; x = this.foo(); this.bar(); function f() { this.baz(x); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_aliases_in_loop() {
|
|
test(
|
|
concat!(
|
|
"function f() { ",
|
|
" var x = extern();",
|
|
" for (var i = 0; i < 5; i++) {",
|
|
" (function() {",
|
|
" var y = x; window.setTimeout(function() { extern(y); }, 0);",
|
|
" })();",
|
|
" }",
|
|
"}"
|
|
),
|
|
concat!(
|
|
"function f() { ",
|
|
" var x = extern();",
|
|
" for (var i = 0; i < 5; i++) {",
|
|
" (function() {",
|
|
" window.setTimeout(function() { extern(x); }, 0);",
|
|
" })();",
|
|
" }",
|
|
"}"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases_in_loop() {
|
|
test_same(concat!(
|
|
"function f() { ",
|
|
" for (var i = 0; i < 5; i++) {",
|
|
" var x = extern();",
|
|
" (function() {",
|
|
" var y = x; window.setTimeout(function() { extern(y); }, 0);",
|
|
" })();",
|
|
" }",
|
|
"}"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn modifier_test_no_inline_aliases1() {
|
|
test(
|
|
"var x = this.foo(); this.bar(); var y = x; x = 3; this.baz(y);",
|
|
"var x = this.foo(); this.bar(); var y = x; x = 3; this.baz(y);",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases1b() {
|
|
test_same("var x = this.foo(); this.bar(); var y; y = x; x = 3; this.baz(y);");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases2() {
|
|
test_same("var x = this.foo(); this.bar(); var y = x; y = 3; this.baz(y); ");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases2b() {
|
|
test_same("var x = this.foo(); this.bar(); var y; y = x; y = 3; this.baz(y); ");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases3() {
|
|
test_same(concat!(
|
|
"var x = this.foo(); this.bar(); ",
|
|
"function f() { var y = x; g(); this.baz(y); } ",
|
|
"function g() { x = 3; }"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases3b() {
|
|
test_same(concat!(
|
|
"var x = this.foo(); this.bar(); ",
|
|
"function f() { var y; y = x; g(); this.baz(y); } ",
|
|
"function g() { x = 3; }"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases4() {
|
|
test_same("var x = this.foo(); this.bar(); function f() { var y = x; y = 3; this.baz(y); }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases4b() {
|
|
test_same(
|
|
"var x = this.foo(); this.bar(); function f() { var y; y = x; y = 3; this.baz(y); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases5() {
|
|
test_same("var x = this.foo(); this.bar(); var y = x; this.bing(); this.baz(y); x = 3;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases5b() {
|
|
test_same("var x = this.foo(); this.bar(); var y; y = x; this.bing(); this.baz(y); x = 3;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases6() {
|
|
test_same("var x = this.foo(); this.bar(); var y = x; this.bing(); this.baz(y); y = 3;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases6b() {
|
|
test_same("var x = this.foo(); this.bar(); var y; y = x; this.bing(); this.baz(y); y = 3;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases7() {
|
|
test_same(concat!(
|
|
"var x = this.foo(); this.bar(); ",
|
|
"function f() { var y = x; this.bing(); this.baz(y); x = 3; }"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases7b() {
|
|
test_same(concat!(
|
|
"var x = this.foo(); this.bar(); ",
|
|
"function f() { var y; y = x; this.bing(); this.baz(y); x = 3; }"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases8() {
|
|
test_same("var x = this.foo(); this.bar(); function f() { var y = x; this.baz(y); y = 3; }");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_inline_aliases8b() {
|
|
test_same(
|
|
"var x = this.foo(); this.bar(); function f() { var y; y = x; this.baz(y); y = 3; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_parameter_alias1() {
|
|
test(
|
|
"function f(x) { var y = x; g(); y;y; }",
|
|
"function f(x) { var y; g(); x;x; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_parameter_alias2() {
|
|
test(
|
|
"function f(x) { var y; y = x; g(); y;y; }",
|
|
"function f(x) { x; g(); x;x; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_inline_function_alias1a() {
|
|
test(
|
|
"function f(x) {} var y = f; g(); y();y();",
|
|
"var y = function f(x) {}; g(); y();y();",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_function_alias1a() {
|
|
test(
|
|
"function f(x) {} var y = f; g(); y();y();",
|
|
"function f(x) {} var y; g(); f();f();",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_function_alias1b() {
|
|
test(
|
|
"function f(x) {}; f;var y = f; g(); y();y();",
|
|
"function f(x) {}; f; var y; g(); f();f();",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_function_alias2a() {
|
|
test(
|
|
"function f(x) {} var y; y = f; g(); y();y();",
|
|
"function f(x) {} var y; y = f; g(); f();f();",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_function_alias2b() {
|
|
test(
|
|
"function f(x) {}; f; var y; y = f; g(); y();y();",
|
|
"function f(x) {}; f; var y; y = f; g(); f();f();",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_switch_var() {
|
|
test("var x = y; switch (x) {}", "var x; switch (y) {}");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_switch_let() {
|
|
test("let x = y; switch (x) {}", "let x; switch (y) {}");
|
|
}
|
|
|
|
// Successfully inlines 'values' and 'e'
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_into_for_loop1() {
|
|
test(
|
|
concat!(
|
|
"function calculate_hashCode() {",
|
|
" var values = [1, 2, 3, 4, 5];",
|
|
" var hashCode = 1;",
|
|
" for (var $array = values, i = 0; i < $array.length; i++) {",
|
|
" var e = $array[i];",
|
|
" hashCode = 31 * hashCode + calculate_hashCode(e);",
|
|
" }",
|
|
" return hashCode;",
|
|
"}",
|
|
),
|
|
concat!(
|
|
"function calculate_hashCode() {",
|
|
" var hashCode = 1;",
|
|
" var $array = [1, 2, 3, 4, 5];",
|
|
" var i = 0;",
|
|
" for (; i < $array.length; i++) {",
|
|
" hashCode = 31 * hashCode + calculate_hashCode($array[i]);",
|
|
" }",
|
|
" return hashCode;",
|
|
"}",
|
|
),
|
|
);
|
|
}
|
|
|
|
// Inlines 'e' but fails to inline 'values'
|
|
// TODO(tbreisacher): Investigate and see if we can improve this.
|
|
#[test]
|
|
fn test_inline_into_for_loop2() {
|
|
test(
|
|
concat!(
|
|
"function calculate_hashCode() {",
|
|
" let values = [1, 2, 3, 4, 5];",
|
|
" let hashCode = 1;",
|
|
" for (let $array = values, i = 0; i < $array.length; i++) {",
|
|
" let e = $array[i];",
|
|
" hashCode = 31 * hashCode + calculate_hashCode(e);",
|
|
" }",
|
|
" return hashCode;",
|
|
"}",
|
|
),
|
|
concat!(
|
|
"function calculate_hashCode() {",
|
|
" let values = [1, 2, 3, 4, 5];",
|
|
" let hashCode = 1;",
|
|
" for (let $array = values, i = 0; i < $array.length; i++) {",
|
|
" let e = $array[i];",
|
|
" hashCode = 31 * hashCode + calculate_hashCode(e);",
|
|
" }",
|
|
" return hashCode;",
|
|
"}",
|
|
),
|
|
);
|
|
}
|
|
|
|
// This used to be inlined, but regressed when we switched to the ES6 scope
|
|
// creator.
|
|
#[test]
|
|
fn test_no_inline_catch_alias_var1() {
|
|
test_same(concat!(
|
|
"try {",
|
|
"} catch (e) {",
|
|
" var y = e;",
|
|
" g();",
|
|
" y;y;",
|
|
"}",
|
|
));
|
|
}
|
|
|
|
// This used to be inlined, but regressed when we switched to the ES6 scope
|
|
// creator.
|
|
#[test]
|
|
fn test_no_inline_catch_alias_var2() {
|
|
test_same(concat!(
|
|
"try {",
|
|
"} catch (e) {",
|
|
" var y; y = e;",
|
|
" g();",
|
|
" y;y;",
|
|
"}",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_catch_alias_let1() {
|
|
test(
|
|
concat!(
|
|
"try {",
|
|
"} catch (e) {",
|
|
" let y = e;",
|
|
" g();",
|
|
" y;y;",
|
|
"}",
|
|
),
|
|
concat!("try {", "} catch (e) {", " g();", " e;e;", "}"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_catch_alias_let2() {
|
|
test(
|
|
concat!(
|
|
"try {",
|
|
"} catch (e) {",
|
|
" let y; y = e;",
|
|
" g();",
|
|
" y;y;",
|
|
"}",
|
|
),
|
|
concat!("try {", "} catch (e) {", " e;", " g();", " e;e;", "}"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_this() {
|
|
test(
|
|
concat!(
|
|
"/** @constructor */",
|
|
"function C() {}",
|
|
"",
|
|
"C.prototype.m = function() {",
|
|
" var self = this;",
|
|
" if (true) {",
|
|
" alert(self);",
|
|
" }",
|
|
"};",
|
|
),
|
|
concat!(
|
|
"(/** @constructor */",
|
|
"function C() {}).prototype.m = function() {",
|
|
" if (true) {",
|
|
" alert(this);",
|
|
" }",
|
|
"};",
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_var_in_block1() {
|
|
test(
|
|
"function f(x) { if (true) {var y = x; y; y;} }",
|
|
"function f(x) { if (true) {var y; x; x;} }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_var_in_block2() {
|
|
test(
|
|
"function f(x) { switch (0) { case 0: { var y = x; y; y; } } }",
|
|
"function f(x) { switch (0) { case 0: { var y; x; x; } } }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_undefined1() {
|
|
test("var x; x;", "var x; void 0;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_undefined2() {
|
|
test_same("var x; x++;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_undefined3() {
|
|
test_same("var x; var x;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_undefined4() {
|
|
test("var x; x; x;", "var x; void 0; void 0;");
|
|
}
|
|
|
|
#[test]
|
|
fn test_inline_undefined5() {
|
|
test_same("var x; for(x in a) {}");
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue90() {
|
|
test("var x; x && alert(1)", "var x; (void 0) && alert(1)");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_this_alias() {
|
|
test(
|
|
"function f() { var a = this; a.y(); a.z(); }",
|
|
"function f() { this.y(); this.z(); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_this_escaped_alias() {
|
|
test_same("function f() { var a = this; var g = function() { a.y(); }; a.z(); }");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_inline_named_function() {
|
|
test("function f() {} f();", "(function f(){})()");
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue378_modified_arguments1() {
|
|
test_same(concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" arguments[0] = this;\n",
|
|
" f.apply(this, arguments);\n",
|
|
"}"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue378_modified_arguments2() {
|
|
test_same(concat!(
|
|
"function g(callback) {\n",
|
|
" /** @const */\n",
|
|
" var f = callback;\n",
|
|
" arguments[0] = this;\n",
|
|
" f.apply(this, arguments);\n",
|
|
"}"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue378_escaped_arguments1() {
|
|
test_same(concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" h(arguments,this);\n",
|
|
" f.apply(this, arguments);\n",
|
|
"}\n",
|
|
"function h(a,b) {\n",
|
|
" a[0] = b;",
|
|
"}"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue378_escaped_arguments2() {
|
|
test_same(concat!(
|
|
"function g(callback) {\n",
|
|
" /** @const */\n",
|
|
" var f = callback;\n",
|
|
" h(arguments,this);\n",
|
|
" f.apply(this);\n",
|
|
"}\n",
|
|
"function h(a,b) {\n",
|
|
" a[0] = b;",
|
|
"}"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // We just give up optimization when arguments is used
|
|
fn test_issue378_escaped_arguments3() {
|
|
test(
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" f.apply(this, arguments);\n",
|
|
"}\n"
|
|
),
|
|
"function g(callback) {\n callback.apply(this, arguments);\n }\n",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue378_escaped_arguments4() {
|
|
test_same(concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" h(arguments[0],this);\n",
|
|
" f.apply(this, arguments);\n",
|
|
"}\n",
|
|
"function h(a,b) {\n",
|
|
" a[0] = b;",
|
|
"}"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // We just give up optimization when arguments is used
|
|
fn test_issue378_arguments_read1() {
|
|
test(
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" var g = arguments[0];\n",
|
|
" f.apply(this, arguments);\n",
|
|
"}"
|
|
),
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var g = arguments[0];\n",
|
|
" callback.apply(this, arguments);\n",
|
|
"}"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // We just give up optimization when arguments is used
|
|
fn test_issue378_arguments_read2() {
|
|
test(
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" h(arguments[0],this);\n",
|
|
" f.apply(this, arguments[0]);\n",
|
|
"}\n",
|
|
"function h(a,b) {\n",
|
|
" a[0] = b;",
|
|
"}"
|
|
),
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" h(arguments[0],this);\n",
|
|
" callback.apply(this, arguments[0]);\n",
|
|
"}\n",
|
|
"function h(a,b) {\n",
|
|
" a[0] = b;",
|
|
"}"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // We just give up optimization when arguments is used
|
|
fn test_arguments_modified_in_outer_function() {
|
|
test(
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" arguments[0] = this;\n",
|
|
" f.apply(this, arguments);\n",
|
|
" function inner(callback) {",
|
|
" var x = callback;\n",
|
|
" x.apply(this);\n",
|
|
" }",
|
|
"}"
|
|
),
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" arguments[0] = this;\n",
|
|
" f.apply(this, arguments);\n",
|
|
" function inner(callback) {",
|
|
" callback.apply(this);\n",
|
|
" }",
|
|
"}"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore] // We just give up optimization when arguments is used
|
|
fn test_arguments_modified_in_inner_function() {
|
|
test(
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" var f = callback;\n",
|
|
" f.apply(this, arguments);\n",
|
|
" function inner(callback) {",
|
|
" var x = callback;\n",
|
|
" arguments[0] = this;\n",
|
|
" x.apply(this);\n",
|
|
" }",
|
|
"}"
|
|
),
|
|
concat!(
|
|
"function g(callback) {\n",
|
|
" callback.apply(this, arguments);\n",
|
|
" function inner(callback1) {",
|
|
" var x = callback1;\n",
|
|
" arguments[0] = this;\n",
|
|
" x.apply(this);\n",
|
|
" }",
|
|
"}"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_bug6598844() {
|
|
test_same(concat!(
|
|
"function F() { this.a = 0; }",
|
|
"F.prototype.inc = function() { this.a++; return 10; };",
|
|
"F.prototype.bar = function() { var x = this.inc(); this.a += x; };"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_external_issue1053() {
|
|
test_same("var u; function f() { u = Random(); var x = u; f(); alert(x===u)}");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_hoisted_function1() {
|
|
test(
|
|
"var x = 1; function f() { return x; }",
|
|
"var x; function f() { return 1; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_hoisted_function2() {
|
|
test_same(concat!(
|
|
"var impl_0;",
|
|
"b(a());",
|
|
"function a() { impl_0 = {}; }",
|
|
"function b() { window['f'] = impl_0; }"
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_hoisted_function3() {
|
|
test_same("var impl_0; b(); impl_0 = 1; function b() { window['f'] = impl_0; }");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_hoisted_function4() {
|
|
test(
|
|
"var impl_0; impl_0 = 1; b(); function b() { window['f'] = impl_0; }",
|
|
"var impl_0; 1; b(); function b() { window['f'] = 1; }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_hoisted_function5() {
|
|
test_same("a(); var debug = 1; function b() { return debug; } function a() { return b(); }");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_hoisted_function6() {
|
|
test(
|
|
concat!(
|
|
"var debug = 1;",
|
|
"a();",
|
|
"function b() { return debug; }",
|
|
"function a() { return b(); }"
|
|
),
|
|
"var debug; a(); function b() { return 1; } function a() { return b(); }",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_issue354() {
|
|
test(
|
|
concat!(
|
|
"var enabled = true;",
|
|
"function Widget() {}",
|
|
"Widget.prototype = {",
|
|
" frob: function() {",
|
|
" search();",
|
|
" }",
|
|
"};",
|
|
"function search() {",
|
|
" if (enabled)",
|
|
" alert(1);",
|
|
" else",
|
|
" alert(2);",
|
|
"}",
|
|
"window.foo = new Widget();",
|
|
"window.bar = search;"
|
|
),
|
|
concat!(
|
|
"var enabled;",
|
|
"function Widget() {}",
|
|
"Widget.prototype = {",
|
|
" frob: function() {",
|
|
" search();",
|
|
" }",
|
|
"};",
|
|
"function search() {",
|
|
" if (true)",
|
|
" alert(1);",
|
|
" else",
|
|
" alert(2);",
|
|
"}",
|
|
"window.foo = new Widget();",
|
|
"window.bar = search;"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_issue354() {
|
|
test(
|
|
concat!(
|
|
"var enabled = true;",
|
|
"function Widget() {}",
|
|
"Widget.prototype = {",
|
|
" frob: function() {",
|
|
" search();",
|
|
" }",
|
|
"};",
|
|
"function search() {",
|
|
" if (enabled)",
|
|
" alert(1);",
|
|
" else",
|
|
" alert(2);",
|
|
"}",
|
|
"window.foo = new Widget();",
|
|
"window.bar = search;"
|
|
),
|
|
concat!(
|
|
"var enabled = true;",
|
|
"function Widget() {}",
|
|
"Widget.prototype = {",
|
|
" frob: function() {",
|
|
" search();",
|
|
" }",
|
|
"};",
|
|
"function search() {",
|
|
" if (enabled)",
|
|
" alert(1);",
|
|
" else",
|
|
" alert(2);",
|
|
"}",
|
|
"window.foo = new Widget();",
|
|
"window.bar = search;"
|
|
),
|
|
);
|
|
}
|
|
|
|
// Test respect for scopes and blocks
|
|
#[test]
|
|
#[ignore]
|
|
fn orig_test_issue1177() {
|
|
test_same("function x_64(){var x_7;for(;;);var x_68=x_7=x_7;}");
|
|
test_same("function x_64(){var x_7;for(;;);var x_68=x_7=x_7++;}");
|
|
test_same("function x_64(){var x_7;for(;;);var x_68=x_7=x_7*2;}");
|
|
}
|
|
|
|
// GitHub issue #1234: https://github.com/google/closure-compiler/issues/1234
|
|
#[test]
|
|
fn test_switch_github_issue1234() {
|
|
test_same(concat!(
|
|
"var x;",
|
|
"switch ('a') {",
|
|
" case 'a':",
|
|
" break;",
|
|
" default:",
|
|
" x = 1;",
|
|
" break;",
|
|
"}",
|
|
"use(x);",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_let_const() {
|
|
test(
|
|
concat!(
|
|
"function f(x) {",
|
|
" if (true) {",
|
|
" let y = x; y; y;",
|
|
" }",
|
|
"}",
|
|
),
|
|
concat!(
|
|
"function f(x) {",
|
|
" if (true) { ",
|
|
" let y;",
|
|
" x; x;",
|
|
" }",
|
|
"}"
|
|
),
|
|
);
|
|
|
|
test(
|
|
concat!(
|
|
"function f(x) {",
|
|
" if (true) {",
|
|
" const y = x; y; y;",
|
|
" }",
|
|
" }",
|
|
),
|
|
concat!(
|
|
"function f(x) {",
|
|
" if (true) {",
|
|
" const y = x;",
|
|
" x; x;",
|
|
" }",
|
|
"}"
|
|
),
|
|
);
|
|
|
|
test(
|
|
concat!(
|
|
"function f(x) {",
|
|
" let y;",
|
|
" {",
|
|
" let y = x; y;",
|
|
" }",
|
|
"}",
|
|
),
|
|
concat!(
|
|
"function f(x) {",
|
|
" let y;",
|
|
" { let y1;",
|
|
" x;",
|
|
" }",
|
|
"}"
|
|
),
|
|
);
|
|
|
|
test(
|
|
concat!(
|
|
"function f(x) {",
|
|
" let y = x; y; const g = 2; ",
|
|
" {",
|
|
" const g = 3; let y = g; y;",
|
|
" }",
|
|
"}",
|
|
),
|
|
concat!(
|
|
"function f(x) {",
|
|
" let y; ",
|
|
" x; const g = 2;",
|
|
" { const g1 = 3; let y1; 3;}",
|
|
"}"
|
|
),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_generators() {
|
|
test(
|
|
concat!("function* f() {", " let x = 1;", " yield x;", "}"),
|
|
concat!("function* f() {", " let x;", " yield 1;", "}"),
|
|
);
|
|
|
|
test(
|
|
concat!("function* f(x) {", " let y = x++", " yield y;", "}"),
|
|
concat!("function* f(x) {", " yield x++;", "}"),
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_template_strings() {
|
|
test(
|
|
" var name = 'Foo'; `Hello ${name}`",
|
|
"var name;`Hello ${'Foo'}`",
|
|
);
|
|
|
|
test(
|
|
" var name = 'Foo'; var foo = name; `Hello ${foo}`",
|
|
"var name;
|
|
var foo; `Hello ${'Foo'}`",
|
|
);
|
|
|
|
test(" var age = 3; `Age: ${age}`", "var age; `Age: ${3}`");
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_tagged_template_literals() {
|
|
test(
|
|
concat!(
|
|
"var name = 'Foo';",
|
|
"function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}",
|
|
"var output = myTag`My name is ${name} ${3}`;",
|
|
),
|
|
concat!(
|
|
"var output = function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}`My name is ${'Foo'} ${3}`;",
|
|
),
|
|
);
|
|
|
|
test(
|
|
concat!(
|
|
"var name = 'Foo';",
|
|
"function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}",
|
|
"var output = myTag`My name is ${name} ${3}`;",
|
|
"output = myTag`My name is ${name} ${2}`;",
|
|
),
|
|
concat!(
|
|
"function myTag(strings, nameExp, numExp) {",
|
|
" var modStr;",
|
|
" if (numExp > 2) {",
|
|
" modStr = nameExp + 'Bar'",
|
|
" } else { ",
|
|
" modStr = nameExp + 'BarBar'",
|
|
" }",
|
|
"}",
|
|
"var output = myTag`My name is ${'Foo'} ${3}`;",
|
|
"output = myTag`My name is ${'Foo'} ${2}`;",
|
|
),
|
|
);
|
|
}
|
|
|
|
test!(
|
|
Syntax::Typescript(TsConfig {
|
|
decorators: true,
|
|
..Default::default()
|
|
}),
|
|
|t| {
|
|
let unresolved_mark = Mark::new();
|
|
let top_level_mark = Mark::fresh(Mark::root());
|
|
chain!(
|
|
resolver(unresolved_mark, top_level_mark, false),
|
|
simple_strip(top_level_mark),
|
|
class_properties(
|
|
Some(t.comments.clone()),
|
|
class_properties::Config {
|
|
set_public_fields: true,
|
|
..Default::default()
|
|
}
|
|
),
|
|
inlining(Default::default())
|
|
)
|
|
},
|
|
issue_1156_1,
|
|
"
|
|
export interface D {
|
|
resolve: any;
|
|
reject: any;
|
|
}
|
|
|
|
export function d(): D {
|
|
let methods;
|
|
const promise = new Promise((resolve, reject) => {
|
|
methods = { resolve, reject };
|
|
});
|
|
return Object.assign(promise, methods);
|
|
}
|
|
",
|
|
"
|
|
export function d() {
|
|
let methods;
|
|
const promise = new Promise((resolve, reject)=>{
|
|
methods = {
|
|
resolve,
|
|
reject
|
|
};
|
|
});
|
|
return Object.assign(promise, methods);
|
|
}
|
|
"
|
|
);
|
|
|
|
test!(
|
|
Syntax::Typescript(TsConfig {
|
|
decorators: true,
|
|
..Default::default()
|
|
}),
|
|
|t| {
|
|
let unresolved_mark = Mark::new();
|
|
let top_level_mark = Mark::new();
|
|
chain!(
|
|
resolver(unresolved_mark, top_level_mark, false),
|
|
simple_strip(top_level_mark),
|
|
class_properties(
|
|
Some(t.comments.clone()),
|
|
class_properties::Config {
|
|
set_public_fields: true,
|
|
..Default::default()
|
|
}
|
|
),
|
|
inlining(Default::default())
|
|
)
|
|
},
|
|
issue_1156_2,
|
|
"
|
|
interface D {
|
|
resolve: any;
|
|
reject: any;
|
|
}
|
|
|
|
function d(): D {
|
|
let methods;
|
|
const promise = new Promise((resolve, reject) => {
|
|
methods = { resolve, reject };
|
|
});
|
|
return Object.assign(promise, methods);
|
|
}
|
|
|
|
class A {
|
|
private s: D = d();
|
|
|
|
a() {
|
|
this.s.resolve();
|
|
}
|
|
|
|
b() {
|
|
this.s = d();
|
|
}
|
|
}
|
|
|
|
new A();
|
|
",
|
|
"
|
|
function d() {
|
|
let methods;
|
|
const promise = new Promise((resolve, reject)=>{
|
|
methods = {
|
|
resolve,
|
|
reject
|
|
};
|
|
});
|
|
return Object.assign(promise, methods);
|
|
}
|
|
class A {
|
|
a() {
|
|
this.s.resolve();
|
|
}
|
|
b() {
|
|
this.s = d();
|
|
}
|
|
constructor(){
|
|
this.s = d();
|
|
}
|
|
}
|
|
new A();
|
|
"
|
|
);
|
|
|
|
test!(
|
|
Syntax::Typescript(TsConfig {
|
|
decorators: true,
|
|
..Default::default()
|
|
}),
|
|
|_| {
|
|
let unresolved_mark = Mark::new();
|
|
let top_level_mark = Mark::new();
|
|
chain!(
|
|
resolver(unresolved_mark, top_level_mark, false),
|
|
simple_strip(top_level_mark),
|
|
inlining(Default::default())
|
|
)
|
|
},
|
|
deno_8180_1,
|
|
r#"
|
|
var Status;
|
|
(function (Status) {
|
|
Status[Status["Continue"] = 100] = "Continue";
|
|
Status[Status["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
})(Status || (Status = {}));
|
|
const STATUS_TEXT = new Map([
|
|
[
|
|
Status.Continue,
|
|
"Continue"
|
|
],
|
|
[
|
|
Status.SwitchingProtocols,
|
|
"Switching Protocols"
|
|
]
|
|
]);
|
|
"#,
|
|
r#"
|
|
var Status;
|
|
(function(Status) {
|
|
Status[Status["Continue"] = 100] = "Continue";
|
|
Status[Status["SwitchingProtocols"] = 101] = "SwitchingProtocols";
|
|
})(Status || (Status = {
|
|
}));
|
|
const STATUS_TEXT = new Map([
|
|
[
|
|
Status.Continue,
|
|
"Continue"
|
|
],
|
|
[
|
|
Status.SwitchingProtocols,
|
|
"Switching Protocols"
|
|
]
|
|
]);
|
|
"#
|
|
);
|
|
|
|
test!(
|
|
Syntax::Typescript(TsConfig {
|
|
decorators: true,
|
|
..Default::default()
|
|
}),
|
|
|_| {
|
|
let unresolved_mark = Mark::new();
|
|
let top_level_mark = Mark::new();
|
|
chain!(
|
|
resolver(unresolved_mark, top_level_mark, false),
|
|
simple_strip(top_level_mark),
|
|
inlining(Default::default())
|
|
)
|
|
},
|
|
deno_8189_1,
|
|
"
|
|
let A, I = null;
|
|
function g() {
|
|
return null !== I && I.buffer === A.memory.buffer || (I = new \
|
|
Uint8Array(A.memory.buffer)), I
|
|
}
|
|
",
|
|
"
|
|
let A, I = null;
|
|
function g() {
|
|
return null !== I && I.buffer === A.memory.buffer || (I = new \
|
|
Uint8Array(A.memory.buffer)), I;
|
|
}
|
|
"
|
|
);
|