enhance join_vars & sequences (#2697)

- nudge declarations without assignments
  - within `AST_BlockStatement`
  - across `AST_If`
This commit is contained in:
Alex Lam S.L
2018-01-01 00:09:26 +08:00
committed by GitHub
parent da82fa59a7
commit 673b071637
4 changed files with 160 additions and 18 deletions

View File

@@ -884,6 +884,7 @@ merge(Compressor.prototype, {
} }
if (compressor.sequences_limit > 0) { if (compressor.sequences_limit > 0) {
sequencesize(statements, compressor); sequencesize(statements, compressor);
sequencesize_2(statements, compressor);
} }
if (compressor.option("join_vars")) { if (compressor.option("join_vars")) {
join_consecutive_vars(statements, compressor); join_consecutive_vars(statements, compressor);
@@ -1537,6 +1538,12 @@ merge(Compressor.prototype, {
}); });
} }
function declarations_only(node) {
return all(node.definitions, function(var_def) {
return !var_def.value;
});
}
function sequencesize(statements, compressor) { function sequencesize(statements, compressor) {
if (statements.length < 2) return; if (statements.length < 2) return;
var seq = [], n = 0; var seq = [], n = 0;
@@ -1553,6 +1560,9 @@ merge(Compressor.prototype, {
var body = stat.body; var body = stat.body;
if (seq.length > 0) body = body.drop_side_effect_free(compressor); if (seq.length > 0) body = body.drop_side_effect_free(compressor);
if (body) merge_sequence(seq, body); if (body) merge_sequence(seq, body);
} else if (stat instanceof AST_Definitions && declarations_only(stat)
|| stat instanceof AST_Defun) {
statements[n++] = stat;
} else { } else {
push_seq(); push_seq();
statements[n++] = stat; statements[n++] = stat;
@@ -1560,13 +1570,31 @@ merge(Compressor.prototype, {
} }
push_seq(); push_seq();
statements.length = n; statements.length = n;
sequencesize_2(statements, compressor); if (n != len) CHANGED = true;
CHANGED = statements.length != len; }
function to_simple_statement(block, decls) {
if (!(block instanceof AST_BlockStatement)) return block;
var defs = [];
var stat = null;
for (var i = 0, len = block.body.length; i < len; i++) {
var line = block.body[i];
if (line instanceof AST_Definitions && declarations_only(line)) {
defs.push(line);
} else if (stat) {
return false;
} else {
stat = line;
}
}
[].push.apply(decls, defs);
return stat;
} }
function sequencesize_2(statements, compressor) { function sequencesize_2(statements, compressor) {
function cons_seq(right) { function cons_seq(right) {
n--; n--;
CHANGED = true;
var left = prev.body; var left = prev.body;
return make_sequence(left, [ left, right ]).transform(compressor); return make_sequence(left, [ left, right ]).transform(compressor);
}; };
@@ -1588,6 +1616,7 @@ merge(Compressor.prototype, {
else { else {
stat.init = prev.body; stat.init = prev.body;
n--; n--;
CHANGED = true;
} }
} }
} }
@@ -1607,6 +1636,22 @@ merge(Compressor.prototype, {
stat.expression = cons_seq(stat.expression); stat.expression = cons_seq(stat.expression);
} }
} }
if (compressor.option("conditionals") && stat instanceof AST_If) {
var decls = [];
var body = to_simple_statement(stat.body, decls);
var alt = to_simple_statement(stat.alternative, decls);
if (body !== false && alt !== false && decls.length > 0) {
decls.push(make_node(AST_If, stat, {
condition: stat.condition,
body: body || make_node(AST_EmptyStatement, stat.body),
alternative: alt
}));
stat = make_node(AST_BlockStatement, stat, {
body: decls
});
CHANGED = true;
}
}
statements[n++] = stat; statements[n++] = stat;
prev = stat instanceof AST_SimpleStatement ? stat : null; prev = stat instanceof AST_SimpleStatement ? stat : null;
} }
@@ -1614,30 +1659,43 @@ merge(Compressor.prototype, {
} }
function join_consecutive_vars(statements, compressor) { function join_consecutive_vars(statements, compressor) {
var defs;
for (var i = 0, j = -1, len = statements.length; i < len; i++) { for (var i = 0, j = -1, len = statements.length; i < len; i++) {
var stat = statements[i]; var stat = statements[i];
var prev = statements[j]; var prev = statements[j];
if (stat instanceof AST_Definitions && prev && prev.TYPE == stat.TYPE) { if (stat instanceof AST_Definitions) {
if (prev && prev.TYPE == stat.TYPE) {
prev.definitions = prev.definitions.concat(stat.definitions); prev.definitions = prev.definitions.concat(stat.definitions);
CHANGED = true; CHANGED = true;
} } else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
else if (stat instanceof AST_For defs.definitions = defs.definitions.concat(stat.definitions);
&& prev instanceof AST_Var
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
CHANGED = true; CHANGED = true;
if (stat.init) {
stat.init.definitions = prev.definitions.concat(stat.init.definitions);
} else { } else {
statements[++j] = stat;
defs = stat;
}
} else if (stat instanceof AST_For) {
if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
if (stat.init) {
prev.definitions = prev.definitions.concat(stat.init.definitions);
}
stat.init = prev; stat.init = prev;
}
statements[j] = stat; statements[j] = stat;
CHANGED = true;
} else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
defs.definitions = defs.definitions.concat(stat.init.definitions);
stat.init = null;
statements[++j] = stat;
CHANGED = true;
} else {
statements[++j] = stat;
} }
else { } else {
statements[++j] = stat; statements[++j] = stat;
} }
} }
statements.length = j + 1; statements.length = j + 1;
}; }
} }
function extract_declarations_from_unreachable_code(compressor, stat, target) { function extract_declarations_from_unreachable_code(compressor, stat, target) {

View File

@@ -1203,3 +1203,24 @@ issue_2560: {
"2", "2",
] ]
} }
hoist_decl: {
options = {
conditionals: true,
join_vars: true,
sequences: true,
}
input: {
if (x()) {
var a;
y();
} else {
z();
var b;
}
}
expect: {
var a, b;
x() ? y() : z();
}
}

View File

@@ -800,12 +800,12 @@ issue_2601_1: {
expect: { expect: {
var a = "FAIL"; var a = "FAIL";
(function() { (function() {
var b;
b = "foo", b = "foo",
function(b) { function(b) {
b && b(); b && b();
}(), }(),
b && (a = "PASS"); b && (a = "PASS");
var b;
})(), })(),
console.log(a); console.log(a);
} }

View File

@@ -796,3 +796,66 @@ cascade_assignment_in_return: {
} }
} }
} }
hoist_defun: {
options = {
join_vars: true,
sequences: true,
}
input: {
x();
function f() {}
y();
}
expect: {
function f() {}
x(), y();
}
}
hoist_decl: {
options = {
join_vars: true,
sequences: true,
}
input: {
var a;
w();
var b = x();
y();
for (var c; 0;) z();
var d;
}
expect: {
var a;
w();
var b = x(), c, d;
for (y(); 0;) z();
}
}
for_init_var: {
options = {
join_vars: true,
unused: false,
}
input: {
var a = "PASS";
(function() {
var b = 42;
for (var c = 5; c > 0;) c--;
a = "FAIL";
var a;
})();
console.log(a);
}
expect: {
var a = "PASS";
(function() {
for (var b = 42, c = 5, a; c > 0;) c--;
a = "FAIL";
})();
console.log(a);
}
expect_stdout: "PASS"
}