function collapse(statements, compressor) {
if (scope.pinned()) return statements;
var args;
+ var assignments = Object.create(null);
var candidates = [];
+ var declare_only = Object.create(null);
+ var force_single;
var stat_index = statements.length;
var scanner = new TreeTransformer(function(node, descend) {
if (abort) return node;
// Skip (non-executed) functions and (leading) default case in switch statements
if (node instanceof AST_Default || node instanceof AST_Scope) return node;
}, patch_sequence);
- var force_single;
while (--stat_index >= 0) {
// Treat parameters as collapsible in IIFE, i.e.
// function(a, b){ ... }(x());
if (stat_index == 0 && compressor.option("unused")) extract_args();
// Find collapsible assignments
var hit_stack = [];
- var declare_only = Object.create(null);
extract_candidates(statements[stat_index]);
while (candidates.length > 0) {
hit_stack = candidates.pop();
candidates.push(hit_stack.slice());
extract_candidates(expr.left);
extract_candidates(expr.right);
+ if (expr.left instanceof AST_SymbolRef) {
+ assignments[expr.left.name] = (assignments[expr.left.name] || 0) + 1;
+ }
} else if (expr instanceof AST_Binary) {
extract_candidates(expr.left);
extract_candidates(expr.right);
if (expr instanceof AST_VarDef) {
var def = expr.name.definition();
if (!member(expr.name, def.orig)) return;
- var referenced = def.references.length - def.replaced;
- var declared = def.orig.length - def.eliminated;
- declared -= declare_only[def.name] || 0;
+ var declared = def.orig.length - def.eliminated - (declare_only[def.name] || 0);
+ var referenced = def.references.length - def.replaced - (assignments[def.name] || 0);
if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg)) {
mangleable_var(expr.value);
return make_node(AST_SymbolRef, expr.name, expr.name);
}
- if (referenced > 1 ? mangleable_var(expr.value) : !compressor.exposed(def)) {
+ if (mangleable_var(expr.value) || referenced == 1 && !compressor.exposed(def)) {
return make_node(AST_SymbolRef, expr.name, expr.name);
}
} else if (expr instanceof AST_Assign) {
found = true;
if (node instanceof AST_VarDef) {
node.value = null;
+ declare_only[node.name.name] = (declare_only[node.name.name] || 0) + 1;
if (value_def) value_def.replaced++;
return node;
}
expect: {
function log(x) { return console.log(x), x; }
function f0(c) {
- var a = 3 / c;
- return a = a;
+ return 3 / c;
}
function f1(c) {
return 1 - 3 / c;
}
expect: {
var f1 = function(x, y) {
- var r = x + y, a = r * r - r, b = 7;
- console.log(a + b);
+ var r = x + y, z = r * r - r, b = 7;
+ console.log(z + b);
};
f1("1", 0);
}
a();
}
expect: {
- var a;
- (a = (a = x) && y)();
+ var a = x;
+ (a = a && y)();
}
}
}
expect_stdout: "PASS"
}
+
+mangleable_var: {
+ options = {
+ collapse_vars: true,
+ unused: true,
+ }
+ input: {
+ function f(a) {
+ var b = a(), c = a(), d = b;
+ return c.p(c, d);
+ }
+ console.log(f(function() {
+ return {
+ p: function() {
+ return "PASS"
+ },
+ };
+ }));
+ }
+ expect: {
+ function f(a) {
+ var b = a(), c = a();
+ return c.p(c, b);
+ }
+ console.log(f(function() {
+ return {
+ p: function() {
+ return "PASS";
+ }
+ };
+ }));
+ }
+ expect_stdout: "PASS"
+}