Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2ec270b04 | ||
|
|
ed7a0a454e | ||
|
|
d819559a01 | ||
|
|
8ca49155a8 | ||
|
|
b95e3338d9 | ||
|
|
e40a0ee9c6 | ||
|
|
cb62bd98d3 | ||
|
|
f30790b11b | ||
|
|
5205dbcbf4 | ||
|
|
3ff625de7e | ||
|
|
4832bc5d88 | ||
|
|
7f342cb3e3 | ||
|
|
05e7d34ed4 |
143
lib/compress.js
143
lib/compress.js
@@ -319,6 +319,7 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
}
|
}
|
||||||
|
def.recursive_refs = 0;
|
||||||
def.references = [];
|
def.references = [];
|
||||||
def.should_replace = undefined;
|
def.should_replace = undefined;
|
||||||
def.single_use = undefined;
|
def.single_use = undefined;
|
||||||
@@ -369,7 +370,7 @@ merge(Compressor.prototype, {
|
|||||||
return compressor.option("unused")
|
return compressor.option("unused")
|
||||||
&& !def.scope.uses_eval
|
&& !def.scope.uses_eval
|
||||||
&& !def.scope.uses_with
|
&& !def.scope.uses_with
|
||||||
&& def.references.length == 1
|
&& def.references.length - def.recursive_refs == 1
|
||||||
&& tw.loop_ids[def.id] === tw.in_loop;
|
&& tw.loop_ids[def.id] === tw.in_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,7 +622,9 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else if (d.fixed) {
|
} else if (d.fixed) {
|
||||||
value = this.fixed_value();
|
value = this.fixed_value();
|
||||||
if (value && ref_once(tw, compressor, d)) {
|
if (value instanceof AST_Lambda && recursive_ref(tw, d)) {
|
||||||
|
d.recursive_refs++;
|
||||||
|
} else if (value && ref_once(tw, compressor, d)) {
|
||||||
d.single_use = value instanceof AST_Lambda
|
d.single_use = value instanceof AST_Lambda
|
||||||
|| d.scope === this.scope && value.is_constant_expression();
|
|| d.scope === this.scope && value.is_constant_expression();
|
||||||
} else {
|
} else {
|
||||||
@@ -1690,15 +1693,8 @@ merge(Compressor.prototype, {
|
|||||||
return this.operator == "void";
|
return this.operator == "void";
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor) {
|
def(AST_Binary, function(compressor) {
|
||||||
switch (this.operator) {
|
return (this.operator == "&&" || this.operator == "||")
|
||||||
case "&&":
|
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||||
return this.left._dot_throw(compressor);
|
|
||||||
case "||":
|
|
||||||
return this.left._dot_throw(compressor)
|
|
||||||
&& this.right._dot_throw(compressor);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
def(AST_Assign, function(compressor) {
|
def(AST_Assign, function(compressor) {
|
||||||
return this.operator == "="
|
return this.operator == "="
|
||||||
@@ -2645,14 +2641,14 @@ merge(Compressor.prototype, {
|
|||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node === self) return;
|
if (node === self) return;
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
|
var node_def = node.name.definition();
|
||||||
if (!drop_funcs && scope === self) {
|
if (!drop_funcs && scope === self) {
|
||||||
var node_def = node.name.definition();
|
|
||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initializations.add(node.name.name, node);
|
initializations.add(node_def.id, node);
|
||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolFunarg && scope === self) {
|
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||||
@@ -2671,7 +2667,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (def.value) {
|
if (def.value) {
|
||||||
initializations.add(def.name.name, def.value);
|
initializations.add(node_def.id, def.value);
|
||||||
if (def.value.has_side_effects(compressor)) {
|
if (def.value.has_side_effects(compressor)) {
|
||||||
def.value.walk(tw);
|
def.value.walk(tw);
|
||||||
}
|
}
|
||||||
@@ -2686,13 +2682,10 @@ merge(Compressor.prototype, {
|
|||||||
// initialization code to figure out if it uses other
|
// initialization code to figure out if it uses other
|
||||||
// symbols (that may not be in_use).
|
// symbols (that may not be in_use).
|
||||||
tw = new TreeWalker(scan_ref_scoped);
|
tw = new TreeWalker(scan_ref_scoped);
|
||||||
for (var i = 0; i < in_use.length; ++i) {
|
for (var i = 0; i < in_use.length; i++) {
|
||||||
in_use[i].orig.forEach(function(decl){
|
var init = initializations.get(in_use[i].id);
|
||||||
// undeclared globals will be instanceof AST_SymbolRef
|
if (init) init.forEach(function(init) {
|
||||||
var init = initializations.get(decl.name);
|
init.walk(tw);
|
||||||
if (init) init.forEach(function(init){
|
|
||||||
init.walk(tw);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
@@ -3685,8 +3678,9 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
||||||
fn = fn.fixed_value();
|
fn = fn.fixed_value();
|
||||||
}
|
}
|
||||||
|
var is_func = fn instanceof AST_Lambda;
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& fn instanceof AST_Function
|
&& is_func
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.uses_eval) {
|
&& !fn.uses_eval) {
|
||||||
var pos = 0, last = 0;
|
var pos = 0, last = 0;
|
||||||
@@ -3855,7 +3849,7 @@ merge(Compressor.prototype, {
|
|||||||
if (func instanceof AST_SymbolRef) {
|
if (func instanceof AST_SymbolRef) {
|
||||||
func = func.fixed_value();
|
func = func.fixed_value();
|
||||||
}
|
}
|
||||||
if (func instanceof AST_Function && !func.contains_this()) {
|
if (func instanceof AST_Lambda && !func.contains_this()) {
|
||||||
return make_sequence(this, [
|
return make_sequence(this, [
|
||||||
self.args[0],
|
self.args[0],
|
||||||
make_node(AST_Call, self, {
|
make_node(AST_Call, self, {
|
||||||
@@ -3925,7 +3919,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var stat = fn instanceof AST_Function && fn.body[0];
|
var stat = is_func && fn.body[0];
|
||||||
if (compressor.option("inline") && stat instanceof AST_Return) {
|
if (compressor.option("inline") && stat instanceof AST_Return) {
|
||||||
var value = stat.value;
|
var value = stat.value;
|
||||||
if (!value || value.is_constant_expression()) {
|
if (!value || value.is_constant_expression()) {
|
||||||
@@ -3933,7 +3927,7 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(self, args).optimize(compressor);
|
return make_sequence(self, args).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fn instanceof AST_Function) {
|
if (is_func) {
|
||||||
var def, value, scope, level = -1;
|
var def, value, scope, level = -1;
|
||||||
if (compressor.option("inline")
|
if (compressor.option("inline")
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
@@ -3981,23 +3975,30 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
|
|
||||||
function can_flatten_args(fn) {
|
function can_flatten_args(fn) {
|
||||||
var catches = Object.create(null);
|
var catches = Object.create(null), defs;
|
||||||
do {
|
do {
|
||||||
scope = compressor.parent(++level);
|
scope = compressor.parent(++level);
|
||||||
if (scope instanceof AST_SymbolRef) {
|
if (scope instanceof AST_Catch) {
|
||||||
scope = scope.fixed_value();
|
|
||||||
} else if (scope instanceof AST_Catch) {
|
|
||||||
catches[scope.argname.name] = true;
|
catches[scope.argname.name] = true;
|
||||||
|
} else if (scope instanceof AST_IterationStatement) {
|
||||||
|
defs = [];
|
||||||
|
} else if (scope instanceof AST_SymbolRef) {
|
||||||
|
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||||
}
|
}
|
||||||
} while (!(scope instanceof AST_Scope));
|
} while (!(scope instanceof AST_Scope));
|
||||||
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
||||||
return all(fn.argnames, function(arg) {
|
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||||
return arg.__unused
|
var arg = fn.argnames[i];
|
||||||
|| safe_to_inject
|
if (arg.__unused) continue;
|
||||||
&& !catches[arg.name]
|
if (!safe_to_inject
|
||||||
&& !identifier_atom(arg.name)
|
|| catches[arg.name]
|
||||||
&& !scope.var_names()[arg.name];
|
|| identifier_atom(arg.name)
|
||||||
});
|
|| scope.var_names()[arg.name]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (defs) defs.push(arg.definition());
|
||||||
|
}
|
||||||
|
return !defs || defs.length == 0 || !is_reachable(stat, defs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function flatten_args(fn) {
|
function flatten_args(fn) {
|
||||||
@@ -4670,20 +4671,18 @@ merge(Compressor.prototype, {
|
|||||||
&& is_lhs(self, compressor.parent()) !== self) {
|
&& is_lhs(self, compressor.parent()) !== self) {
|
||||||
var d = self.definition();
|
var d = self.definition();
|
||||||
var fixed = self.fixed_value();
|
var fixed = self.fixed_value();
|
||||||
if (fixed instanceof AST_Defun) {
|
var single_use = d.single_use;
|
||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
if (single_use && fixed instanceof AST_Lambda) {
|
||||||
}
|
|
||||||
if (d.single_use && fixed instanceof AST_Function) {
|
|
||||||
if (d.scope !== self.scope
|
if (d.scope !== self.scope
|
||||||
&& (!compressor.option("reduce_funcs")
|
&& (!compressor.option("reduce_funcs")
|
||||||
|| d.escaped == 1
|
|| d.escaped == 1
|
||||||
|| fixed.inlined)) {
|
|| fixed.inlined)) {
|
||||||
d.single_use = false;
|
single_use = false;
|
||||||
} else if (recursive_ref(compressor, d)) {
|
} else if (recursive_ref(compressor, d)) {
|
||||||
d.single_use = false;
|
single_use = false;
|
||||||
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
|
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
|
||||||
d.single_use = fixed.is_constant_expression(self.scope);
|
single_use = fixed.is_constant_expression(self.scope);
|
||||||
if (d.single_use == "f") {
|
if (single_use == "f") {
|
||||||
var scope = self.scope;
|
var scope = self.scope;
|
||||||
do {
|
do {
|
||||||
if (scope instanceof AST_Defun || scope instanceof AST_Function) {
|
if (scope instanceof AST_Defun || scope instanceof AST_Function) {
|
||||||
@@ -4693,9 +4692,33 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d.single_use && fixed) {
|
if (single_use && fixed) {
|
||||||
var value = fixed.optimize(compressor);
|
if (fixed instanceof AST_Defun) {
|
||||||
return value === fixed ? fixed.clone(true) : value;
|
fixed = make_node(AST_Function, fixed, fixed);
|
||||||
|
}
|
||||||
|
var value;
|
||||||
|
if (d.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
|
||||||
|
value = fixed.clone(true);
|
||||||
|
var defun_def = value.name.definition();
|
||||||
|
var lambda_def = value.variables.get(value.name.name);
|
||||||
|
var name = lambda_def && lambda_def.orig[0];
|
||||||
|
if (!(name instanceof AST_SymbolLambda)) {
|
||||||
|
name = make_node(AST_SymbolLambda, value.name, value.name);
|
||||||
|
name.scope = value;
|
||||||
|
value.name = name;
|
||||||
|
lambda_def = value.def_function(name);
|
||||||
|
}
|
||||||
|
value.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
|
||||||
|
node.thedef = lambda_def;
|
||||||
|
lambda_def.references.push(node);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
value = fixed.optimize(compressor);
|
||||||
|
if (value === fixed) value = fixed.clone(true);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
if (fixed && d.should_replace === undefined) {
|
if (fixed && d.should_replace === undefined) {
|
||||||
var init;
|
var init;
|
||||||
@@ -4815,18 +4838,42 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function is_reachable(self, defs) {
|
||||||
|
var reachable = false;
|
||||||
|
var find_ref = new TreeWalker(function(node) {
|
||||||
|
if (reachable) return true;
|
||||||
|
if (node instanceof AST_SymbolRef && member(node.definition(), defs)) {
|
||||||
|
return reachable = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var scan_scope = new TreeWalker(function(node) {
|
||||||
|
if (reachable) return true;
|
||||||
|
if (node instanceof AST_Scope && node !== self) {
|
||||||
|
var parent = scan_scope.parent();
|
||||||
|
if (!(parent instanceof AST_Call && parent.expression === node)) {
|
||||||
|
node.walk(find_ref);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.walk(scan_scope);
|
||||||
|
return reachable;
|
||||||
|
}
|
||||||
|
|
||||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||||
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
||||||
OPT(AST_Assign, function(self, compressor){
|
OPT(AST_Assign, function(self, compressor){
|
||||||
|
var def;
|
||||||
if (compressor.option("dead_code")
|
if (compressor.option("dead_code")
|
||||||
&& self.left instanceof AST_SymbolRef
|
&& self.left instanceof AST_SymbolRef
|
||||||
&& self.left.definition().scope === compressor.find_parent(AST_Lambda)) {
|
&& (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) {
|
||||||
var level = 0, node, parent = self;
|
var level = 0, node, parent = self;
|
||||||
do {
|
do {
|
||||||
node = parent;
|
node = parent;
|
||||||
parent = compressor.parent(level++);
|
parent = compressor.parent(level++);
|
||||||
if (parent instanceof AST_Exit) {
|
if (parent instanceof AST_Exit) {
|
||||||
if (in_try(level, parent instanceof AST_Throw)) break;
|
if (in_try(level, parent instanceof AST_Throw)) break;
|
||||||
|
if (is_reachable(def.scope, [ def ])) break;
|
||||||
if (self.operator == "=") return self.right;
|
if (self.operator == "=") return self.right;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: self.operator.slice(0, -1),
|
operator: self.operator.slice(0, -1),
|
||||||
|
|||||||
@@ -671,9 +671,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PARENS(AST_Node, function(){
|
PARENS(AST_Node, return_false);
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// a function expression needs parens around it when it's provably
|
// a function expression needs parens around it when it's provably
|
||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
@@ -699,9 +697,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
PARENS(AST_Object, function(output){
|
PARENS(AST_Object, first_in_statement);
|
||||||
return first_in_statement(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output){
|
PARENS(AST_Unary, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
|
|||||||
@@ -307,7 +307,9 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
||||||
this.functions.set(symbol.name, this.def_variable(symbol));
|
var def = this.def_variable(symbol);
|
||||||
|
this.functions.set(symbol.name, def);
|
||||||
|
return def;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
AST_Scope.DEFMETHOD("def_variable", function(symbol){
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.3.2",
|
"version": "3.3.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3878,10 +3878,9 @@ recursive_function_replacement: {
|
|||||||
console.log(f(c));
|
console.log(f(c));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(n) {
|
console.log(function n(o) {
|
||||||
return x(y(f(n)));
|
return x(y(n(o)));
|
||||||
}
|
}(c));
|
||||||
console.log(f(c));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -828,3 +828,56 @@ issue_2597: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2666: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a = {
|
||||||
|
p: function() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
console.log(typeof f().p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = {
|
||||||
|
p: function() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
console.log(typeof f().p());
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2692: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
reduce_vars: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a = g;
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = g;
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1413,3 +1413,112 @@ issue_2516_2: {
|
|||||||
Baz(2);
|
Baz(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defun_lambda_same_name: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}
|
||||||
|
console.log(function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}(5));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}(5));
|
||||||
|
}
|
||||||
|
expect_stdout: "120"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2660_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 2;
|
||||||
|
function f(b) {
|
||||||
|
return b && f() || a--;
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 2;
|
||||||
|
(function f(b) {
|
||||||
|
return b && f() || a--;
|
||||||
|
})(1);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2660_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f(b) {
|
||||||
|
b && f();
|
||||||
|
--a, a.toString();
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
(function f(b) {
|
||||||
|
b && f(),
|
||||||
|
(--a).toString();
|
||||||
|
})(),
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2665: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 2,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function g() {
|
||||||
|
a-- && g();
|
||||||
|
}
|
||||||
|
typeof h == "function" && h();
|
||||||
|
function h() {
|
||||||
|
typeof g == "function" && g();
|
||||||
|
}
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
!function g() {
|
||||||
|
a-- && g();
|
||||||
|
}();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "-1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1345,11 +1345,10 @@ issue_2630_3: {
|
|||||||
expect: {
|
expect: {
|
||||||
var x = 2, a = 1;
|
var x = 2, a = 1;
|
||||||
(function() {
|
(function() {
|
||||||
function f1(a) {
|
(function f1(a) {
|
||||||
f2();
|
f2();
|
||||||
--x >= 0 && f1({});
|
--x >= 0 && f1({});
|
||||||
}
|
})(a++);
|
||||||
f1(a++);
|
|
||||||
function f2() {
|
function f2() {
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
@@ -1424,7 +1423,7 @@ issue_2630_5: {
|
|||||||
expect_stdout: "155"
|
expect_stdout: "155"
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_inline: {
|
recursive_inline_1: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
@@ -1447,3 +1446,203 @@ recursive_inline: {
|
|||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recursive_inline_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}
|
||||||
|
console.log(f(5));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}(5));
|
||||||
|
}
|
||||||
|
expect_stdout: "120"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2657: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function f() {
|
||||||
|
return h;
|
||||||
|
function g(b) {
|
||||||
|
return b || b();
|
||||||
|
}
|
||||||
|
function h(a) {
|
||||||
|
g(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}()(42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return b = a, b || b(), a;
|
||||||
|
var b;
|
||||||
|
}(42));
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2663_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var i, o = {};
|
||||||
|
function createFn(j) {
|
||||||
|
return function() {
|
||||||
|
console.log(j);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
o[i] = createFn(i);
|
||||||
|
for (i in o)
|
||||||
|
o[i]();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
var i, o = {};
|
||||||
|
function createFn(j) {
|
||||||
|
return function() {
|
||||||
|
console.log(j);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
o[i] = createFn(i);
|
||||||
|
for (i in o)
|
||||||
|
o[i]();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2663_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var i;
|
||||||
|
function fn(j) {
|
||||||
|
return function() {
|
||||||
|
console.log(j);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
fn(i);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
var i;
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
j = i, console.log(j);
|
||||||
|
var j;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2663_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function () {
|
||||||
|
var outputs = [
|
||||||
|
{ type: 0, target: null, eventName: "ngSubmit", propName: null },
|
||||||
|
{ type: 0, target: null, eventName: "submit", propName: null },
|
||||||
|
{ type: 0, target: null, eventName: "reset", propName: null },
|
||||||
|
];
|
||||||
|
function listenToElementOutputs(outputs) {
|
||||||
|
var handlers = [];
|
||||||
|
for (var i = 0; i < outputs.length; i++) {
|
||||||
|
var output = outputs[i];
|
||||||
|
var handleEventClosure = renderEventHandlerClosure(output.eventName);
|
||||||
|
handlers.push(handleEventClosure)
|
||||||
|
}
|
||||||
|
var target, name;
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
function renderEventHandlerClosure(eventName) {
|
||||||
|
return function () {
|
||||||
|
return console.log(eventName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
listenToElementOutputs(outputs).forEach(function (handler) {
|
||||||
|
return handler()
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
function renderEventHandlerClosure(eventName) {
|
||||||
|
return function() {
|
||||||
|
return console.log(eventName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(function(outputs) {
|
||||||
|
var handlers = [];
|
||||||
|
for (var i = 0; i < outputs.length; i++) {
|
||||||
|
var output = outputs[i];
|
||||||
|
var handleEventClosure = renderEventHandlerClosure(output.eventName);
|
||||||
|
handlers.push(handleEventClosure);
|
||||||
|
}
|
||||||
|
return handlers;
|
||||||
|
})([ {
|
||||||
|
type: 0,
|
||||||
|
target: null,
|
||||||
|
eventName: "ngSubmit",
|
||||||
|
propName: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
target: null,
|
||||||
|
eventName: "submit",
|
||||||
|
propName: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
target: null,
|
||||||
|
eventName: "reset",
|
||||||
|
propName: null
|
||||||
|
} ]).forEach(function(handler) {
|
||||||
|
return handler();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"ngSubmit",
|
||||||
|
"submit",
|
||||||
|
"reset",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -611,3 +611,35 @@ issue_2313_6: {
|
|||||||
x();
|
x();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2678: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1, c = "FAIL";
|
||||||
|
(function f() {
|
||||||
|
(a-- && f()).p;
|
||||||
|
return {
|
||||||
|
get p() {
|
||||||
|
c = "PASS";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1, c = "FAIL";
|
||||||
|
(function f() {
|
||||||
|
(a-- && f()).p;
|
||||||
|
return {
|
||||||
|
get p() {
|
||||||
|
c = "PASS";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1355,10 +1355,9 @@ defun_inline_1: {
|
|||||||
function f() {
|
function f() {
|
||||||
return function(b) {
|
return function(b) {
|
||||||
return b;
|
return b;
|
||||||
}(2) + h();
|
}(2) + function h() {
|
||||||
function h() {
|
|
||||||
return h();
|
return h();
|
||||||
}
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1382,12 +1381,11 @@ defun_inline_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
function h() {
|
|
||||||
return h();
|
|
||||||
}
|
|
||||||
return function(b) {
|
return function(b) {
|
||||||
return b;
|
return b;
|
||||||
}(2) + h();
|
}(2) + function h() {
|
||||||
|
return h();
|
||||||
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -329,7 +329,8 @@ function createTopLevelCode() {
|
|||||||
rng(2) == 0
|
rng(2) == 0
|
||||||
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
||||||
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
||||||
'console.log(null, a, b, c);' // preceding `null` makes for a cleaner output (empty string still shows up etc)
|
// preceding `null` makes for a cleaner output (empty string still shows up etc)
|
||||||
|
'console.log(null, a, b, c, Infinity, NaN, undefined);'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,6 +636,8 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
|
case p++:
|
||||||
|
return getVarName() + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
|
|||||||
Reference in New Issue
Block a user