parent
60c0f40250
commit
dba8da4800
|
|
@ -826,10 +826,12 @@ merge(Compressor.prototype, {
|
||||||
(function(def){
|
(function(def){
|
||||||
def(AST_Statement, function(){ return null });
|
def(AST_Statement, function(){ return null });
|
||||||
def(AST_Jump, function(){ return this });
|
def(AST_Jump, function(){ return this });
|
||||||
def(AST_BlockStatement, function(){
|
function block_aborts(){
|
||||||
var n = this.body.length;
|
var n = this.body.length;
|
||||||
return n > 0 && aborts(this.body[n - 1]);
|
return n > 0 && aborts(this.body[n - 1]);
|
||||||
});
|
};
|
||||||
|
def(AST_BlockStatement, block_aborts);
|
||||||
|
def(AST_SwitchBranch, block_aborts);
|
||||||
def(AST_If, function(){
|
def(AST_If, function(){
|
||||||
return this.alternative && aborts(this.body) && aborts(this.alternative);
|
return this.alternative && aborts(this.body) && aborts(this.alternative);
|
||||||
});
|
});
|
||||||
|
|
@ -1360,6 +1362,74 @@ merge(Compressor.prototype, {
|
||||||
if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
|
if (stat instanceof AST_Break && loop_body(compressor.loopcontrol_target(stat.label)) === self)
|
||||||
last_branch.body.pop();
|
last_branch.body.pop();
|
||||||
}
|
}
|
||||||
|
var exp = self.expression.evaluate(compressor);
|
||||||
|
out: if (exp.length == 2) try {
|
||||||
|
// constant expression
|
||||||
|
self.expression = exp[0];
|
||||||
|
if (!compressor.option("dead_code")) break out;
|
||||||
|
var value = exp[1];
|
||||||
|
var in_substat = false;
|
||||||
|
var started = false;
|
||||||
|
var stopped = false;
|
||||||
|
var ruined = false;
|
||||||
|
var tt = new TreeTransformer(function(node, descend, in_list){
|
||||||
|
if (node instanceof AST_Lambda || node instanceof AST_SimpleStatement) {
|
||||||
|
// no need to descend these node types
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Switch) {
|
||||||
|
if (node === self) {
|
||||||
|
node = node.clone();
|
||||||
|
descend(node, this);
|
||||||
|
return ruined ? node : make_node(AST_BlockStatement, node, {
|
||||||
|
body: node.body.reduce(function(a, branch){
|
||||||
|
return a.concat(branch.body);
|
||||||
|
}, [])
|
||||||
|
}).transform(compressor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_StatementWithBody || node instanceof AST_Switch || node instanceof AST_Try) {
|
||||||
|
var save_substat = in_substat;
|
||||||
|
in_substat = true;
|
||||||
|
descend(node, this);
|
||||||
|
in_substat = save_substat;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Break && this.loopcontrol_target(node.label) === self) {
|
||||||
|
if (in_substat) {
|
||||||
|
// won't handle situations like if (foo) break;
|
||||||
|
ruined = true;
|
||||||
|
return node;
|
||||||
|
} else {
|
||||||
|
stopped = true;
|
||||||
|
}
|
||||||
|
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_SwitchBranch && this.parent() === self) {
|
||||||
|
if (stopped) return MAP.skip;
|
||||||
|
if (node instanceof AST_Case) {
|
||||||
|
var exp = node.expression.evaluate(compressor);
|
||||||
|
if (exp.length < 2) {
|
||||||
|
// got a case with non-constant expression, baling out
|
||||||
|
throw self;
|
||||||
|
}
|
||||||
|
if (exp[1] === value || started) {
|
||||||
|
started = true;
|
||||||
|
if (aborts(node)) stopped = true;
|
||||||
|
descend(node, this);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
return MAP.skip;
|
||||||
|
}
|
||||||
|
descend(node, this);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tt.stack = compressor.stack; // so that's able to see parent nodes
|
||||||
|
self = self.transform(tt);
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex !== self) throw ex;
|
||||||
|
}
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
186
test/compress/switch.js
Normal file
186
test/compress/switch.js
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
constant_switch_1: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
switch (1+1) {
|
||||||
|
case 1: foo(); break;
|
||||||
|
case 1+1: bar(); break;
|
||||||
|
case 1+1+1: baz(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_2: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
switch (1) {
|
||||||
|
case 1: foo();
|
||||||
|
case 1+1: bar(); break;
|
||||||
|
case 1+1+1: baz();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_3: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
switch (10) {
|
||||||
|
case 1: foo();
|
||||||
|
case 1+1: bar(); break;
|
||||||
|
case 1+1+1: baz();
|
||||||
|
default:
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_4: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
switch (2) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
if (foo) break;
|
||||||
|
y();
|
||||||
|
break;
|
||||||
|
case 1+1:
|
||||||
|
bar();
|
||||||
|
default:
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
bar();
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_5: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
switch (1) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
if (foo) break;
|
||||||
|
y();
|
||||||
|
break;
|
||||||
|
case 1+1:
|
||||||
|
bar();
|
||||||
|
default:
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
// the break inside the if ruins our job
|
||||||
|
// we can still get rid of irrelevant cases.
|
||||||
|
switch (1) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
if (foo) break;
|
||||||
|
y();
|
||||||
|
}
|
||||||
|
// XXX: we could optimize this better by inventing an outer
|
||||||
|
// labeled block, but that's kinda tricky.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_6: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
OUT: {
|
||||||
|
foo();
|
||||||
|
switch (1) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
if (foo) break OUT;
|
||||||
|
y();
|
||||||
|
case 1+1:
|
||||||
|
bar();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
OUT: {
|
||||||
|
foo();
|
||||||
|
x();
|
||||||
|
if (foo) break OUT;
|
||||||
|
y();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_7: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
OUT: {
|
||||||
|
foo();
|
||||||
|
switch (1) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
if (foo) break OUT;
|
||||||
|
for (var x = 0; x < 10; x++) {
|
||||||
|
if (x > 5) break; // this break refers to the for, not to the switch; thus it
|
||||||
|
// shouldn't ruin our optimization
|
||||||
|
console.log(x);
|
||||||
|
}
|
||||||
|
y();
|
||||||
|
case 1+1:
|
||||||
|
bar();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
OUT: {
|
||||||
|
foo();
|
||||||
|
x();
|
||||||
|
if (foo) break OUT;
|
||||||
|
for (var x = 0; x < 10; x++) {
|
||||||
|
if (x > 5) break;
|
||||||
|
console.log(x);
|
||||||
|
}
|
||||||
|
y();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_switch_8: {
|
||||||
|
options = { dead_code: true, evaluate: true };
|
||||||
|
input: {
|
||||||
|
OUT: switch (1) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
for (;;) break OUT;
|
||||||
|
y();
|
||||||
|
break;
|
||||||
|
case 1+1:
|
||||||
|
bar();
|
||||||
|
default:
|
||||||
|
def();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
OUT: switch (1) {
|
||||||
|
case 1:
|
||||||
|
x();
|
||||||
|
for (;;) break OUT;
|
||||||
|
y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user