[Pkg-javascript-commits] [uglifyjs] 100/190: Collapse single use var definitions
Antonio Terceiro
terceiro at moszumanska.debian.org
Sun Aug 7 23:17:17 UTC 2016
This is an automated email from the git hooks/post-receive script.
terceiro pushed a commit to annotated tag upstream/2.7.0
in repository uglifyjs.
commit f4c2ea37bf9231b6f76804e74ee157be916280de
Author: kzc <zaxxon2011 at gmail.com>
Date: Wed Jan 27 02:17:06 2016 -0500
Collapse single use var definitions
Fix #721
---
lib/compress.js | 146 ++++++
lib/transform.js | 2 +-
test/compress/collapse_vars.js | 1047 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 1194 insertions(+), 1 deletion(-)
diff --git a/lib/compress.js b/lib/compress.js
index 1f5988f..814e9a8 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -66,6 +66,7 @@ function Compressor(options, false_by_default) {
hoist_vars : false,
if_return : !false_by_default,
join_vars : !false_by_default,
+ collapse_vars : false,
cascade : !false_by_default,
side_effects : !false_by_default,
pure_getters : false,
@@ -218,6 +219,9 @@ merge(Compressor.prototype, {
if (compressor.option("join_vars")) {
statements = join_consecutive_vars(statements, compressor);
}
+ if (compressor.option("collapse_vars")) {
+ statements = collapse_single_use_vars(statements, compressor);
+ }
} while (CHANGED && max_iter-- > 0);
if (compressor.option("negate_iife")) {
@@ -226,6 +230,148 @@ merge(Compressor.prototype, {
return statements;
+ function collapse_single_use_vars(statements, compressor) {
+ // Iterate statements backwards looking for a statement with a var/const
+ // declaration immediately preceding it. Grab the rightmost var definition
+ // and if it has exactly one reference then attempt to replace its reference
+ // in the statement with the var value and then erase the var definition.
+
+ var self = compressor.self();
+ var var_defs_removed = false;
+ for (var stat_index = statements.length; --stat_index >= 0;) {
+ var stat = statements[stat_index];
+ if (stat instanceof AST_Definitions) continue;
+
+ // Process child blocks of statement if present.
+ [stat, stat.body, stat.alternative, stat.bcatch, stat.bfinally].forEach(function(node) {
+ node && node.body && collapse_single_use_vars(node.body, compressor);
+ });
+
+ // The variable definition must precede a statement.
+ if (stat_index <= 0) break;
+ var prev_stat_index = stat_index - 1;
+ var prev_stat = statements[prev_stat_index];
+ if (!(prev_stat instanceof AST_Definitions)) continue;
+ var var_defs = prev_stat.definitions;
+ if (var_defs == null) continue;
+
+ // Scan variable definitions from right to left.
+ var side_effects_encountered = false;
+ var lvalues_encountered = false;
+ var lvalues = {};
+ for (var var_defs_index = var_defs.length; --var_defs_index >= 0;) {
+ var var_decl = var_defs[var_defs_index];
+ if (var_decl.value == null) continue;
+
+ // Only interested in cases with just one reference to the variable.
+ var var_name = var_decl.name.name;
+ var def = self.find_variable && self.find_variable(var_name);
+ if (!def || !def.references || def.references.length !== 1 || var_name == "arguments") {
+ side_effects_encountered = true;
+ continue;
+ }
+ var ref = def.references[0];
+
+ // Don't replace ref if eval() or with statement in scope.
+ if (ref.scope.uses_eval || ref.scope.uses_with) break;
+
+ // Constant single use vars can be replaced in any scope.
+ if (var_decl.value.is_constant(compressor)) {
+ var ctt = new TreeTransformer(function(node) {
+ if (node === ref)
+ return replace_var(node, ctt.parent(), true);
+ });
+ stat.transform(ctt);
+ continue;
+ }
+
+ // Restrict var replacement to constants if side effects encountered.
+ if (side_effects_encountered |= lvalues_encountered) continue;
+
+ // Non-constant single use vars can only be replaced in same scope.
+ if (ref.scope !== self) {
+ side_effects_encountered |= var_decl.value.has_side_effects(compressor);
+ continue;
+ }
+
+ // Detect lvalues in var value.
+ var tw = new TreeWalker(function(node){
+ if (node instanceof AST_SymbolRef && is_lvalue(node, tw.parent())) {
+ lvalues[node.name] = lvalues_encountered = true;
+ }
+ });
+ var_decl.value.walk(tw);
+
+ // Replace the non-constant single use var in statement if side effect free.
+ var unwind = false;
+ var tt = new TreeTransformer(
+ function preorder(node) {
+ if (unwind) return node;
+ var parent = tt.parent();
+ if (node instanceof AST_Lambda
+ || node instanceof AST_Try
+ || node instanceof AST_With
+ || node instanceof AST_IterationStatement
+ || (parent instanceof AST_Switch && node !== parent.expression)) {
+ return unwind = true, node;
+ }
+ },
+ function postorder(node) {
+ if (unwind) return node;
+ if (node === ref)
+ return unwind = true, replace_var(node, tt.parent(), false);
+ if (side_effects_encountered |= node.has_side_effects(compressor))
+ return unwind = true, node;
+ if (lvalues_encountered && node instanceof AST_SymbolRef && node.name in lvalues) {
+ side_effects_encountered = true;
+ return unwind = true, node;
+ }
+ }
+ );
+ stat.transform(tt);
+ }
+ }
+
+ // Remove extraneous empty statments in block after removing var definitions.
+ // Leave at least one statement in `statements`.
+ if (var_defs_removed) for (var i = statements.length; --i >= 0;) {
+ if (statements.length > 1 && statements[i] instanceof AST_EmptyStatement)
+ statements.splice(i, 1);
+ }
+
+ return statements;
+
+ function is_lvalue(node, parent) {
+ return node instanceof AST_SymbolRef && (
+ (parent instanceof AST_Assign && node === parent.left)
+ || (parent instanceof AST_Unary && parent.expression === node
+ && (parent.operator == "++" || parent.operator == "--")));
+ }
+ function replace_var(node, parent, is_constant) {
+ if (is_lvalue(node, parent)) return node;
+
+ // Remove var definition and return its value to the TreeTransformer to replace.
+ var value = var_decl.value;
+ var_decl.value = null;
+
+ var_defs.splice(var_defs_index, 1);
+ if (var_defs.length === 0) {
+ statements[prev_stat_index] = make_node(AST_EmptyStatement, self);
+ var_defs_removed = true;
+ }
+ // Further optimize statement after substitution.
+ stat.walk(new TreeWalker(function(node){
+ delete node._squeezed;
+ delete node._optimized;
+ }));
+
+ compressor.warn("Replacing " + (is_constant ? "constant" : "variable") +
+ " " + var_name + " [{file}:{line},{col}]", node.start);
+ CHANGED = true;
+ return value;
+ }
+ }
+
function process_for_angular(statements) {
function has_inject(comment) {
return /@ngInject/.test(comment.value);
diff --git a/lib/transform.js b/lib/transform.js
index 62e6e02..3018e8f 100644
--- a/lib/transform.js
+++ b/lib/transform.js
@@ -64,7 +64,7 @@ TreeTransformer.prototype = new TreeWalker;
x = this;
descend(x, tw);
} else {
- tw.stack[tw.stack.length - 1] = x = this.clone();
+ tw.stack[tw.stack.length - 1] = x = this;
descend(x, tw);
y = tw.after(x, in_list);
if (y !== undefined) x = y;
diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js
new file mode 100644
index 0000000..e023597
--- /dev/null
+++ b/test/compress/collapse_vars.js
@@ -0,0 +1,1047 @@
+collapse_vars_side_effects_1: {
+ 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
+ }
+ input: {
+ function f1() {
+ var e = 7;
+ var s = "abcdef";
+ var i = 2;
+ var log = console.log.bind(console);
+ var x = s.charAt(i++);
+ var y = s.charAt(i++);
+ var z = s.charAt(i++);
+ log(x, y, z, e);
+ }
+ function f2() {
+ var e = 7;
+ var log = console.log.bind(console);
+ var s = "abcdef";
+ var i = 2;
+ var x = s.charAt(i++);
+ var y = s.charAt(i++);
+ var z = s.charAt(i++);
+ log(x, i, y, z, e);
+ }
+ function f3() {
+ var e = 7;
+ var s = "abcdef";
+ var i = 2;
+ var log = console.log.bind(console);
+ var x = s.charAt(i++);
+ var y = s.charAt(i++);
+ var z = s.charAt(i++);
+ log(x, z, y, e);
+ }
+ function f4() {
+ var log = console.log.bind(console),
+ i = 10,
+ x = i += 2,
+ y = i += 3,
+ z = i += 4;
+ log(x, z, y, i);
+ }
+ }
+ expect: {
+ function f1() {
+ var s = "abcdef", i = 2;
+ console.log.bind(console)(s.charAt(i++), s.charAt(i++), s.charAt(i++), 7);
+ }
+ function f2() {
+ var log = console.log.bind(console),
+ s = "abcdef",
+ i = 2,
+ x = s.charAt(i++),
+ y = s.charAt(i++),
+ z = s.charAt(i++);
+ log(x, i, y, z, 7);
+ }
+ function f3() {
+ var s = "abcdef",
+ i = 2,
+ log = console.log.bind(console),
+ x = s.charAt(i++),
+ y = s.charAt(i++);
+ log(x, s.charAt(i++), y, 7);
+ }
+ function f4() {
+ var log = console.log.bind(console),
+ i = 10,
+ x = i += 2,
+ y = i += 3;
+ log(x, i += 4, y, i);
+ }
+ }
+}
+
+collapse_vars_side_effects_2: {
+ 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
+ }
+ input: {
+ function fn(x) { return console.log(x), x; }
+
+ function p1() { var a = foo(), b = bar(), c = baz(); return a + b + c; }
+ function p2() { var a = foo(), c = bar(), b = baz(); return a + b + c; }
+ function p3() { var b = foo(), a = bar(), c = baz(); return a + b + c; }
+ function p4() { var b = foo(), c = bar(), a = baz(); return a + b + c; }
+ function p5() { var c = foo(), a = bar(), b = baz(); return a + b + c; }
+ function p6() { var c = foo(), b = bar(), a = baz(); return a + b + c; }
+
+ function q1() { var a = foo(), b = bar(), c = baz(); return fn(a + b + c); }
+ function q2() { var a = foo(), c = bar(), b = baz(); return fn(a + b + c); }
+ function q3() { var b = foo(), a = bar(), c = baz(); return fn(a + b + c); }
+ function q4() { var b = foo(), c = bar(), a = baz(); return fn(a + b + c); }
+ function q5() { var c = foo(), a = bar(), b = baz(); return fn(a + b + c); }
+ function q6() { var c = foo(), b = bar(), a = baz(); return fn(a + b + c); }
+
+ function r1() { var a = foo(), b = bar(), c = baz(); return fn(a) + fn(b) + fn(c); }
+ function r2() { var a = foo(), c = bar(), b = baz(); return fn(a) + fn(b) + fn(c); }
+ function r3() { var b = foo(), a = bar(), c = baz(); return fn(a) + fn(b) + fn(c); }
+ function r4() { var b = foo(), c = bar(), a = baz(); return fn(a) + fn(b) + fn(c); }
+ function r5() { var c = foo(), a = bar(), b = baz(); return fn(a) + fn(b) + fn(c); }
+ function r6() { var c = foo(), b = bar(), a = baz(); return fn(a) + fn(b) + fn(c); }
+
+ function s1() { var a = foo(), b = bar(), c = baz(); return g(a + b + c); }
+ function s6() { var c = foo(), b = bar(), a = baz(); return g(a + b + c); }
+
+ function t1() { var a = foo(), b = bar(), c = baz(); return g(a) + g(b) + g(c); }
+ function t6() { var c = foo(), b = bar(), a = baz(); return g(a) + g(b) + g(c); }
+ }
+ expect: {
+ function fn(x) { return console.log(x), x; }
+
+ function p1() { return foo() + bar() + baz(); }
+ function p2() { var a = foo(), c = bar(); return a + baz() + c; }
+ function p3() { var b = foo(); return bar() + b + baz(); }
+ function p4() { var b = foo(), c = bar(); return baz() + b + c; }
+ function p5() { var c = foo(); return bar() + baz() + c; }
+ function p6() { var c = foo(), b = bar(); return baz() + b + c; }
+
+ function q1() { return fn(foo() + bar() + baz()); }
+ function q2() { var a = foo(), c = bar(); return fn(a + baz() + c); }
+ function q3() { var b = foo(); return fn(bar() + b + baz()); }
+ function q4() { var b = foo(), c = bar(); return fn(baz() + b + c); }
+ function q5() { var c = foo(); return fn(bar() + baz() + c); }
+ function q6() { var c = foo(), b = bar(); return fn(baz() + b + c); }
+
+ function r1() { var a = foo(), b = bar(), c = baz(); return fn(a) + fn(b) + fn(c); }
+ function r2() { var a = foo(), c = bar(), b = baz(); return fn(a) + fn(b) + fn(c); }
+ function r3() { var b = foo(), a = bar(), c = baz(); return fn(a) + fn(b) + fn(c); }
+ function r4() { var b = foo(), c = bar(); return fn(baz()) + fn(b) + fn(c); }
+ function r5() { var c = foo(), a = bar(), b = baz(); return fn(a) + fn(b) + fn(c); }
+ function r6() { var c = foo(), b = bar(); return fn(baz()) + fn(b) + fn(c); }
+
+ function s1() { var a = foo(), b = bar(), c = baz(); return g(a + b + c); }
+ function s6() { var c = foo(), b = bar(), a = baz(); return g(a + b + c); }
+
+ function t1() { var a = foo(), b = bar(), c = baz(); return g(a) + g(b) + g(c); }
+ function t6() { var c = foo(), b = bar(), a = baz(); return g(a) + g(b) + g(c); }
+ }
+}
+
+collapse_vars_issue_721: {
+ 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
+ }
+ input: {
+ define(["require", "exports", 'handlebars'], function (require, exports, hb) {
+ var win = window;
+ var _hb = win.Handlebars = hb;
+ return _hb;
+ });
+ def(function (hb) {
+ var win = window;
+ var prop = 'Handlebars';
+ var _hb = win[prop] = hb;
+ return _hb;
+ });
+ def(function (hb) {
+ var prop = 'Handlebars';
+ var win = window;
+ var _hb = win[prop] = hb;
+ return _hb;
+ });
+ def(function (hb) {
+ var prop = 'Handlebars';
+ var win = g();
+ var _hb = win[prop] = hb;
+ return _hb;
+ });
+ def(function (hb) {
+ var prop = g1();
+ var win = g2();
+ var _hb = win[prop] = hb;
+ return _hb;
+ });
+ def(function (hb) {
+ var win = g2();
+ var prop = g1();
+ var _hb = win[prop] = hb;
+ return _hb;
+ });
+ }
+ expect: {
+ define([ "require", "exports", "handlebars" ], function(require, exports, hb) {
+ return window.Handlebars = hb;
+ }),
+ def(function(hb) {
+ return window.Handlebars = hb;
+ }),
+ def(function(hb) {
+ return window.Handlebars = hb;
+ }),
+ def(function (hb) {
+ return g().Handlebars = hb;
+ }),
+ def(function (hb) {
+ var prop = g1();
+ return g2()[prop] = hb;
+ }),
+ def(function (hb) {
+ return g2()[g1()] = hb;
+ });
+ }
+}
+
+collapse_vars_properties: {
+ 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
+ }
+ input: {
+ function f1(obj) {
+ var prop = 'LiteralProperty';
+ return !!-+obj[prop];
+ }
+ function f2(obj) {
+ var prop1 = 'One';
+ var prop2 = 'Two';
+ return ~!!-+obj[prop1 + prop2];
+ }
+ }
+ expect: {
+ function f1(obj) {
+ return !!-+obj.LiteralProperty;
+ }
+ function f2(obj) {
+ return ~!!-+obj.OneTwo;
+ }
+ }
+}
+
+collapse_vars_if: {
+ 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
+ }
+ input: {
+ function f1() {
+ var not_used = sideeffect(), x = g1 + g2;
+ var y = x / 4, z = 'Bar' + y;
+ if ('x' != z) { return g9; }
+ else return g5;
+ }
+ function f2() {
+ var x = g1 + g2, not_used = sideeffect();
+ var y = x / 4
+ var z = 'Bar' + y;
+ if ('x' != z) { return g9; }
+ else return g5;
+ }
+ function f3(x) {
+ if (x) {
+ var a = 1;
+ return a;
+ }
+ else {
+ var b = 2;
+ return b;
+ }
+ }
+ }
+ expect: {
+ function f1() {
+ sideeffect();
+ return "x" != "Bar" + (g1 + g2) / 4 ? g9 : g5;
+ }
+ function f2() {
+ var x = g1 + g2;
+ sideeffect();
+ return "x" != "Bar" + x / 4 ? g9 : g5;
+ }
+ function f3(x) {
+ if (x) {
+ return 1;
+ }
+ return 2;
+ }
+ }
+}
+
+collapse_vars_while: {
+ options = {
+ collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
+ comparisons:true, evaluate:true, booleans:true, loops:false, unused:true, hoist_funs:true,
+ keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
+ }
+ input: {
+ function f1(y) {
+ // Neither the non-constant while condition `c` will be
+ // replaced, nor the non-constant `x` in the body.
+ var x = y, c = 3 - y;
+ while (c) { return x; }
+ var z = y * y;
+ return z;
+ }
+ function f2(y) {
+ // The constant `x` will be replaced in the while body.
+ var x = 7;
+ while (y) { return x; }
+ var z = y * y;
+ return z;
+ }
+ function f3(y) {
+ // The non-constant `n` will not be replaced in the while body.
+ var n = 5 - y;
+ while (y) { return n; }
+ var z = y * y;
+ return z;
+ }
+ }
+ expect: {
+ function f1(y) {
+ var x = y, c = 3 - y;
+ while (c) return x;
+ return y * y;
+ }
+ function f2(y) {
+ while (y) return 7;
+ return y * y
+ }
+ function f3(y) {
+ var n = 5 - y;
+ while (y) return n;
+ return y * y;
+ }
+ }
+}
+
+collapse_vars_do_while: {
+ options = {
+ collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
+ comparisons:true, evaluate:true, booleans:false, loops:false, unused:true, hoist_funs:true,
+ keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
+ }
+ input: {
+ function f1(y) {
+ // The constant do-while condition `c` will be replaced.
+ var c = 9;
+ do { } while (c === 77);
+ }
+ function f2(y) {
+ // The non-constant do-while condition `c` will not be replaced.
+ var c = 5 - y;
+ do { } while (c);
+ }
+ function f3(y) {
+ // The constant `x` will be replaced in the do loop body.
+ function fn(n) { console.log(n); }
+ var a = 2, x = 7;
+ do {
+ fn(a = x);
+ break;
+ } while (y);
+ }
+ function f4(y) {
+ // The non-constant `a` will not be replaced in the do loop body.
+ var a = y / 4;
+ do {
+ return a;
+ } while (y);
+ }
+ function f5(y) {
+ function p(x) { console.log(x); }
+ do {
+ // The non-constant `a` will be replaced in p(a)
+ // because it is declared in same block.
+ var a = y - 3;
+ p(a);
+ } while (--y);
+ }
+ }
+ expect: {
+ function f1(y) {
+ do ; while (false);
+ }
+ function f2(y) {
+ var c = 5 - y;
+ do ; while (c);
+ }
+ function f3(y) {
+ function fn(n) { console.log(n); }
+ var a = 2;
+ do {
+ fn(a = 7);
+ break;
+ } while (y);
+ }
+ function f4(y) {
+ var a = y / 4;
+ do
+ return a;
+ while (y);
+ }
+ function f5(y) {
+ function p(x) { console.log(x); }
+ do {
+ p(y - 3);
+ } while (--y);
+ }
+ }
+}
+
+collapse_vars_seq: {
+ 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
+ }
+ 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 a, b, r = x + y;
+ return a = r * r - r, b = 7, a + b
+ };
+ }
+}
+
+collapse_vars_throw: {
+ 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
+ }
+ 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 a, b, r = x + y;
+ throw a = r * r - r, b = 7, a + b
+ };
+ }
+}
+
+collapse_vars_switch: {
+ 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
+ }
+ input: {
+ function f1() {
+ var not_used = sideeffect(), x = g1 + g2;
+ var y = x / 4, z = 'Bar' + y;
+ switch (z) { case 0: return g9; }
+ }
+ function f2() {
+ var x = g1 + g2, not_used = sideeffect();
+ var y = x / 4
+ var z = 'Bar' + y;
+ switch (z) { case 0: return g9; }
+ }
+ function f3(x) {
+ switch(x) { case 1: var a = 3 - x; return a; }
+ }
+ }
+ expect: {
+ function f1() {
+ sideeffect();
+ switch ("Bar" + (g1 + g2) / 4) { case 0: return g9 }
+ }
+ function f2() {
+ var x = g1 + g2;
+ sideeffect();
+ switch ("Bar" + x / 4) { case 0: return g9 }
+ }
+ function f3(x) {
+ // verify no extraneous semicolon in case block before return
+ // when the var definition was eliminated
+ switch(x) { case 1: return 3 - x; }
+ }
+ }
+}
+
+collapse_vars_assignment: {
+ 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
+ }
+ input: {
+ function log(x) { return console.log(x), x; }
+ function f0(c) {
+ var a = 3 / c;
+ return a = a;
+ }
+ function f1(c) {
+ const a = 3 / c;
+ const b = 1 - a;
+ return b;
+ }
+ function f2(c) {
+ var a = 3 / c;
+ var b = a - 7;
+ return log(c = b);
+ }
+ function f3(c) {
+ var a = 3 / c;
+ var b = a - 7;
+ return log(c |= b);
+ }
+ function f4(c) {
+ var a = 3 / c;
+ var b = 2;
+ return log(b += a);
+ }
+ function f5(c) {
+ var b = 2;
+ var a = 3 / c;
+ return log(b += a);
+ }
+ function f6(c) {
+ var b = g();
+ var a = 3 / c;
+ return log(b += a);
+ }
+ }
+ expect: {
+ function log(x) { return console.log(x), x; }
+ function f0(c) {
+ var a = 3 / c;
+ return a = a;
+ }
+ function f1(c) {
+ return 1 - 3 / c
+ }
+ function f2(c) {
+ return log(c = 3 / c - 7);
+ }
+ function f3(c) {
+ return log(c |= 3 / c - 7);
+ }
+ function f4(c) {
+ var b = 2;
+ return log(b += 3 / c);
+ }
+ function f5(c) {
+ var b = 2;
+ return log(b += 3 / c);
+ }
+ function f6(c) {
+ var b = g();
+ return log(b += 3 / c);
+ }
+ }
+}
+
+collapse_vars_lvalues: {
+ 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
+ }
+ input: {
+ function f0(x) { var i = ++x; return x += i; }
+ function f1(x) { var a = (x -= 3); return x += a; }
+ function f2(x) { var z = x, a = ++z; return z += a; }
+ function f3(x) { var a = (x -= 3), b = x + a; return b; }
+ function f4(x) { var a = (x -= 3); return x + a; }
+ function f5(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return b - c; }
+ function f6(x) { var w = e1(), v = e2(), c = v = --x, b = w = x; return c - b; }
+ function f7(x) { var w = e1(), v = e2(), c = v - x, b = w = x; return b - c; }
+ function f8(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return b - c; }
+ function f9(x) { var w = e1(), v = e2(), b = w = x, c = v - x; return c - b; }
+ }
+ expect: {
+ function f0(x) { var i = ++x; return x += i; }
+ function f1(x) { var a = (x -= 3); return x += a; }
+ function f2(x) { var z = x, a = ++z; return z += a; }
+ function f3(x) { var a = (x -= 3); return x + a; }
+ function f4(x) { var a = (x -= 3); return x + a; }
+ function f5(x) { var w = e1(), v = e2(), c = v = --x; return (w = x) - c; }
+ function f6(x) { var w = e1(), v = e2(); return (v = --x) - (w = x); }
+ function f7(x) { var w = e1(), v = e2(), c = v - x; return (w = x) - c; }
+ function f8(x) { var w = e1(), v = e2(); return (w = x) - (v - x); }
+ function f9(x) { var w = e1(); return e2() - x - (w = x); }
+
+ }
+}
+
+collapse_vars_misc1: {
+ 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
+ }
+ input: {
+ function f0(o, a, h) {
+ var b = 3 - a;
+ var obj = o;
+ var seven = 7;
+ var prop = 'run';
+ var t = obj[prop](b)[seven] = h;
+ return t;
+ }
+ function f1(x) { var y = 5 - x; return y; }
+ function f2(x) { const z = foo(), y = z / (5 - x); return y; }
+ function f3(x) { var z = foo(), y = (5 - x) / z; return y; }
+ function f4(x) { var z = foo(), y = (5 - u) / z; return y; }
+ function f5(x) { const z = foo(), y = (5 - window.x) / z; return y; }
+ function f6() { var b = window.a * window.z; return b && zap(); }
+ function f7() { var b = window.a * window.z; return b + b; }
+ function f8() { var b = window.a * window.z; var c = b + 5; return b + c; }
+ function f9() { var b = window.a * window.z; return bar() || b; }
+ function f10(x) { var a = 5, b = 3; return a += b; }
+ function f11(x) { var a = 5, b = 3; return a += --b; }
+ }
+ expect: {
+ function f0(o, a, h) {
+ var b = 3 - a;
+ return o.run(b)[7] = h;
+ }
+ function f1(x) { return 5 - x }
+ function f2(x) { return foo() / (5 - x) }
+ function f3(x) { return (5 - x) / foo() }
+ function f4(x) { var z = foo(); return (5 - u) / z }
+ function f5(x) { const z = foo(); return (5 - window.x) / z }
+ function f6() { return window.a * window.z && zap() }
+ function f7() { var b = window.a * window.z; return b + b }
+ function f8() { var b = window.a * window.z; return b + (b + 5) }
+ function f9() { var b = window.a * window.z; return bar() || b }
+ function f10(x) { var a = 5; return a += 3; }
+ function f11(x) { var a = 5, b = 3; return a += --b; }
+ }
+}
+
+collapse_vars_self_reference: {
+ options = {
+ collapse_vars:true, unused:false,
+ sequences:true, properties:true, dead_code:true, conditionals:true,
+ comparisons:true, evaluate:true, booleans:true, loops:true, hoist_funs:true,
+ keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
+ }
+ input: {
+ // avoid bug in self-referential declaration.
+ function f1() {
+ var self = {
+ inner: function() { return self; }
+ };
+ }
+ function f2() {
+ var self = { inner: self };
+ }
+ }
+ expect: {
+ // note: `unused` option is false
+ function f1() {
+ var self = {
+ inner: function() { return self }
+ };
+ }
+ function f2() {
+ var self = { inner: self };
+ }
+ }
+}
+
+collapse_vars_repeated: {
+ 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
+ }
+ input: {
+ function f1() {
+ var dummy = 3, a = 5, unused = 2, a = 1, a = 3;
+ return -a;
+ }
+ function f2() {
+ var a = 3, a = a + 2;
+ return a;
+ }
+ }
+ expect: {
+ function f1() {
+ return -3
+ }
+ function f2() {
+ var a = 3, a = a + 2;
+ return a
+ }
+ }
+}
+
+collapse_vars_closures: {
+ 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
+ }
+ input: {
+ function constant_vars_can_be_replaced_in_any_scope() {
+ var outer = 3;
+ return function() { return outer; }
+ }
+ function non_constant_vars_can_only_be_replace_in_same_scope(x) {
+ var outer = x;
+ return function() { return outer; }
+ }
+ }
+ expect: {
+ function constant_vars_can_be_replaced_in_any_scope() {
+ return function() { return 3 }
+ }
+ function non_constant_vars_can_only_be_replace_in_same_scope(x) {
+ var outer = x
+ return function() { return outer }
+ }
+ }
+}
+
+collapse_vars_unary: {
+ 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
+ }
+ input: {
+ function f0(o, p) {
+ var x = o[p];
+ delete x;
+ }
+ function f1(n) {
+ var k = !!n;
+ return n > +k;
+ }
+ function f2(n) {
+ // test unary with constant
+ var k = 7;
+ return k--;
+ }
+ function f3(n) {
+ // test unary with constant
+ var k = 7;
+ return ++k;
+ }
+ function f4(n) {
+ // test unary with non-constant
+ var k = 8 - n;
+ return k--;
+ }
+ function f5(n) {
+ // test unary with non-constant
+ var k = 9 - n;
+ return ++k;
+ }
+ }
+ expect: {
+ function f0(o, p) {
+ delete o[p];
+ }
+ function f1(n) {
+ return n > +!!n
+ }
+ function f2(n) {
+ var k = 7;
+ return k--
+ }
+ function f3(n) {
+ var k = 7;
+ return ++k
+ }
+ function f4(n) {
+ var k = 8 - n;
+ return k--;
+ }
+ function f5(n) {
+ var k = 9 - n;
+ return ++k;
+ }
+ }
+}
+
+collapse_vars_try: {
+ 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
+ }
+ input: {
+ function f1() {
+ try {
+ var a = 1;
+ return a;
+ }
+ catch (ex) {
+ var b = 2;
+ return b;
+ }
+ finally {
+ var c = 3;
+ return c;
+ }
+ }
+ function f2() {
+ var t = could_throw(); // shouldn't be replaced in try block
+ try {
+ return t + might_throw();
+ }
+ catch (ex) {
+ return 3;
+ }
+ }
+ }
+ expect: {
+ function f1() {
+ try {
+ return 1;
+ }
+ catch (ex) {
+ return 2;
+ }
+ finally {
+ return 3;
+ }
+ }
+ function f2() {
+ var t = could_throw();
+ try {
+ return t + might_throw();
+ }
+ catch (ex) {
+ return 3;
+ }
+ }
+ }
+}
+
+collapse_vars_array: {
+ 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
+ }
+ input: {
+ function f1(x, y) {
+ var z = x + y;
+ return [z];
+ }
+ function f2(x, y) {
+ var z = x + y;
+ return [x, side_effect(), z];
+ }
+ function f3(x, y) {
+ var z = f(x + y);
+ return [ [3], [z, x, y], [g()] ];
+ }
+ }
+ expect: {
+ function f1(x, y) {
+ return [x + y]
+ }
+ function f2(x, y) {
+ var z = x + y
+ return [x, side_effect(), z]
+ }
+ function f3(x, y) {
+ return [ [3], [f(x + y), x, y], [g()] ]
+ }
+ }
+}
+
+collapse_vars_object: {
+ 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
+ }
+ input: {
+ function f0(x, y) {
+ var z = x + y;
+ return {
+ get b() { return 7; },
+ r: z
+ };
+ }
+ function f1(x, y) {
+ var z = x + y;
+ return {
+ r: z,
+ get b() { return 7; }
+ };
+ }
+ function f2(x, y) {
+ var z = x + y;
+ var k = x - y;
+ return {
+ q: k,
+ r: g(x),
+ s: z
+ };
+ }
+ function f3(x, y) {
+ var z = f(x + y);
+ return [{
+ a: {q: x, r: y, s: z},
+ b: g()
+ }];
+ }
+ }
+ expect: {
+ function f0(x, y) {
+ var z = x + y;
+ return {
+ get b() { return 7; },
+ r: z
+ };
+ }
+ function f1(x, y) {
+ return {
+ r: x + y,
+ get b() { return 7; }
+ };
+ }
+ function f2(x, y) {
+ var z = x + y;
+ return {
+ q: x - y,
+ r: g(x),
+ s: z
+ };
+ }
+ function f3(x, y) {
+ return [{
+ a: {q: x, r: y, s: f(x + y)},
+ b: g()
+ }];
+ }
+ }
+}
+
+collapse_vars_eval_and_with: {
+ options = {
+ collapse_vars:true, sequences:false, 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
+ }
+ input: {
+ // Don't attempt to collapse vars in presence of eval() or with statement.
+ (function f0() {
+ var a = 2;
+ console.log(a - 5);
+ eval("console.log(a);");
+ })();
+ (function f1() {
+ var o = {a: 1}, a = 2;
+ with (o) console.log(a);
+ })();
+ (function f2() {
+ var o = {a: 1}, a = 2;
+ return function() { with (o) console.log(a) };
+ })()();
+ }
+ expect: {
+ (function f0() {
+ var a = 2;
+ console.log(a - 5);
+ eval("console.log(a);");
+ })();
+ (function f1() {
+ var o = {a: 1}, a = 2;
+ with(o) console.log(a);
+ })();
+ (function f2() {
+ var o = {a: 1}, a = 2;
+ return function() { with (o) console.log(a) };
+ })()();
+ }
+}
+
+collapse_vars_constants: {
+ 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
+ }
+ input: {
+ function f1(x) {
+ var a = 4, b = x.prop, c = 5, d = sideeffect1(), e = sideeffect2();
+ return b + (function() { return d - a * e - c; })();
+ }
+ function f2(x) {
+ var a = 4, b = x.prop, c = 5, not_used = sideeffect1(), e = sideeffect2();
+ return b + (function() { return -a * e - c; })();
+ }
+ function f3(x) {
+ var a = 4, b = x.prop, c = 5, not_used = sideeffect1();
+ return b + (function() { return -a - c; })();
+ }
+ }
+ expect: {
+ function f1(x) {
+ var b = x.prop, d = sideeffect1(), e = sideeffect2();
+ return b + (function() { return d - 4 * e - 5; })();
+ }
+ function f2(x) {
+ var b = x.prop, e = (sideeffect1(), sideeffect2());
+ return b + (function() { return -4 * e - 5; })();
+ }
+ function f3(x) {
+ var b = x.prop;
+ sideeffect1();
+ return b + (function() { return -9; })();
+ }
+ }
+}
+
+collapse_vars_arguments: {
+ 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
+ }
+ input: {
+ var outer = function() {
+ // Do not replace `arguments` but do replace the constant `k` before it.
+ var k = 7, arguments = 5, inner = function() { console.log(arguments); }
+ inner(k, 1);
+ }
+ outer();
+ }
+ expect: {
+ (function() {
+ (function(){console.log(arguments);})(7, 1);
+ })();
+ }
+}
+
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git
More information about the Pkg-javascript-commits
mailing list