opportunistically turn assignment into declaration
fixes #27 fixes #315
This commit is contained in:
parent
9bf72cf758
commit
65a7d92d9c
|
|
@ -48,6 +48,7 @@ function Compressor(options, false_by_default) {
|
|||
return new Compressor(options, false_by_default);
|
||||
TreeTransformer.call(this, this.before, this.after);
|
||||
this.options = defaults(options, {
|
||||
assignments : false,
|
||||
booleans : !false_by_default,
|
||||
cascade : !false_by_default,
|
||||
collapse_vars : !false_by_default,
|
||||
|
|
@ -484,9 +485,10 @@ merge(Compressor.prototype, {
|
|||
|
||||
function is_modified(node, level, immutable) {
|
||||
var parent = tw.parent(level);
|
||||
if (is_lhs(node, parent)
|
||||
|| !immutable && parent instanceof AST_Call && parent.expression === node) {
|
||||
if (is_lhs(node, parent)) {
|
||||
return true;
|
||||
} else if (parent instanceof AST_Call && parent.expression === node) {
|
||||
return !immutable && level > 0;
|
||||
} else if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||
return !immutable && is_modified(parent, level + 1);
|
||||
}
|
||||
|
|
@ -1144,7 +1146,68 @@ merge(Compressor.prototype, {
|
|||
return true;
|
||||
}
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
function assign_to_decl(compressor, expr) {
|
||||
if (!(expr instanceof AST_Assign)) return;
|
||||
var def;
|
||||
if (expr.operator == "="
|
||||
&& expr.left instanceof AST_SymbolRef
|
||||
&& (def = expr.left.definition()).scope === expr.left.scope
|
||||
&& (!def.global || compressor.option("toplevel"))
|
||||
&& all(def.orig, function(sym) {
|
||||
return sym instanceof AST_SymbolVar;
|
||||
})) {
|
||||
def.references.splice(def.references.indexOf(expr.left), 1);
|
||||
return [ make_node(AST_Var, expr, {
|
||||
definitions: [ make_node(AST_VarDef, expr, {
|
||||
name: make_node(AST_SymbolVar, expr.left, expr.left),
|
||||
value: expr.right
|
||||
}) ]
|
||||
}) ];
|
||||
}
|
||||
var body = assign_to_decl(compressor, expr.right);
|
||||
if (body) {
|
||||
if (body.length == 1) {
|
||||
body.push(make_node(AST_SimpleStatement, expr, {
|
||||
body: make_node(AST_Assign, expr, {
|
||||
operator: expr.operator,
|
||||
left: expr.left,
|
||||
right: expr.right.left
|
||||
})
|
||||
}));
|
||||
} else {
|
||||
body[1].body = make_node(AST_Assign, expr, {
|
||||
operator: expr.operator,
|
||||
left: expr.left,
|
||||
right: body[1].body
|
||||
});
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
function transform_assignments(compressor, expr) {
|
||||
if (!compressor.option("assignments")) return;
|
||||
if (expr instanceof AST_Sequence) {
|
||||
var transformed = false;
|
||||
var list = MAP(expr.expressions, function(e) {
|
||||
var body = assign_to_decl(compressor, e);
|
||||
if (body) {
|
||||
transformed = true;
|
||||
return MAP.splice(body);
|
||||
}
|
||||
return e;
|
||||
});
|
||||
if (transformed) {
|
||||
return list.map(function(e) {
|
||||
return e instanceof AST_Statement ? e : make_node(AST_SimpleStatement, e, {
|
||||
body: e
|
||||
});
|
||||
});
|
||||
}
|
||||
} else return assign_to_decl(compressor, expr);
|
||||
}
|
||||
|
||||
function is_undefined(node, compressor) {
|
||||
return node.is_undefined
|
||||
|
|
@ -2372,8 +2435,8 @@ merge(Compressor.prototype, {
|
|||
});
|
||||
|
||||
OPT(AST_SimpleStatement, function(self, compressor){
|
||||
var body = self.body;
|
||||
if (compressor.option("side_effects")) {
|
||||
var body = self.body;
|
||||
var node = body.drop_side_effect_free(compressor, true);
|
||||
if (!node) {
|
||||
compressor.warn("Dropping side-effect-free statement [{file}:{line},{col}]", self.start);
|
||||
|
|
@ -2383,7 +2446,10 @@ merge(Compressor.prototype, {
|
|||
return make_node(AST_SimpleStatement, self, { body: node });
|
||||
}
|
||||
}
|
||||
return self;
|
||||
body = transform_assignments(compressor, self.body);
|
||||
return body ? make_node(AST_BlockStatement, self, {
|
||||
body: body
|
||||
}).optimize(compressor) : self;
|
||||
});
|
||||
|
||||
OPT(AST_DWLoop, function(self, compressor){
|
||||
|
|
@ -2486,6 +2552,17 @@ merge(Compressor.prototype, {
|
|||
}
|
||||
}
|
||||
if_break_in_loop(self, compressor);
|
||||
if (self.init && !(self.init instanceof AST_Statement)) {
|
||||
var body = transform_assignments(compressor, self.init);
|
||||
if (body) {
|
||||
var node = self.clone();
|
||||
node.init = null;
|
||||
body.push(node);
|
||||
return make_node(AST_BlockStatement, self, {
|
||||
body: body
|
||||
}).optimize(compressor);
|
||||
}
|
||||
}
|
||||
return self;
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -505,7 +505,28 @@ collapse_vars_seq: {
|
|||
expect: {
|
||||
var f1 = function(x, y) {
|
||||
var a, b, r = x + y;
|
||||
return a = r * r - r, b = 7, a + b
|
||||
return a = r * r - r, b = 7, a + b;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
collapse_vars_seq_assignments: {
|
||||
options = {
|
||||
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, assignments:true
|
||||
}
|
||||
input: {
|
||||
var f1 = function(x, y) {
|
||||
var a, b, r = x + y, q = r * r, z = q - r;
|
||||
a = z, b = 7;
|
||||
return a + b;
|
||||
};
|
||||
}
|
||||
expect: {
|
||||
var f1 = function(x, y) {
|
||||
var r = x + y, b = 7;
|
||||
return r * r - r + b;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -526,7 +547,28 @@ collapse_vars_throw: {
|
|||
expect: {
|
||||
var f1 = function(x, y) {
|
||||
var a, b, r = x + y;
|
||||
throw a = r * r - r, b = 7, a + b
|
||||
throw a = r * r - r, b = 7, a + b;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
collapse_vars_throw_assignments: {
|
||||
options = {
|
||||
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true, assignments:true
|
||||
}
|
||||
input: {
|
||||
var f1 = function(x, y) {
|
||||
var a, b, r = x + y, q = r * r, z = q - r;
|
||||
a = z, b = 7;
|
||||
throw a + b;
|
||||
};
|
||||
}
|
||||
expect: {
|
||||
var f1 = function(x,y) {
|
||||
var r = x + y, b = 7;
|
||||
throw r * r - r + b;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1677,3 +1719,45 @@ var_defs: {
|
|||
}
|
||||
expect_stdout: "97"
|
||||
}
|
||||
|
||||
assign_to_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f() {
|
||||
var a;
|
||||
a = x;
|
||||
return a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f() {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_27: {
|
||||
options = {
|
||||
assignments: true,
|
||||
collapse_vars: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function(jQuery) {
|
||||
var $;
|
||||
$ = jQuery;
|
||||
$("body").addClass("foo");
|
||||
})(jQuery);
|
||||
}
|
||||
expect: {
|
||||
(function(jQuery) {
|
||||
jQuery("body").addClass("foo");
|
||||
})(jQuery);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2327,3 +2327,58 @@ iife_assign: {
|
|||
}
|
||||
expect_stdout: "1"
|
||||
}
|
||||
|
||||
assign_to_var: {
|
||||
options = {
|
||||
assignments: true,
|
||||
join_vars: true,
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
function f(b) {
|
||||
var a;
|
||||
for (a = x; b;) return a;
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f(b) {
|
||||
for (var a = x; b;) return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
issue_315: {
|
||||
options = {
|
||||
assignments: true,
|
||||
evaluate: true,
|
||||
join_vars: true,
|
||||
keep_fargs: false,
|
||||
loops: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
console.log(function(s) {
|
||||
var w, _i, _len, _ref, _results;
|
||||
_ref = s.trim().split(" ");
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
w = _ref[_i];
|
||||
_results.push(w.toLowerCase());
|
||||
}
|
||||
return _results;
|
||||
}("test"));
|
||||
}
|
||||
expect: {
|
||||
console.log(function() {
|
||||
for (var _ref = "test".trim().split(" "), _results = [], _i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
var w = _ref[_i];
|
||||
_results.push(w.toLowerCase());
|
||||
}
|
||||
return _results;
|
||||
}());
|
||||
}
|
||||
expect_stdout: true
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user