join object assignments (#2763)

This commit is contained in:
Alex Lam S.L
2018-01-11 17:08:21 +08:00
committed by GitHub
parent 6a0af85c8b
commit f1e1bb419a
2 changed files with 109 additions and 1 deletions

View File

@@ -869,6 +869,7 @@ merge(Compressor.prototype, {
} }
function tighten_body(statements, compressor) { function tighten_body(statements, compressor) {
var scope = compressor.find_parent(AST_Scope);
var CHANGED, max_iter = 10; var CHANGED, max_iter = 10;
do { do {
CHANGED = false; CHANGED = false;
@@ -900,7 +901,6 @@ merge(Compressor.prototype, {
// Will not attempt to collapse assignments into or past code blocks // Will not attempt to collapse assignments into or past code blocks
// which are not sequentially executed, e.g. loops and conditionals. // which are not sequentially executed, e.g. loops and conditionals.
function collapse(statements, compressor) { function collapse(statements, compressor) {
var scope = compressor.find_parent(AST_Scope);
if (scope.uses_eval || scope.uses_with) return statements; if (scope.uses_eval || scope.uses_with) return statements;
var args; var args;
var candidates = []; var candidates = [];
@@ -1696,6 +1696,41 @@ merge(Compressor.prototype, {
statements.length = n; statements.length = n;
} }
function join_object_assignments(defn, body) {
if (!(defn instanceof AST_Definitions)) return;
var exprs;
if (body instanceof AST_Assign) {
exprs = [ body ];
} else if (body instanceof AST_Sequence) {
exprs = body.expressions.slice();
}
if (!exprs) return;
do {
var node = exprs[0];
if (!(node instanceof AST_Assign)) break;
if (!(node.left instanceof AST_PropAccess)) break;
var sym = node.left.expression;
if (!(sym instanceof AST_SymbolRef)) break;
var def = find_if(function(def) {
return def.name.name == sym.name
&& def.value instanceof AST_Object;
}, defn.definitions);
if (!def) break;
if (!node.right.is_constant_expression(scope)) break;
var prop = node.left.property;
if (prop instanceof AST_Node) {
prop = prop.evaluate(compressor);
}
if (prop instanceof AST_Node) break;
def.value.properties.push(make_node(AST_ObjectKeyVal, node, {
key: prop,
value: node.right
}));
exprs.shift();
} while (exprs.length);
return exprs;
}
function join_consecutive_vars(statements, compressor) { function join_consecutive_vars(statements, compressor) {
var defs; 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++) {
@@ -1728,6 +1763,17 @@ merge(Compressor.prototype, {
} else { } else {
statements[++j] = stat; statements[++j] = stat;
} }
} else if (stat instanceof AST_SimpleStatement) {
var exprs = join_object_assignments(prev, stat.body);
if (exprs) {
if (exprs.length > 0) {
stat.body = make_sequence(stat.body, exprs);
statements[++j] = stat;
}
CHANGED = true;
} else {
statements[++j] = stat;
}
} else { } else {
statements[++j] = stat; statements[++j] = stat;
} }

View File

@@ -1100,3 +1100,65 @@ const_prop_assign_pure: {
x(); x();
} }
} }
join_object_assignments_1: {
options = {
evaluate: true,
join_vars: true,
}
input: {
console.log(function() {
var x = {
a: 1,
c: (console.log("c"), "C"),
};
x.b = 2;
x[3] = function() {
console.log(x);
},
x["a"] = /foo/,
x.bar = x;
return x;
}());
}
expect: {
console.log(function() {
var x = {
a: 1,
c: (console.log("c"), "C"),
b: 2,
3: function() {
console.log(x);
},
a: /foo/,
};
x.bar = x;
return x;
}());
}
expect_stdout: true
}
join_object_assignments_2: {
options = {
evaluate: true,
hoist_props: true,
join_vars: true,
passes: 3,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var o = {
foo: 1,
};
o.bar = 2;
o.baz = 3;
console.log(o.foo, o.bar + o.bar, o.foo * o.bar * o.baz);
}
expect: {
console.log(1, 4, 6);
}
expect_stdout: "1 4 6"
}