support const (#4190)
This commit is contained in:
107
lib/ast.js
107
lib/ast.js
@@ -203,6 +203,10 @@ var AST_Directive = DEFNODE("Directive", "value quote", {
|
|||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
||||||
|
$documentation: "The empty statement (empty block or simply a semicolon)"
|
||||||
|
}, AST_Statement);
|
||||||
|
|
||||||
function must_be_expression(node, prop) {
|
function must_be_expression(node, prop) {
|
||||||
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
||||||
if (node[prop] instanceof AST_Statement && !(node[prop] instanceof AST_Function)) {
|
if (node[prop] instanceof AST_Statement && !(node[prop] instanceof AST_Function)) {
|
||||||
@@ -226,6 +230,34 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
|||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", {
|
||||||
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
|
$propdoc: {
|
||||||
|
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
||||||
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
|
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
||||||
|
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||||
|
},
|
||||||
|
clone: function(deep) {
|
||||||
|
var node = this._clone(deep);
|
||||||
|
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
||||||
|
if (this.functions) node.functions = this.functions.clone();
|
||||||
|
if (this.variables) node.variables = this.variables.clone();
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
pinned: function() {
|
||||||
|
return this.resolve().pinned();
|
||||||
|
},
|
||||||
|
resolve: function() {
|
||||||
|
return this.parent_scope.resolve();
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.parent_scope == null) return;
|
||||||
|
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
|
||||||
|
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
|
||||||
|
},
|
||||||
|
}, AST_Statement);
|
||||||
|
|
||||||
function walk_body(node, visitor) {
|
function walk_body(node, visitor) {
|
||||||
node.body.forEach(function(node) {
|
node.body.forEach(function(node) {
|
||||||
node.walk(visitor);
|
node.walk(visitor);
|
||||||
@@ -249,44 +281,11 @@ var AST_Block = DEFNODE("Block", "body", {
|
|||||||
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
|
if (node instanceof AST_Function) throw new Error("body cannot contain AST_Function");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
var AST_BlockScope = DEFNODE("BlockScope", "cname enclosed functions make_def parent_scope variables", {
|
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
|
||||||
$propdoc: {
|
|
||||||
cname: "[integer/S] current index for mangling variables (used internally by the mangler)",
|
|
||||||
enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes",
|
|
||||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
|
||||||
parent_scope: "[AST_Scope?/S] link to the parent scope",
|
|
||||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
|
||||||
},
|
|
||||||
clone: function(deep) {
|
|
||||||
var node = this._clone(deep);
|
|
||||||
if (this.enclosed) node.enclosed = this.enclosed.slice();
|
|
||||||
if (this.functions) node.functions = this.functions.clone();
|
|
||||||
if (this.variables) node.variables = this.variables.clone();
|
|
||||||
return node;
|
|
||||||
},
|
|
||||||
pinned: function() {
|
|
||||||
return this.resolve().pinned();
|
|
||||||
},
|
|
||||||
resolve: function() {
|
|
||||||
return this.parent_scope.resolve();
|
|
||||||
},
|
|
||||||
_validate: function() {
|
|
||||||
if (this.parent_scope == null) return;
|
|
||||||
if (!(this.parent_scope instanceof AST_BlockScope)) throw new Error("parent_scope must be AST_BlockScope");
|
|
||||||
if (!(this.resolve() instanceof AST_Scope)) throw new Error("must be contained within AST_Scope");
|
|
||||||
},
|
|
||||||
}, AST_Block);
|
|
||||||
|
|
||||||
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
|
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
|
||||||
$documentation: "A block statement",
|
$documentation: "A block statement",
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
|
||||||
$documentation: "The empty statement (empty block or simply a semicolon)"
|
|
||||||
}, AST_Statement);
|
|
||||||
|
|
||||||
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
||||||
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
|
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
|
||||||
@@ -297,7 +296,7 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
|
|||||||
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
if (!(this.body instanceof AST_Statement)) throw new Error("body must be AST_Statement");
|
||||||
if (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
|
if (this.body instanceof AST_Function) throw new Error("body cannot be AST_Function");
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_BlockScope);
|
||||||
|
|
||||||
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
||||||
$documentation: "Statement with a label",
|
$documentation: "Statement with a label",
|
||||||
@@ -451,7 +450,7 @@ var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", {
|
|||||||
return this.uses_eval || this.uses_with;
|
return this.uses_eval || this.uses_with;
|
||||||
},
|
},
|
||||||
resolve: return_this,
|
resolve: return_this,
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
||||||
$documentation: "The toplevel scope",
|
$documentation: "The toplevel scope",
|
||||||
@@ -699,7 +698,7 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
if (!(this.bfinally instanceof AST_Finally)) throw new Error("bfinally must be AST_Finally");
|
if (!(this.bfinally instanceof AST_Finally)) throw new Error("bfinally must be AST_Finally");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
@@ -718,11 +717,11 @@ var AST_Catch = DEFNODE("Catch", "argname", {
|
|||||||
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
if (!(this.argname instanceof AST_SymbolCatch)) throw new Error("argname must be AST_SymbolCatch");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
var AST_Finally = DEFNODE("Finally", null, {
|
var AST_Finally = DEFNODE("Finally", null, {
|
||||||
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
|
||||||
}, AST_BlockScope);
|
}, AST_Block);
|
||||||
|
|
||||||
/* -----[ VAR ]----- */
|
/* -----[ VAR ]----- */
|
||||||
|
|
||||||
@@ -738,14 +737,30 @@ var AST_Definitions = DEFNODE("Definitions", "definitions", {
|
|||||||
defn.walk(visitor);
|
defn.walk(visitor);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
_validate: function() {
|
||||||
|
if (this.definitions.length < 1) throw new Error("must have at least one definition");
|
||||||
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
|
var AST_Const = DEFNODE("Const", null, {
|
||||||
|
$documentation: "A `const` statement",
|
||||||
|
_validate: function() {
|
||||||
|
this.definitions.forEach(function(node) {
|
||||||
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
|
if (!(node.name instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||||
|
must_be_expression(node, "value");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, AST_Definitions);
|
||||||
|
|
||||||
var AST_Var = DEFNODE("Var", null, {
|
var AST_Var = DEFNODE("Var", null, {
|
||||||
$documentation: "A `var` statement",
|
$documentation: "A `var` statement",
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
this.definitions.forEach(function(node) {
|
this.definitions.forEach(function(node) {
|
||||||
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
if (!(node instanceof AST_VarDef)) throw new Error("definitions must be AST_VarDef[]");
|
||||||
|
if (!(node.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||||
|
if (node.value != null) must_be_expression(node, "value");
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -763,10 +778,6 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
|||||||
if (node.value) node.value.walk(visitor);
|
if (node.value) node.value.walk(visitor);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
|
||||||
if (!(this.name instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
|
||||||
if (this.value != null) must_be_expression(this, "value");
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ OTHER ]----- */
|
/* -----[ OTHER ]----- */
|
||||||
@@ -1032,12 +1043,12 @@ var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
|
|||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
|
||||||
|
$documentation: "Base class for all symbols",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[string] name of this symbol",
|
name: "[string] name of this symbol",
|
||||||
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
|
||||||
thedef: "[SymbolDef/S] the definition of this symbol"
|
thedef: "[SymbolDef/S] the definition of this symbol"
|
||||||
},
|
},
|
||||||
$documentation: "Base class for all symbols",
|
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
if (typeof this.name != "string") throw new Error("name must be string");
|
if (typeof this.name != "string") throw new Error("name must be string");
|
||||||
},
|
},
|
||||||
@@ -1051,6 +1062,10 @@ var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
|
|||||||
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
$documentation: "A declaration symbol (symbol in var, function name or argument, symbol in catch)",
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
|
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
||||||
|
$documentation: "Symbol defining a constant",
|
||||||
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
||||||
$documentation: "Symbol defining a variable",
|
$documentation: "Symbol defining a variable",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|||||||
298
lib/compress.js
298
lib/compress.js
@@ -370,7 +370,8 @@ merge(Compressor.prototype, {
|
|||||||
def.cross_loop = false;
|
def.cross_loop = false;
|
||||||
def.direct_access = false;
|
def.direct_access = false;
|
||||||
def.escaped = [];
|
def.escaped = [];
|
||||||
def.fixed = !def.scope.pinned()
|
def.fixed = !def.const_redefs
|
||||||
|
&& !def.scope.pinned()
|
||||||
&& !compressor.exposed(def)
|
&& !compressor.exposed(def)
|
||||||
&& !(def.init instanceof AST_Function && def.init !== def.scope)
|
&& !(def.init instanceof AST_Function && def.init !== def.scope)
|
||||||
&& def.init;
|
&& def.init;
|
||||||
@@ -481,8 +482,10 @@ merge(Compressor.prototype, {
|
|||||||
return def.fixed instanceof AST_Defun;
|
return def.fixed instanceof AST_Defun;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safe_to_assign(tw, def) {
|
function safe_to_assign(tw, def, declare) {
|
||||||
if (def.fixed === undefined) return true;
|
if (def.fixed === undefined) return declare || all(def.orig, function(sym) {
|
||||||
|
return !(sym instanceof AST_SymbolConst);
|
||||||
|
});
|
||||||
if (def.fixed === null && def.safe_ids) {
|
if (def.fixed === null && def.safe_ids) {
|
||||||
def.safe_ids[def.id] = false;
|
def.safe_ids[def.id] = false;
|
||||||
delete def.safe_ids;
|
delete def.safe_ids;
|
||||||
@@ -654,6 +657,11 @@ merge(Compressor.prototype, {
|
|||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
def(AST_BlockScope, function(tw, descend, compressor) {
|
||||||
|
this.variables.each(function(def) {
|
||||||
|
reset_def(tw, compressor, def);
|
||||||
|
});
|
||||||
|
});
|
||||||
def(AST_Call, function(tw, descend) {
|
def(AST_Call, function(tw, descend) {
|
||||||
tw.find_parent(AST_Scope).may_call_this();
|
tw.find_parent(AST_Scope).may_call_this();
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
@@ -717,7 +725,10 @@ merge(Compressor.prototype, {
|
|||||||
tw.in_loop = saved_loop;
|
tw.in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_For, function(tw) {
|
def(AST_For, function(tw, descend, compressor) {
|
||||||
|
this.variables.each(function(def) {
|
||||||
|
reset_def(tw, compressor, def);
|
||||||
|
});
|
||||||
if (this.init) this.init.walk(tw);
|
if (this.init) this.init.walk(tw);
|
||||||
var saved_loop = tw.in_loop;
|
var saved_loop = tw.in_loop;
|
||||||
tw.in_loop = this;
|
tw.in_loop = this;
|
||||||
@@ -735,7 +746,10 @@ merge(Compressor.prototype, {
|
|||||||
tw.in_loop = saved_loop;
|
tw.in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_ForIn, function(tw) {
|
def(AST_ForIn, function(tw, descend, compressor) {
|
||||||
|
this.variables.each(function(def) {
|
||||||
|
reset_def(tw, compressor, def);
|
||||||
|
});
|
||||||
this.object.walk(tw);
|
this.object.walk(tw);
|
||||||
var saved_loop = tw.in_loop;
|
var saved_loop = tw.in_loop;
|
||||||
tw.in_loop = this;
|
tw.in_loop = this;
|
||||||
@@ -816,7 +830,10 @@ merge(Compressor.prototype, {
|
|||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Switch, function(tw) {
|
def(AST_Switch, function(tw, descend, compressor) {
|
||||||
|
this.variables.each(function(def) {
|
||||||
|
reset_def(tw, compressor, def);
|
||||||
|
});
|
||||||
this.expression.walk(tw);
|
this.expression.walk(tw);
|
||||||
var first = true;
|
var first = true;
|
||||||
this.body.forEach(function(branch) {
|
this.body.forEach(function(branch) {
|
||||||
@@ -900,7 +917,10 @@ merge(Compressor.prototype, {
|
|||||||
walk_defuns(tw, this);
|
walk_defuns(tw, this);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
def(AST_Try, function(tw) {
|
def(AST_Try, function(tw, descend, compressor) {
|
||||||
|
this.variables.each(function(def) {
|
||||||
|
reset_def(tw, compressor, def);
|
||||||
|
});
|
||||||
push(tw);
|
push(tw);
|
||||||
walk_body(this, tw);
|
walk_body(this, tw);
|
||||||
pop(tw);
|
pop(tw);
|
||||||
@@ -963,7 +983,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!node.value) return;
|
if (!node.value) return;
|
||||||
descend();
|
descend();
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (safe_to_assign(tw, d)) {
|
if (safe_to_assign(tw, d, true)) {
|
||||||
mark(tw, d);
|
mark(tw, d);
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
@@ -1667,8 +1687,6 @@ merge(Compressor.prototype, {
|
|||||||
extract_candidates(expr.condition);
|
extract_candidates(expr.condition);
|
||||||
extract_candidates(expr.consequent);
|
extract_candidates(expr.consequent);
|
||||||
extract_candidates(expr.alternative);
|
extract_candidates(expr.alternative);
|
||||||
} else if (expr instanceof AST_Definitions) {
|
|
||||||
expr.definitions.forEach(extract_candidates);
|
|
||||||
} else if (expr instanceof AST_Dot) {
|
} else if (expr instanceof AST_Dot) {
|
||||||
extract_candidates(expr.expression);
|
extract_candidates(expr.expression);
|
||||||
} else if (expr instanceof AST_DWLoop) {
|
} else if (expr instanceof AST_DWLoop) {
|
||||||
@@ -1722,6 +1740,8 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
extract_candidates(expr.expression);
|
extract_candidates(expr.expression);
|
||||||
}
|
}
|
||||||
|
} else if (expr instanceof AST_Var) {
|
||||||
|
expr.definitions.forEach(extract_candidates);
|
||||||
} else if (expr instanceof AST_VarDef) {
|
} else if (expr instanceof AST_VarDef) {
|
||||||
if (expr.value) {
|
if (expr.value) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
@@ -1895,6 +1915,7 @@ merge(Compressor.prototype, {
|
|||||||
function get_lhs(expr) {
|
function get_lhs(expr) {
|
||||||
if (expr instanceof AST_VarDef) {
|
if (expr instanceof AST_VarDef) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
|
if (def.const_redefs) return;
|
||||||
if (!member(expr.name, def.orig)) return;
|
if (!member(expr.name, def.orig)) return;
|
||||||
var declared = def.orig.length - def.eliminated - (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);
|
var referenced = def.references.length - def.replaced - (assignments[def.name] || 0);
|
||||||
@@ -2139,12 +2160,16 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0; i < statements.length;) {
|
for (var i = 0; i < statements.length;) {
|
||||||
var stat = statements[i];
|
var stat = statements[i];
|
||||||
if (stat instanceof AST_BlockStatement) {
|
if (stat instanceof AST_BlockStatement) {
|
||||||
|
if (all(stat.body, function(stat) {
|
||||||
|
return !(stat instanceof AST_Const);
|
||||||
|
})) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
eliminate_spurious_blocks(stat.body);
|
eliminate_spurious_blocks(stat.body);
|
||||||
[].splice.apply(statements, [i, 1].concat(stat.body));
|
[].splice.apply(statements, [i, 1].concat(stat.body));
|
||||||
i += stat.body.length;
|
i += stat.body.length;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (stat instanceof AST_Directive) {
|
if (stat instanceof AST_Directive) {
|
||||||
if (member(stat.value, seen_dirs)) {
|
if (member(stat.value, seen_dirs)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
@@ -2379,12 +2404,15 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function as_statement_array_with_return(node, ab) {
|
function as_statement_array_with_return(node, ab) {
|
||||||
var body = as_statement_array(node).slice(0, -1);
|
var body = as_statement_array(node);
|
||||||
if (ab.value) {
|
var block = body, last;
|
||||||
body.push(make_node(AST_SimpleStatement, ab.value, {
|
while ((last = block[block.length - 1]) !== ab) {
|
||||||
|
block = last.body;
|
||||||
|
}
|
||||||
|
block.pop();
|
||||||
|
if (ab.value) body.push(make_node(AST_SimpleStatement, ab.value, {
|
||||||
body: ab.value.expression
|
body: ab.value.expression
|
||||||
}));
|
}));
|
||||||
}
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2430,7 +2458,7 @@ merge(Compressor.prototype, {
|
|||||||
statements.length = n;
|
statements.length = n;
|
||||||
CHANGED = n != len;
|
CHANGED = n != len;
|
||||||
if (has_quit) has_quit.forEach(function(stat) {
|
if (has_quit) has_quit.forEach(function(stat) {
|
||||||
extract_declarations_from_unreachable_code(stat, statements);
|
extract_declarations_from_unreachable_code(compressor, stat, statements);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2574,7 +2602,7 @@ merge(Compressor.prototype, {
|
|||||||
if (merge_conditional_assignments(def, exprs, keep)) trimmed = true;
|
if (merge_conditional_assignments(def, exprs, keep)) trimmed = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (join_var_assign(defn.definitions, exprs, keep)) trimmed = true;
|
if (defn instanceof AST_Var && join_var_assign(defn.definitions, exprs, keep)) trimmed = true;
|
||||||
}
|
}
|
||||||
return trimmed && exprs;
|
return trimmed && exprs;
|
||||||
}
|
}
|
||||||
@@ -2668,7 +2696,7 @@ merge(Compressor.prototype, {
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
} else {
|
} else {
|
||||||
statements[++j] = stat;
|
statements[++j] = stat;
|
||||||
defs = stat;
|
if (stat instanceof AST_Var) defs = stat;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
} else if (stat instanceof AST_Exit) {
|
} else if (stat instanceof AST_Exit) {
|
||||||
@@ -2690,7 +2718,7 @@ merge(Compressor.prototype, {
|
|||||||
defs.definitions = defs.definitions.concat(stat.init.definitions);
|
defs.definitions = defs.definitions.concat(stat.init.definitions);
|
||||||
stat.init = null;
|
stat.init = null;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
} else if (stat.init instanceof AST_Definitions) {
|
} else if (stat.init instanceof AST_Var) {
|
||||||
defs = stat.init;
|
defs = stat.init;
|
||||||
}
|
}
|
||||||
} else if (stat instanceof AST_ForIn) {
|
} else if (stat instanceof AST_ForIn) {
|
||||||
@@ -2750,25 +2778,46 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
if (!(stat instanceof AST_Defun)) {
|
if (!(stat instanceof AST_Defun)) {
|
||||||
AST_Node.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
AST_Node.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
||||||
}
|
}
|
||||||
stat.walk(new TreeWalker(function(node) {
|
var block;
|
||||||
|
stat.walk(new TreeWalker(function(node, descend) {
|
||||||
if (node instanceof AST_Definitions) {
|
if (node instanceof AST_Definitions) {
|
||||||
AST_Node.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
AST_Node.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
||||||
node.remove_initializers();
|
node.remove_initializers(compressor);
|
||||||
target.push(node);
|
push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
target.push(node);
|
push(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) return true;
|
||||||
|
if (node instanceof AST_BlockScope) {
|
||||||
|
var save = block;
|
||||||
|
block = [];
|
||||||
|
descend();
|
||||||
|
if (block.required) {
|
||||||
|
target.push(make_node(AST_BlockStatement, stat, {
|
||||||
|
body: block
|
||||||
|
}));
|
||||||
|
} else if (block.length) {
|
||||||
|
[].push.apply(target, block);
|
||||||
|
}
|
||||||
|
block = save;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
function push(node) {
|
||||||
|
if (block) {
|
||||||
|
block.push(node);
|
||||||
|
if (node instanceof AST_Const) block.required = true;
|
||||||
|
} else {
|
||||||
|
target.push(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_undefined(node, compressor) {
|
function is_undefined(node, compressor) {
|
||||||
@@ -4038,7 +4087,9 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_SymbolDeclaration, return_false);
|
def(AST_SymbolDeclaration, return_false);
|
||||||
def(AST_SymbolRef, function(compressor) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
return !this.is_declared(compressor);
|
return !(this.is_declared(compressor) && all(this.definition().orig, function(sym) {
|
||||||
|
return !(sym instanceof AST_SymbolConst);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
def(AST_This, return_false);
|
def(AST_This, return_false);
|
||||||
def(AST_Try, function(compressor) {
|
def(AST_Try, function(compressor) {
|
||||||
@@ -4285,12 +4336,15 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
function trim_block(stat) {
|
function trim_block(node) {
|
||||||
switch (stat.body.length) {
|
switch (node.body.length) {
|
||||||
case 1: return stat.body[0];
|
case 0:
|
||||||
case 0: return make_node(AST_EmptyStatement, stat);
|
return make_node(AST_EmptyStatement, node);
|
||||||
|
case 1:
|
||||||
|
var stat = node.body[0];
|
||||||
|
if (!(stat instanceof AST_Const)) return stat;
|
||||||
}
|
}
|
||||||
return stat;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
OPT(AST_BlockStatement, function(self, compressor) {
|
OPT(AST_BlockStatement, function(self, compressor) {
|
||||||
@@ -4386,6 +4440,16 @@ merge(Compressor.prototype, {
|
|||||||
pop();
|
pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Const) {
|
||||||
|
node.definitions.forEach(function(defn) {
|
||||||
|
var def = defn.name.definition();
|
||||||
|
references[def.id] = false;
|
||||||
|
def = def.redefined();
|
||||||
|
if (def) references[def.id] = false;
|
||||||
|
defn.value.walk(tw);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_For) {
|
||||||
if (node.init) node.init.walk(tw);
|
if (node.init) node.init.walk(tw);
|
||||||
push();
|
push();
|
||||||
@@ -4633,7 +4697,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!(sym instanceof AST_SymbolRef)) return;
|
if (!(sym instanceof AST_SymbolRef)) return;
|
||||||
if (compressor.exposed(sym.definition())) return;
|
if (compressor.exposed(sym.definition())) return;
|
||||||
if (!all(sym.definition().orig, function(sym) {
|
if (!all(sym.definition().orig, function(sym) {
|
||||||
return !(sym instanceof AST_SymbolLambda);
|
return !(sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLambda);
|
||||||
})) return;
|
})) return;
|
||||||
return sym;
|
return sym;
|
||||||
};
|
};
|
||||||
@@ -4668,43 +4732,41 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (node === self) return;
|
if (node === self) return;
|
||||||
|
if (scope === self) {
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
var node_def = node.name.definition();
|
var def = node.name.definition();
|
||||||
if (!drop_funcs && scope === self) {
|
if (!drop_funcs && !(def.id in in_use_ids)) {
|
||||||
if (!(node_def.id in in_use_ids)) {
|
in_use_ids[def.id] = true;
|
||||||
in_use_ids[node_def.id] = true;
|
in_use.push(def);
|
||||||
in_use.push(node_def);
|
|
||||||
}
|
}
|
||||||
}
|
initializations.add(def.id, 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_Definitions) {
|
||||||
var node_def = node.definition();
|
node.definitions.forEach(function(defn) {
|
||||||
var_defs_by_id.add(node_def.id, node);
|
var def = defn.name.definition();
|
||||||
assignments.add(node_def.id, node);
|
var_defs_by_id.add(def.id, defn);
|
||||||
|
if (!drop_vars && !(def.id in in_use_ids)) {
|
||||||
|
in_use_ids[def.id] = true;
|
||||||
|
in_use.push(def);
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (!defn.value) return;
|
||||||
node.definitions.forEach(function(def) {
|
if (defn.value.has_side_effects(compressor)) {
|
||||||
var node_def = def.name.definition();
|
defn.value.walk(tw);
|
||||||
var_defs_by_id.add(node_def.id, def);
|
|
||||||
if (!drop_vars) {
|
|
||||||
if (!(node_def.id in in_use_ids)) {
|
|
||||||
in_use_ids[node_def.id] = true;
|
|
||||||
in_use.push(node_def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (def.value) {
|
|
||||||
if (def.value.has_side_effects(compressor)) {
|
|
||||||
def.value.walk(tw);
|
|
||||||
} else {
|
} else {
|
||||||
initializations.add(node_def.id, def.value);
|
initializations.add(def.id, defn.value);
|
||||||
}
|
|
||||||
assignments.add(node_def.id, def);
|
|
||||||
}
|
}
|
||||||
|
assignments.add(def.id, defn);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_SymbolFunarg) {
|
||||||
|
var def = node.definition();
|
||||||
|
var_defs_by_id.add(def.id, node);
|
||||||
|
assignments.add(def.id, node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return scan_ref_scoped(node, descend, true);
|
return scan_ref_scoped(node, descend, true);
|
||||||
});
|
});
|
||||||
tw.directives = Object.create(compressor.directives);
|
tw.directives = Object.create(compressor.directives);
|
||||||
@@ -4714,7 +4776,14 @@ merge(Compressor.prototype, {
|
|||||||
// 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++) {
|
||||||
var init = initializations.get(in_use[i].id);
|
var in_use_def = in_use[i];
|
||||||
|
if (in_use_def.const_redefs) in_use_def.const_redefs.forEach(function(def) {
|
||||||
|
if (!(def.id in in_use_ids)) {
|
||||||
|
in_use_ids[def.id] = true;
|
||||||
|
in_use.push(def);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var init = initializations.get(in_use_def.id);
|
||||||
if (init) init.forEach(function(init) {
|
if (init) init.forEach(function(init) {
|
||||||
init.walk(tw);
|
init.walk(tw);
|
||||||
});
|
});
|
||||||
@@ -4915,7 +4984,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
tail.push(def);
|
tail.push(def);
|
||||||
}
|
}
|
||||||
} else if (sym.orig[0] instanceof AST_SymbolCatch) {
|
} else if (sym.orig[0] instanceof AST_SymbolCatch
|
||||||
|
&& sym.scope.resolve() === def.name.scope.resolve()) {
|
||||||
var value = def.value && def.value.drop_side_effect_free(compressor);
|
var value = def.value && def.value.drop_side_effect_free(compressor);
|
||||||
if (value) side_effects.push(value);
|
if (value) side_effects.push(value);
|
||||||
var var_defs = var_defs_by_id.get(sym.id);
|
var var_defs = var_defs_by_id.get(sym.id);
|
||||||
@@ -5012,7 +5082,13 @@ merge(Compressor.prototype, {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
}, function(node, in_list) {
|
}, function(node, in_list) {
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_BlockStatement) switch (node.body.length) {
|
||||||
|
case 0:
|
||||||
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
|
case 1:
|
||||||
|
var stat = node.body[0];
|
||||||
|
if (!(stat instanceof AST_Const)) return stat;
|
||||||
|
} else if (node instanceof AST_For) {
|
||||||
// Certain combination of unused name + side effect leads to invalid AST:
|
// Certain combination of unused name + side effect leads to invalid AST:
|
||||||
// https://github.com/mishoo/UglifyJS/issues/44
|
// https://github.com/mishoo/UglifyJS/issues/44
|
||||||
// https://github.com/mishoo/UglifyJS/issues/1838
|
// https://github.com/mishoo/UglifyJS/issues/1838
|
||||||
@@ -5574,6 +5650,9 @@ merge(Compressor.prototype, {
|
|||||||
})
|
})
|
||||||
&& all(def.references, function(ref) {
|
&& all(def.references, function(ref) {
|
||||||
return ref.fixed_value() === right;
|
return ref.fixed_value() === right;
|
||||||
|
})
|
||||||
|
&& all(def.orig, function(sym) {
|
||||||
|
return !(sym instanceof AST_SymbolConst);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -5790,7 +5869,9 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(this, [ expression, property ]);
|
return make_sequence(this, [ expression, property ]);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
return this.is_declared(compressor) ? null : this;
|
return this.is_declared(compressor) && all(this.definition().orig, function(sym) {
|
||||||
|
return !(sym instanceof AST_SymbolConst);
|
||||||
|
}) ? null : this;
|
||||||
});
|
});
|
||||||
def(AST_This, return_null);
|
def(AST_This, return_null);
|
||||||
def(AST_Unary, function(compressor, first_in_statement) {
|
def(AST_Unary, function(compressor, first_in_statement) {
|
||||||
@@ -5848,27 +5929,25 @@ merge(Compressor.prototype, {
|
|||||||
if (!compressor.option("loops")) return self;
|
if (!compressor.option("loops")) return self;
|
||||||
var cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
var cond = self.condition.is_truthy() || self.condition.evaluate(compressor, true);
|
||||||
if (!(cond instanceof AST_Node)) {
|
if (!(cond instanceof AST_Node)) {
|
||||||
if (cond) return make_node(AST_For, self, {
|
if (cond && !has_loop_control(self, compressor.parent(), AST_Continue)) return make_node(AST_For, self, {
|
||||||
body: make_node(AST_BlockStatement, self.body, {
|
body: make_node(AST_BlockStatement, self.body, {
|
||||||
body: [
|
body: [
|
||||||
self.body,
|
self.body,
|
||||||
make_node(AST_SimpleStatement, self.condition, {
|
make_node(AST_SimpleStatement, self.condition, {
|
||||||
body: self.condition
|
body: self.condition
|
||||||
})
|
}),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
if (!has_loop_control(self, compressor.parent())) {
|
if (!has_loop_control(self, compressor.parent())) return make_node(AST_BlockStatement, self.body, {
|
||||||
return make_node(AST_BlockStatement, self.body, {
|
|
||||||
body: [
|
body: [
|
||||||
self.body,
|
self.body,
|
||||||
make_node(AST_SimpleStatement, self.condition, {
|
make_node(AST_SimpleStatement, self.condition, {
|
||||||
body: self.condition
|
body: self.condition
|
||||||
})
|
}),
|
||||||
]
|
]
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (self.body instanceof AST_BlockStatement && !has_loop_control(self, compressor.parent(), AST_Continue)) {
|
if (self.body instanceof AST_BlockStatement && !has_loop_control(self, compressor.parent(), AST_Continue)) {
|
||||||
var body = self.body.body;
|
var body = self.body.body;
|
||||||
for (var i = body.length; --i >= 0;) {
|
for (var i = body.length; --i >= 0;) {
|
||||||
@@ -5877,6 +5956,7 @@ merge(Compressor.prototype, {
|
|||||||
&& !stat.alternative
|
&& !stat.alternative
|
||||||
&& stat.body instanceof AST_Break
|
&& stat.body instanceof AST_Break
|
||||||
&& compressor.loopcontrol_target(stat.body) === self) {
|
&& compressor.loopcontrol_target(stat.body) === self) {
|
||||||
|
if (has_block_scope_refs(stat.condition)) break;
|
||||||
self.condition = make_node(AST_Binary, self, {
|
self.condition = make_node(AST_Binary, self, {
|
||||||
operator: "&&",
|
operator: "&&",
|
||||||
left: stat.condition.negate(compressor),
|
left: stat.condition.negate(compressor),
|
||||||
@@ -5884,6 +5964,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
body.splice(i, 1);
|
body.splice(i, 1);
|
||||||
} else if (stat instanceof AST_SimpleStatement) {
|
} else if (stat instanceof AST_SimpleStatement) {
|
||||||
|
if (has_block_scope_refs(stat.body)) break;
|
||||||
self.condition = make_sequence(self, [
|
self.condition = make_sequence(self, [
|
||||||
stat.body,
|
stat.body,
|
||||||
self.condition,
|
self.condition,
|
||||||
@@ -5904,6 +5985,18 @@ merge(Compressor.prototype, {
|
|||||||
body: make_node(AST_EmptyStatement, self)
|
body: make_node(AST_EmptyStatement, self)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
|
function has_block_scope_refs(node) {
|
||||||
|
var found = false;
|
||||||
|
node.walk(new TreeWalker(function(node) {
|
||||||
|
if (found) return true;
|
||||||
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
if (!member(node.definition(), self.enclosed)) found = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return found;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function if_break_in_loop(self, compressor) {
|
function if_break_in_loop(self, compressor) {
|
||||||
@@ -5934,7 +6027,7 @@ merge(Compressor.prototype, {
|
|||||||
} else if (retain) {
|
} else if (retain) {
|
||||||
body.push(first);
|
body.push(first);
|
||||||
}
|
}
|
||||||
extract_declarations_from_unreachable_code(self.body, body);
|
extract_declarations_from_unreachable_code(compressor, self.body, body);
|
||||||
return make_node(AST_BlockStatement, self, {
|
return make_node(AST_BlockStatement, self, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
@@ -5952,7 +6045,7 @@ merge(Compressor.prototype, {
|
|||||||
self.condition = first.condition.negate(compressor);
|
self.condition = first.condition.negate(compressor);
|
||||||
}
|
}
|
||||||
var body = as_statement_array(first.alternative);
|
var body = as_statement_array(first.alternative);
|
||||||
extract_declarations_from_unreachable_code(first.body, body);
|
extract_declarations_from_unreachable_code(compressor, first.body, body);
|
||||||
return drop_it(body);
|
return drop_it(body);
|
||||||
}
|
}
|
||||||
ab = first_statement(first.alternative);
|
ab = first_statement(first.alternative);
|
||||||
@@ -5967,7 +6060,7 @@ merge(Compressor.prototype, {
|
|||||||
self.condition = first.condition;
|
self.condition = first.condition;
|
||||||
}
|
}
|
||||||
var body = as_statement_array(first.body);
|
var body = as_statement_array(first.body);
|
||||||
extract_declarations_from_unreachable_code(first.alternative, body);
|
extract_declarations_from_unreachable_code(compressor, first.alternative, body);
|
||||||
return drop_it(body);
|
return drop_it(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6015,7 +6108,6 @@ merge(Compressor.prototype, {
|
|||||||
if (!cond) {
|
if (!cond) {
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
var body = [];
|
var body = [];
|
||||||
extract_declarations_from_unreachable_code(self.body, body);
|
|
||||||
if (self.init instanceof AST_Statement) {
|
if (self.init instanceof AST_Statement) {
|
||||||
body.push(self.init);
|
body.push(self.init);
|
||||||
} else if (self.init) {
|
} else if (self.init) {
|
||||||
@@ -6026,6 +6118,7 @@ merge(Compressor.prototype, {
|
|||||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
body.push(make_node(AST_SimpleStatement, self.condition, {
|
||||||
body: self.condition
|
body: self.condition
|
||||||
}));
|
}));
|
||||||
|
extract_declarations_from_unreachable_code(compressor, self.body, body);
|
||||||
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
||||||
}
|
}
|
||||||
} else if (self.condition && !(cond instanceof AST_Node)) {
|
} else if (self.condition && !(cond instanceof AST_Node)) {
|
||||||
@@ -6121,21 +6214,23 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
AST_Node.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
||||||
var body = [];
|
var body = [
|
||||||
extract_declarations_from_unreachable_code(self.body, body);
|
make_node(AST_SimpleStatement, self.condition, {
|
||||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
|
||||||
body: self.condition
|
body: self.condition
|
||||||
}));
|
}),
|
||||||
|
];
|
||||||
|
extract_declarations_from_unreachable_code(compressor, self.body, body);
|
||||||
if (self.alternative) body.push(self.alternative);
|
if (self.alternative) body.push(self.alternative);
|
||||||
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
||||||
} else if (!(cond instanceof AST_Node)) {
|
} else if (!(cond instanceof AST_Node)) {
|
||||||
AST_Node.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
|
AST_Node.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
|
||||||
var body = [];
|
var body = [
|
||||||
if (self.alternative) extract_declarations_from_unreachable_code(self.alternative, body);
|
make_node(AST_SimpleStatement, self.condition, {
|
||||||
body.push(make_node(AST_SimpleStatement, self.condition, {
|
|
||||||
body: self.condition
|
body: self.condition
|
||||||
}));
|
}),
|
||||||
body.push(self.body);
|
self.body,
|
||||||
|
];
|
||||||
|
if (self.alternative) extract_declarations_from_unreachable_code(compressor, self.alternative, body);
|
||||||
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6459,7 +6554,7 @@ merge(Compressor.prototype, {
|
|||||||
if (prev && !aborts(prev)) {
|
if (prev && !aborts(prev)) {
|
||||||
prev.body = prev.body.concat(branch.body);
|
prev.body = prev.body.concat(branch.body);
|
||||||
} else {
|
} else {
|
||||||
extract_declarations_from_unreachable_code(branch, decl);
|
extract_declarations_from_unreachable_code(compressor, branch, decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -6470,9 +6565,9 @@ merge(Compressor.prototype, {
|
|||||||
if (has_declarations_only(self)) {
|
if (has_declarations_only(self)) {
|
||||||
var body = [];
|
var body = [];
|
||||||
if (self.bcatch) {
|
if (self.bcatch) {
|
||||||
extract_declarations_from_unreachable_code(self.bcatch, body);
|
extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
|
||||||
body.forEach(function(stat) {
|
body.forEach(function(stat) {
|
||||||
if (!(stat instanceof AST_Definitions)) return;
|
if (!(stat instanceof AST_Var)) return;
|
||||||
stat.definitions.forEach(function(var_def) {
|
stat.definitions.forEach(function(var_def) {
|
||||||
var def = var_def.name.definition().redefined();
|
var def = var_def.name.definition().redefined();
|
||||||
if (!def) return;
|
if (!def) return;
|
||||||
@@ -6499,7 +6594,13 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Definitions.DEFMETHOD("remove_initializers", function() {
|
AST_Const.DEFMETHOD("remove_initializers", function(compressor) {
|
||||||
|
this.definitions.forEach(function(def) {
|
||||||
|
def.value = make_node(AST_Undefined, def).optimize(compressor);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
AST_Var.DEFMETHOD("remove_initializers", function() {
|
||||||
this.definitions.forEach(function(def) {
|
this.definitions.forEach(function(def) {
|
||||||
def.value = null;
|
def.value = null;
|
||||||
});
|
});
|
||||||
@@ -6526,8 +6627,31 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(this, assignments);
|
return make_sequence(this, assignments);
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Definitions, function(self, compressor) {
|
OPT(AST_Const, function(self, compressor) {
|
||||||
return self.definitions.length ? self : make_node(AST_EmptyStatement, self);
|
return all(self.definitions, function(defn) {
|
||||||
|
var node = defn.name;
|
||||||
|
if (!node.fixed_value()) return false;
|
||||||
|
var def = node.definition();
|
||||||
|
var scope = def.scope.resolve();
|
||||||
|
if (scope instanceof AST_Toplevel) {
|
||||||
|
if (!compressor.toplevel.vars) return false;
|
||||||
|
if (def.scope === scope) return true;
|
||||||
|
return !scope.variables.has(node.name) && !scope.globals.has(node.name);
|
||||||
|
}
|
||||||
|
return def.scope === scope || !scope.find_variable(node);
|
||||||
|
}) ? make_node(AST_Var, self, {
|
||||||
|
definitions: self.definitions.map(function(defn) {
|
||||||
|
var name = make_node(AST_SymbolVar, defn.name, defn.name);
|
||||||
|
var def = name.definition();
|
||||||
|
def.orig[def.orig.indexOf(defn.name)] = name;
|
||||||
|
var scope = def.scope.resolve();
|
||||||
|
if (def.scope !== scope) scope.variables.set(def.name, def);
|
||||||
|
return make_node(AST_VarDef, defn, {
|
||||||
|
name: name,
|
||||||
|
value: defn.value
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}) : self;
|
||||||
});
|
});
|
||||||
|
|
||||||
function lift_sequence_in_expression(node, compressor) {
|
function lift_sequence_in_expression(node, compressor) {
|
||||||
|
|||||||
@@ -835,10 +835,6 @@ function OutputStream(options) {
|
|||||||
use_asm = was_asm;
|
use_asm = was_asm;
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) {
|
|
||||||
force_statement(this.body, output);
|
|
||||||
});
|
|
||||||
|
|
||||||
DEFPRINT(AST_Statement, function(output) {
|
DEFPRINT(AST_Statement, function(output) {
|
||||||
this.body.print(output);
|
this.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
@@ -897,7 +893,7 @@ function OutputStream(options) {
|
|||||||
self.condition.print(output);
|
self.condition.print(output);
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_For, function(output) {
|
DEFPRINT(AST_For, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -927,7 +923,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ForIn, function(output) {
|
DEFPRINT(AST_ForIn, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -941,7 +937,7 @@ function OutputStream(options) {
|
|||||||
self.object.print(output);
|
self.object.print(output);
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_With, function(output) {
|
DEFPRINT(AST_With, function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@@ -951,7 +947,7 @@ function OutputStream(options) {
|
|||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ functions ]----- */
|
/* -----[ functions ]----- */
|
||||||
@@ -1036,7 +1032,7 @@ function OutputStream(options) {
|
|||||||
else
|
else
|
||||||
force_statement(self.alternative, output);
|
force_statement(self.alternative, output);
|
||||||
} else {
|
} else {
|
||||||
self._do_print_body(output);
|
force_statement(self.body, output);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1114,9 +1110,10 @@ function OutputStream(options) {
|
|||||||
print_braced(this, output);
|
print_braced(this, output);
|
||||||
});
|
});
|
||||||
|
|
||||||
DEFPRINT(AST_Var, function(output) {
|
function print_definitinos(type) {
|
||||||
|
return function(output) {
|
||||||
var self = this;
|
var self = this;
|
||||||
output.print("var");
|
output.print(type);
|
||||||
output.space();
|
output.space();
|
||||||
self.definitions.forEach(function(def, i) {
|
self.definitions.forEach(function(def, i) {
|
||||||
if (i) output.comma();
|
if (i) output.comma();
|
||||||
@@ -1124,7 +1121,10 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon();
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
DEFPRINT(AST_Const, print_definitinos("const"));
|
||||||
|
DEFPRINT(AST_Var, print_definitinos("var"));
|
||||||
|
|
||||||
function parenthesize_for_noin(node, output, noin) {
|
function parenthesize_for_noin(node, output, noin) {
|
||||||
var parens = false;
|
var parens = false;
|
||||||
@@ -1383,10 +1383,11 @@ function OutputStream(options) {
|
|||||||
function force_statement(stat, output) {
|
function force_statement(stat, output) {
|
||||||
if (output.option("braces")) {
|
if (output.option("braces")) {
|
||||||
make_block(stat, output);
|
make_block(stat, output);
|
||||||
} else {
|
} else if (!stat || stat instanceof AST_EmptyStatement) {
|
||||||
if (!stat || stat instanceof AST_EmptyStatement)
|
|
||||||
output.force_semicolon();
|
output.force_semicolon();
|
||||||
else
|
} else if (stat instanceof AST_Const) {
|
||||||
|
make_block(stat, output);
|
||||||
|
} else {
|
||||||
stat.print(output);
|
stat.print(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
lib/parse.js
37
lib/parse.js
@@ -832,6 +832,12 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
return break_cont(AST_Break);
|
return break_cont(AST_Break);
|
||||||
|
|
||||||
|
case "const":
|
||||||
|
next();
|
||||||
|
var node = const_();
|
||||||
|
semicolon();
|
||||||
|
return node;
|
||||||
|
|
||||||
case "continue":
|
case "continue":
|
||||||
next();
|
next();
|
||||||
return break_cont(AST_Continue);
|
return break_cont(AST_Continue);
|
||||||
@@ -988,7 +994,9 @@ function parse($TEXT, options) {
|
|||||||
expect("(");
|
expect("(");
|
||||||
var init = null;
|
var init = null;
|
||||||
if (!is("punc", ";")) {
|
if (!is("punc", ";")) {
|
||||||
init = is("keyword", "var")
|
init = is("keyword", "const")
|
||||||
|
? (next(), const_(true))
|
||||||
|
: is("keyword", "var")
|
||||||
? (next(), var_(true))
|
? (next(), var_(true))
|
||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
@@ -1161,13 +1169,22 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function vardefs(no_in) {
|
function vardefs(type, no_in, must_init) {
|
||||||
var a = [];
|
var a = [];
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
var start = S.token;
|
||||||
|
var name = as_symbol(type);
|
||||||
|
var value = null;
|
||||||
|
if (is("operator", "=")) {
|
||||||
|
next();
|
||||||
|
value = expression(false, no_in);
|
||||||
|
} else if (must_init) {
|
||||||
|
croak("Missing initializer in declaration");
|
||||||
|
}
|
||||||
a.push(new AST_VarDef({
|
a.push(new AST_VarDef({
|
||||||
start : S.token,
|
start : start,
|
||||||
name : as_symbol(AST_SymbolVar),
|
name : name,
|
||||||
value : is("operator", "=") ? (next(), expression(false, no_in)) : null,
|
value : value,
|
||||||
end : prev()
|
end : prev()
|
||||||
}));
|
}));
|
||||||
if (!is("punc", ","))
|
if (!is("punc", ","))
|
||||||
@@ -1177,10 +1194,18 @@ function parse($TEXT, options) {
|
|||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var const_ = function(no_in) {
|
||||||
|
return new AST_Const({
|
||||||
|
start : prev(),
|
||||||
|
definitions : vardefs(AST_SymbolConst, no_in, true),
|
||||||
|
end : prev()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
var var_ = function(no_in) {
|
var var_ = function(no_in) {
|
||||||
return new AST_Var({
|
return new AST_Var({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(no_in),
|
definitions : vardefs(AST_SymbolVar, no_in),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
61
lib/scope.js
61
lib/scope.js
@@ -80,7 +80,12 @@ SymbolDef.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
redefined: function() {
|
redefined: function() {
|
||||||
return this.defun && this.defun.variables.get(this.name);
|
var scope = this.defun;
|
||||||
|
if (!scope) return;
|
||||||
|
var def = scope.variables.get(this.name);
|
||||||
|
if (!def && scope instanceof AST_Toplevel) def = scope.globals.get(this.name);
|
||||||
|
if (def === this) return;
|
||||||
|
return def;
|
||||||
},
|
},
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
return this.global && !options.toplevel
|
return this.global && !options.toplevel
|
||||||
@@ -114,6 +119,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_SwitchBranch) {
|
||||||
|
node.init_vars(scope);
|
||||||
|
descend();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Try) {
|
if (node instanceof AST_Try) {
|
||||||
walk_scope(function() {
|
walk_scope(function() {
|
||||||
walk_body(node, tw);
|
walk_body(node, tw);
|
||||||
@@ -122,10 +132,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
if (node.bfinally) node.bfinally.walk(tw);
|
if (node.bfinally) node.bfinally.walk(tw);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_BlockScope) {
|
|
||||||
walk_scope(descend);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_With) {
|
if (node instanceof AST_With) {
|
||||||
var s = scope;
|
var s = scope;
|
||||||
do {
|
do {
|
||||||
@@ -133,7 +139,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
if (s.uses_with) break;
|
if (s.uses_with) break;
|
||||||
s.uses_with = true;
|
s.uses_with = true;
|
||||||
} while (s = s.parent_scope);
|
} while (s = s.parent_scope);
|
||||||
return;
|
walk_scope(descend);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_BlockScope) {
|
||||||
|
walk_scope(descend);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
node.scope = scope;
|
node.scope = scope;
|
||||||
@@ -144,6 +155,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolCatch) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
scope.def_variable(node).defun = defun;
|
scope.def_variable(node).defun = defun;
|
||||||
|
} else if (node instanceof AST_SymbolConst) {
|
||||||
|
scope.def_variable(node).defun = defun;
|
||||||
} else if (node instanceof AST_SymbolDefun) {
|
} else if (node instanceof AST_SymbolDefun) {
|
||||||
defun.def_function(node, tw.parent());
|
defun.def_function(node, tw.parent());
|
||||||
entangle(defun, scope);
|
entangle(defun, scope);
|
||||||
@@ -216,7 +229,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
node.reference(options);
|
node.reference(options);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// ensure mangling works if catch reuses a scope variable
|
// ensure mangling works if `catch` reuses a scope variable
|
||||||
if (node instanceof AST_SymbolCatch) {
|
if (node instanceof AST_SymbolCatch) {
|
||||||
var def = node.definition().redefined();
|
var def = node.definition().redefined();
|
||||||
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
if (def) for (var s = node.scope; s; s = s.parent_scope) {
|
||||||
@@ -225,6 +238,16 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// ensure compression works if `const` reuses a scope variable
|
||||||
|
if (node instanceof AST_SymbolConst) {
|
||||||
|
var def = node.definition();
|
||||||
|
var redef = def.redefined();
|
||||||
|
if (redef) {
|
||||||
|
if (!redef.const_redefs) redef.const_redefs = [];
|
||||||
|
redef.const_redefs.push(def);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
@@ -290,7 +313,6 @@ AST_Toplevel.DEFMETHOD("def_global", function(node) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function init_block_vars(scope, parent) {
|
function init_block_vars(scope, parent) {
|
||||||
scope.cname = -1; // the current index for mangling functions/variables
|
|
||||||
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
scope.enclosed = []; // variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||||
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
scope.parent_scope = parent; // the parent scope (null if this is the top level)
|
||||||
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
scope.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||||
@@ -368,8 +390,9 @@ AST_BlockScope.DEFMETHOD("def_variable", function(symbol, init) {
|
|||||||
function names_in_use(scope, options) {
|
function names_in_use(scope, options) {
|
||||||
var names = scope.names_in_use;
|
var names = scope.names_in_use;
|
||||||
if (!names) {
|
if (!names) {
|
||||||
scope.names_in_use = names = Object.create(null);
|
scope.cname = -1;
|
||||||
scope.cname_holes = [];
|
scope.cname_holes = [];
|
||||||
|
scope.names_in_use = names = Object.create(null);
|
||||||
var cache = options.cache && options.cache.props;
|
var cache = options.cache && options.cache.props;
|
||||||
scope.enclosed.forEach(function(def) {
|
scope.enclosed.forEach(function(def) {
|
||||||
if (def.unmangleable(options)) names[def.name] = true;
|
if (def.unmangleable(options)) names[def.name] = true;
|
||||||
@@ -467,7 +490,11 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
lname = save_nesting;
|
lname = save_nesting;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_BlockScope) {
|
||||||
|
var to_mangle = [];
|
||||||
|
node.variables.each(function(def) {
|
||||||
|
if (!defer_redef(def)) to_mangle.push(def);
|
||||||
|
});
|
||||||
descend();
|
descend();
|
||||||
if (options.cache && node instanceof AST_Toplevel) {
|
if (options.cache && node instanceof AST_Toplevel) {
|
||||||
node.globals.each(mangle);
|
node.globals.each(mangle);
|
||||||
@@ -477,9 +504,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
sym.scope = node;
|
sym.scope = node;
|
||||||
sym.reference(options);
|
sym.reference(options);
|
||||||
}
|
}
|
||||||
node.variables.each(function(def) {
|
to_mangle.forEach(mangle);
|
||||||
if (!defer_redef(def)) mangle(def);
|
|
||||||
});
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
if (node instanceof AST_Label) {
|
||||||
@@ -490,13 +515,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
node.mangled_name = name;
|
node.mangled_name = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!options.ie8 && node instanceof AST_Catch && node.argname) {
|
|
||||||
var def = node.argname.definition();
|
|
||||||
var redef = defer_redef(def, node.argname);
|
|
||||||
descend();
|
|
||||||
if (!redef) mangle(def);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
redefined.forEach(mangle);
|
redefined.forEach(mangle);
|
||||||
@@ -511,7 +529,8 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options) {
|
|||||||
if (!redef) return false;
|
if (!redef) return false;
|
||||||
redefined.push(def);
|
redefined.push(def);
|
||||||
def.references.forEach(reference);
|
def.references.forEach(reference);
|
||||||
if (node) reference(node);
|
var node = def.orig[0];
|
||||||
|
if (node instanceof AST_SymbolCatch || node instanceof AST_SymbolConst) reference(node);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
function reference(sym) {
|
function reference(sym) {
|
||||||
|
|||||||
@@ -76,9 +76,8 @@ asm_mixed: {
|
|||||||
start = start | 0;
|
start = start | 0;
|
||||||
end = end | 0;
|
end = end | 0;
|
||||||
var sum = 0.0, p = 0, q = 0;
|
var sum = 0.0, p = 0, q = 0;
|
||||||
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) {
|
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0)
|
||||||
sum = sum + +log(values[p >> 3]);
|
sum = sum + +log(values[p >> 3]);
|
||||||
}
|
|
||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
function geometricMean(start, end) {
|
||||||
@@ -91,7 +90,8 @@ asm_mixed: {
|
|||||||
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
function logSum(start, end) {
|
function logSum(start, end) {
|
||||||
start |= 0, end |= 0;
|
start |= 0, end |= 0;
|
||||||
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]);
|
for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0)
|
||||||
|
sum += +log(values[p >> 3]);
|
||||||
return +sum;
|
return +sum;
|
||||||
}
|
}
|
||||||
function geometricMean(start, end) {
|
function geometricMean(start, end) {
|
||||||
|
|||||||
@@ -346,9 +346,8 @@ collapse_vars_if: {
|
|||||||
return "x" != "Bar" + x / 4 ? g9 : g5;
|
return "x" != "Bar" + x / 4 ? g9 : g5;
|
||||||
}
|
}
|
||||||
function f3(x) {
|
function f3(x) {
|
||||||
if (x) {
|
if (x)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4192,12 +4191,11 @@ issue_2436_11: {
|
|||||||
if (isCollection(arg1)) {
|
if (isCollection(arg1)) {
|
||||||
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
|
||||||
return size && true === size.isMatrix ? matrix(res) : res;
|
return size && true === size.isMatrix ? matrix(res) : res;
|
||||||
} else {
|
} else
|
||||||
return _randomInt(min = arg1, max = arg2);
|
return _randomInt(min = arg1, max = arg2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
issue_2436_12: {
|
issue_2436_12: {
|
||||||
options = {
|
options = {
|
||||||
@@ -4310,9 +4308,8 @@ issue_2497: {
|
|||||||
function sample() {
|
function sample() {
|
||||||
if (true)
|
if (true)
|
||||||
for (var i = 0; i < 1; ++i)
|
for (var i = 0; i < 1; ++i)
|
||||||
for (var k = 0; k < 1; ++k) {
|
for (var k = 0; k < 1; ++k)
|
||||||
value = (value = 1) ? value + 1 : 0;
|
value = (value = 1) ? value + 1 : 0;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
for (i = 0; i < 1; ++i)
|
for (i = 0; i < 1; ++i)
|
||||||
for (k = 0; k < 1; ++k)
|
for (k = 0; k < 1; ++k)
|
||||||
|
|||||||
@@ -55,14 +55,15 @@ ifs_3_should_warn: {
|
|||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var x, y;
|
var x, y;
|
||||||
if (x && !(x + "1") && y) { // 1
|
// 1
|
||||||
|
if (x && !(x + "1") && y) {
|
||||||
var qq;
|
var qq;
|
||||||
foo();
|
foo();
|
||||||
} else {
|
} else {
|
||||||
bar();
|
bar();
|
||||||
}
|
}
|
||||||
|
// 2
|
||||||
if (x || !!(x + "1") || y) { // 2
|
if (x || !!(x + "1") || y) {
|
||||||
foo();
|
foo();
|
||||||
} else {
|
} else {
|
||||||
var jj;
|
var jj;
|
||||||
@@ -71,9 +72,27 @@ ifs_3_should_warn: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var x, y;
|
var x, y;
|
||||||
var qq; bar(); // 1
|
// 1
|
||||||
var jj; foo(); // 2
|
var qq; bar();
|
||||||
|
// 2
|
||||||
|
foo(); var jj;
|
||||||
}
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: + in boolean context always true [test/compress/conditionals.js:3,18]",
|
||||||
|
"WARN: Boolean && always false [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Condition left of && always false [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Condition always false [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/conditionals.js:4,12]",
|
||||||
|
"WARN: + in boolean context always true [test/compress/conditionals.js:10,19]",
|
||||||
|
"WARN: Boolean || always true [test/compress/conditionals.js:10,12]",
|
||||||
|
"WARN: Condition left of || always true [test/compress/conditionals.js:10,12]",
|
||||||
|
"WARN: Condition always true [test/compress/conditionals.js:10,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/conditionals.js:13,12]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
ifs_4: {
|
ifs_4: {
|
||||||
|
|||||||
667
test/compress/const.js
Normal file
667
test/compress/const.js
Normal file
@@ -0,0 +1,667 @@
|
|||||||
|
mangle_catch_1: {
|
||||||
|
mangle = {}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
throw "eeeee";
|
||||||
|
} catch (c) {
|
||||||
|
const e = typeof d;
|
||||||
|
}
|
||||||
|
console.log(typeof a, typeof b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
throw "eeeee";
|
||||||
|
} catch (e) {
|
||||||
|
const o = typeof d;
|
||||||
|
}
|
||||||
|
console.log(typeof a, typeof b);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_catch_2: {
|
||||||
|
mangle = {}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
try {} catch (e) {
|
||||||
|
const f = 0;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function o() {
|
||||||
|
try {} catch (c) {
|
||||||
|
const o = 0;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
retain_block: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
var a = "PASS";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
var a = "PASS";
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
if_dead_branch: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function() {
|
||||||
|
if (0) {
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
0;
|
||||||
|
{
|
||||||
|
const a = void 0;
|
||||||
|
}
|
||||||
|
return typeof a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
merge_vars_1: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
var b = typeof a;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
var b = typeof a;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"object",
|
||||||
|
"object",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
merge_vars_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
(function() {
|
||||||
|
var b = function f() {
|
||||||
|
const c = a && f;
|
||||||
|
c.var += 0;
|
||||||
|
}();
|
||||||
|
console.log(b);
|
||||||
|
})(1 && --a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
1 && --a,
|
||||||
|
b = function f() {
|
||||||
|
const c = a && f;
|
||||||
|
c.var += 0;
|
||||||
|
}(),
|
||||||
|
void console.log(b);
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
merge_vars_3: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
var b = console;
|
||||||
|
console.log(typeof b);
|
||||||
|
}
|
||||||
|
var a = 1;
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
var b = console;
|
||||||
|
console.log(typeof b);
|
||||||
|
}
|
||||||
|
var a = 1;
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_merge_vars: {
|
||||||
|
options = {
|
||||||
|
merge_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const a = console;
|
||||||
|
console.log(typeof a);
|
||||||
|
var b = typeof a;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var b = console;
|
||||||
|
console.log(typeof b);
|
||||||
|
b = typeof b;
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"object",
|
||||||
|
"object",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
use_before_init_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a = "foo";
|
||||||
|
const a = "bar";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = "foo";
|
||||||
|
const a = "bar";
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
use_before_init_2: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
a = "foo";
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
const a = "bar";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
a = "foo";
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
const a = "bar";
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
use_before_init_3: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
a;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
const a = 42;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
a;
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
const a = 42;
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
use_before_init_4: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
console.log(a);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
console.log(a);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
const a = "FAIL";
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_block: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_block_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_block_1_toplevel: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_block_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_block_2_toplevel: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const a = typeof console;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
console.log(typeof a);
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
hoist_props_1: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const o = {
|
||||||
|
p: "PASS",
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
{
|
||||||
|
const o = {
|
||||||
|
p: "PASS",
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
hoist_props_2: {
|
||||||
|
options = {
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
const o = {
|
||||||
|
p: "PASS",
|
||||||
|
};
|
||||||
|
console.log(o.p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o_p = "PASS";
|
||||||
|
console.log(o_p);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_block_1: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
const o = console;
|
||||||
|
console.log(typeof o.log);
|
||||||
|
} while (!console);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do {
|
||||||
|
const o = console;
|
||||||
|
console.log(typeof o.log);
|
||||||
|
} while (!console);
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_block_2: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
const o = {};
|
||||||
|
(function() {
|
||||||
|
console.log(typeof this, o.p++);
|
||||||
|
})();
|
||||||
|
} while (!console);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do {
|
||||||
|
const o = {};
|
||||||
|
(function() {
|
||||||
|
console.log(typeof this, o.p++);
|
||||||
|
})();
|
||||||
|
} while (!console);
|
||||||
|
}
|
||||||
|
expect_stdout: "object NaN"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_continue: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} while ([ A ]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
const a = 0;
|
||||||
|
continue;
|
||||||
|
} while ([ A ]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
catch_ie8_1: {
|
||||||
|
options = {
|
||||||
|
ie8: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch (a) {}
|
||||||
|
console.log(function a() {
|
||||||
|
const a = 0;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {} catch (a) {}
|
||||||
|
console.log(function a() {
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
catch_ie8_2: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
ie8: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {} catch (a) {
|
||||||
|
const b = 0;
|
||||||
|
}
|
||||||
|
try {} catch (b) {}
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}().b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
return this;
|
||||||
|
}().b);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
dead_block_after_return: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
console.log(a);
|
||||||
|
return;
|
||||||
|
{
|
||||||
|
const a = void 0;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
const_to_var_scope_adjustment: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
for (var k in [ 42 ])
|
||||||
|
console.log(function f() {
|
||||||
|
if (k) {
|
||||||
|
const a = 0;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var k in [ 42 ])
|
||||||
|
console.log(void (k && 0));
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_if_continue_1: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
if (console) {
|
||||||
|
console.log("PASS");
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
var b;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do {
|
||||||
|
if (!console);
|
||||||
|
else {
|
||||||
|
console.log("PASS");
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (b);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_if_continue_2: {
|
||||||
|
options = {
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
if (console) {
|
||||||
|
console.log("PASS");
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
A = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (A);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do {
|
||||||
|
if (!console);
|
||||||
|
else {
|
||||||
|
console.log("PASS");
|
||||||
|
{
|
||||||
|
const a = 0;
|
||||||
|
A = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (A);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_unused: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
const b = a, c = b;
|
||||||
|
0 && c.p++;
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
const b = a;
|
||||||
|
b;
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
@@ -59,6 +59,11 @@ dead_code_2_should_warn: {
|
|||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:10,16]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:10,16]",
|
||||||
|
]
|
||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,11 +94,23 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
function bar() {}
|
function bar() {}
|
||||||
// nothing for the while
|
// nothing for the while
|
||||||
// as for the for, it should keep:
|
// as for the for, it should keep:
|
||||||
var moo;
|
|
||||||
var x = 10, y;
|
var x = 10, y;
|
||||||
|
var moo;
|
||||||
bar();
|
bar();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: + in boolean context always true [test/compress/dead-code.js:1,33]",
|
||||||
|
"WARN: Boolean || always true [test/compress/dead-code.js:1,16]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:3,12]",
|
||||||
|
"WARN: Boolean expression always true [test/compress/dead-code.js:6,47]",
|
||||||
|
"WARN: Boolean && always false [test/compress/dead-code.js:6,28]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/dead-code.js:9,12]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]",
|
||||||
|
"WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]",
|
||||||
|
]
|
||||||
node_version: "<=4"
|
node_version: "<=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,13 +90,13 @@ non_hoisted_function_after_return_2a: {
|
|||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]",
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]",
|
||||||
"INFO: pass 0: last_count: Infinity, count: 36",
|
"INFO: pass 0: last_count: Infinity, count: 35",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]",
|
||||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
"INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]",
|
||||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
"INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]",
|
||||||
"INFO: pass 1: last_count: 36, count: 18",
|
"INFO: pass 1: last_count: 35, count: 18",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,13 +248,13 @@ non_hoisted_function_after_return_2a_strict: {
|
|||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]",
|
||||||
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]",
|
||||||
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]",
|
||||||
"INFO: pass 0: last_count: Infinity, count: 47",
|
"INFO: pass 0: last_count: Infinity, count: 46",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]",
|
||||||
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]",
|
||||||
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
"INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]",
|
||||||
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
"INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]",
|
||||||
"INFO: pass 1: last_count: 47, count: 29",
|
"INFO: pass 1: last_count: 46, count: 29",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -547,8 +547,8 @@ dead_code_condition: {
|
|||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var c;
|
|
||||||
var a = 0, b = 5;
|
var a = 0, b = 5;
|
||||||
|
var c;
|
||||||
a += 1, 0,
|
a += 1, 0,
|
||||||
console.log(a);
|
console.log(a);
|
||||||
}
|
}
|
||||||
@@ -1197,3 +1197,28 @@ issue_4182_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_continue: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
continue;
|
||||||
|
} while ([ A ]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
continue;
|
||||||
|
} while ([ A ]);
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -848,12 +848,11 @@ collapse_vars_1_true: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
for (;;) {
|
for (;;)
|
||||||
if (a.g() || b.p) break;
|
if (a.g() || b.p) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
collapse_vars_1_false: {
|
collapse_vars_1_false: {
|
||||||
options = {
|
options = {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// preserve for (var xxx; ...)
|
// preserve for (var xxx; ...)
|
||||||
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Var) return node;
|
if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node;
|
||||||
// preserve for (xxx in ...)
|
// preserve for (xxx in ...)
|
||||||
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
if (parent instanceof U.AST_ForIn && parent.init === node) return node;
|
||||||
|
|
||||||
@@ -145,7 +145,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
return permute < 2 ? expr : wrap_with_console_log(expr);
|
return permute < 2 ? expr : wrap_with_console_log(expr);
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_BlockStatement) {
|
else if (node instanceof U.AST_BlockStatement) {
|
||||||
if (in_list) {
|
if (in_list && node.body.filter(function(node) {
|
||||||
|
return node instanceof U.AST_Const;
|
||||||
|
}).length == 0) {
|
||||||
node.start._permute++;
|
node.start._permute++;
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
return List.splice(node.body);
|
return List.splice(node.body);
|
||||||
@@ -410,7 +412,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
start: {},
|
start: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (node instanceof U.AST_Var) {
|
else if (node instanceof U.AST_Definitions) {
|
||||||
// remove empty var statement
|
// remove empty var statement
|
||||||
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({
|
||||||
start: {},
|
start: {},
|
||||||
|
|||||||
@@ -275,6 +275,7 @@ var CANNOT_RETURN = true;
|
|||||||
var NO_DEFUN = false;
|
var NO_DEFUN = false;
|
||||||
var DEFUN_OK = true;
|
var DEFUN_OK = true;
|
||||||
var DONT_STORE = true;
|
var DONT_STORE = true;
|
||||||
|
var NO_CONST = true;
|
||||||
|
|
||||||
var VAR_NAMES = [
|
var VAR_NAMES = [
|
||||||
"a",
|
"a",
|
||||||
@@ -312,6 +313,7 @@ var TYPEOF_OUTCOMES = [
|
|||||||
"crap",
|
"crap",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var block_vars = [];
|
||||||
var unique_vars = [];
|
var unique_vars = [];
|
||||||
var loops = 0;
|
var loops = 0;
|
||||||
var funcs = 0;
|
var funcs = 0;
|
||||||
@@ -374,11 +376,45 @@ function filterDirective(s) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
||||||
|
var block_len = block_vars.length;
|
||||||
|
var var_len = VAR_NAMES.length;
|
||||||
|
var consts = [];
|
||||||
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
|
while (!rng(block_vars.length > block_len ? 10 : 100)) {
|
||||||
|
var name = createVarName(MANDATORY, DONT_STORE);
|
||||||
|
consts.push(name);
|
||||||
|
block_vars.push(name);
|
||||||
|
}
|
||||||
|
unique_vars.length -= 6;
|
||||||
|
fn(function() {
|
||||||
|
var s = [];
|
||||||
|
if (consts.length) {
|
||||||
|
var save = VAR_NAMES;
|
||||||
|
VAR_NAMES = VAR_NAMES.filter(function(name) {
|
||||||
|
return consts.indexOf(name) < 0;
|
||||||
|
});
|
||||||
|
var len = VAR_NAMES.length;
|
||||||
|
s.push("const " + consts.map(function(name) {
|
||||||
|
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
VAR_NAMES.push(name);
|
||||||
|
return name + " = " + value;
|
||||||
|
}).join(", ") + ";");
|
||||||
|
VAR_NAMES = save.concat(VAR_NAMES.slice(len));
|
||||||
|
}
|
||||||
|
return s.join("\n");
|
||||||
|
});
|
||||||
|
block_vars.length = block_len;
|
||||||
|
if (consts.length) VAR_NAMES.splice(var_len, consts.length);
|
||||||
|
}
|
||||||
|
|
||||||
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0;
|
||||||
var namesLenBefore = VAR_NAMES.length;
|
var s = [];
|
||||||
var name;
|
var name;
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
|
var namesLenBefore = VAR_NAMES.length;
|
||||||
if (allowDefun || rng(5) > 0) {
|
if (allowDefun || rng(5) > 0) {
|
||||||
name = "f" + funcs++;
|
name = "f" + funcs++;
|
||||||
} else {
|
} else {
|
||||||
@@ -386,21 +422,20 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
name = createVarName(MANDATORY, !allowDefun);
|
name = createVarName(MANDATORY, !allowDefun);
|
||||||
unique_vars.length -= 3;
|
unique_vars.length -= 3;
|
||||||
}
|
}
|
||||||
var s = [
|
s.push("function " + name + "(" + createParams() + "){", strictMode());
|
||||||
"function " + name + "(" + createParams() + "){",
|
s.push(defns());
|
||||||
strictMode()
|
|
||||||
];
|
|
||||||
if (rng(5) === 0) {
|
if (rng(5) === 0) {
|
||||||
// functions with functions. lower the recursion to prevent a mess.
|
// functions with functions. lower the recursion to prevent a mess.
|
||||||
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth));
|
s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth));
|
||||||
} else {
|
} else {
|
||||||
// functions with statements
|
// functions with statements
|
||||||
s.push(createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
s.push(_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth));
|
||||||
}
|
}
|
||||||
s.push("}", "");
|
s.push("}", "");
|
||||||
s = filterDirective(s).join("\n");
|
s = filterDirective(s).join("\n");
|
||||||
|
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
|
});
|
||||||
|
|
||||||
if (!allowDefun) {
|
if (!allowDefun) {
|
||||||
// avoid "function statements" (decl inside statements)
|
// avoid "function statements" (decl inside statements)
|
||||||
@@ -414,7 +449,7 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) {
|
|||||||
return s + ";";
|
return s + ";";
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
function _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||||
if (--recurmax < 0) { return ";"; }
|
if (--recurmax < 0) { return ";"; }
|
||||||
var s = "";
|
var s = "";
|
||||||
while (--n > 0) {
|
while (--n > 0) {
|
||||||
@@ -423,6 +458,15 @@ function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotRe
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) {
|
||||||
|
var s = "";
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
|
s += defns() + "\n";
|
||||||
|
s += _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
|
});
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
function enableLoopControl(flag, defaultValue) {
|
function enableLoopControl(flag, defaultValue) {
|
||||||
return Array.isArray(flag) && flag.indexOf("") < 0 ? flag.concat("") : flag || defaultValue;
|
return Array.isArray(flag) && flag.indexOf("") < 0 ? flag.concat("") : flag || defaultValue;
|
||||||
}
|
}
|
||||||
@@ -496,7 +540,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
var key = rng(10) ? "key" + loop : getVarName();
|
var key = rng(10) ? "key" + loop : getVarName(NO_CONST);
|
||||||
return [
|
return [
|
||||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
label.target + " for (",
|
label.target + " for (",
|
||||||
@@ -571,13 +615,18 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
// the catch var should only be accessible in the catch clause...
|
// the catch var should only be accessible in the catch clause...
|
||||||
// we have to do go through some trouble here to prevent leaking it
|
// we have to do go through some trouble here to prevent leaking it
|
||||||
var nameLenBefore = VAR_NAMES.length;
|
var nameLenBefore = VAR_NAMES.length;
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var catchName = createVarName(MANDATORY);
|
var catchName = createVarName(MANDATORY);
|
||||||
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
var freshCatchName = VAR_NAMES.length !== nameLenBefore;
|
||||||
if (!catch_redef) unique_vars.push(catchName);
|
if (!catch_redef) unique_vars.push(catchName);
|
||||||
s += " catch (" + catchName + ") { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
s += " catch (" + catchName + ") { ";
|
||||||
|
s += defns() + "\n";
|
||||||
|
s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||||
|
s += " }";
|
||||||
// remove catch name
|
// remove catch name
|
||||||
if (!catch_redef) unique_vars.pop();
|
if (!catch_redef) unique_vars.pop();
|
||||||
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }";
|
||||||
return s;
|
return s;
|
||||||
@@ -597,7 +646,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
|
|||||||
if (hadDefault || rng(5) > 0) {
|
if (hadDefault || rng(5) > 0) {
|
||||||
s.push(
|
s.push(
|
||||||
"case " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":",
|
"case " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":",
|
||||||
createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
_createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
rng(10) > 0 ? " break;" : "/* fall-through */",
|
rng(10) > 0 ? " break;" : "/* fall-through */",
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
@@ -605,7 +654,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR
|
|||||||
hadDefault = true;
|
hadDefault = true;
|
||||||
s.push(
|
s.push(
|
||||||
"default:",
|
"default:",
|
||||||
createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
_createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
""
|
""
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -653,7 +702,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
case p++:
|
case p++:
|
||||||
return getVarName() + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return getVarName(NO_CONST) + 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++:
|
||||||
@@ -699,19 +748,22 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
var instantiate = rng(4) ? "new " : "";
|
var instantiate = rng(4) ? "new " : "";
|
||||||
s.push(
|
s.push(
|
||||||
instantiate + "function " + name + "(){",
|
instantiate + "function " + name + "(){",
|
||||||
strictMode()
|
strictMode(),
|
||||||
|
defns()
|
||||||
);
|
);
|
||||||
if (instantiate) for (var i = rng(4); --i >= 0;) {
|
if (instantiate) for (var i = rng(4); --i >= 0;) {
|
||||||
if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
||||||
else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";");
|
||||||
}
|
}
|
||||||
s.push(
|
s.push(
|
||||||
createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
_createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
rng(2) == 0 ? "}" : "}()"
|
rng(2) == 0 ? "}" : "}()"
|
||||||
);
|
);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
VAR_NAMES.length = nameLenBefore;
|
VAR_NAMES.length = nameLenBefore;
|
||||||
@@ -861,13 +913,16 @@ function createAccessor(recurmax, stmtDepth, canThrow) {
|
|||||||
do {
|
do {
|
||||||
prop2 = getDotKey();
|
prop2 = getDotKey();
|
||||||
} while (prop1 == prop2);
|
} while (prop1 == prop2);
|
||||||
|
createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) {
|
||||||
s = [
|
s = [
|
||||||
"set " + prop1 + "(" + createVarName(MANDATORY) + "){",
|
"set " + prop1 + "(" + createVarName(MANDATORY) + "){",
|
||||||
strictMode(),
|
strictMode(),
|
||||||
createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
defns(),
|
||||||
|
_createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth),
|
||||||
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
"this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";",
|
||||||
"},"
|
"},"
|
||||||
];
|
];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
VAR_NAMES.length = namesLenBefore;
|
VAR_NAMES.length = namesLenBefore;
|
||||||
return filterDirective(s).join("\n");
|
return filterDirective(s).join("\n");
|
||||||
@@ -906,7 +961,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case 1:
|
case 1:
|
||||||
return "(" + createUnarySafePrefix() + "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + "))";
|
return "(" + createUnarySafePrefix() + "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + "))";
|
||||||
case 2:
|
case 2:
|
||||||
assignee = getVarName();
|
assignee = getVarName(NO_CONST);
|
||||||
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")";
|
||||||
case 3:
|
case 3:
|
||||||
assignee = getVarName();
|
assignee = getVarName();
|
||||||
@@ -968,9 +1023,10 @@ function createUnaryPostfix() {
|
|||||||
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVarName() {
|
function getVarName(noConst) {
|
||||||
// try to get a generated name reachable from current scope. default to just `a`
|
// try to get a generated name reachable from current scope. default to just `a`
|
||||||
return VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)] || "a";
|
var name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)];
|
||||||
|
return !name || noConst && block_vars.indexOf(name) >= 0 ? "a" : name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createVarName(maybe, dontStore) {
|
function createVarName(maybe, dontStore) {
|
||||||
@@ -980,7 +1036,7 @@ function createVarName(maybe, dontStore) {
|
|||||||
do {
|
do {
|
||||||
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
name = VAR_NAMES[rng(VAR_NAMES.length)];
|
||||||
if (suffix) name += "_" + suffix;
|
if (suffix) name += "_" + suffix;
|
||||||
} while (unique_vars.indexOf(name) >= 0);
|
} while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0);
|
||||||
if (suffix && !dontStore) VAR_NAMES.push(name);
|
if (suffix && !dontStore) VAR_NAMES.push(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@@ -1258,10 +1314,6 @@ function patch_try_catch(orig, toplevel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var fallback_options = [ JSON.stringify({
|
|
||||||
compress: false,
|
|
||||||
mangle: false
|
|
||||||
}) ];
|
|
||||||
var minify_options = require("./options.json").map(JSON.stringify);
|
var minify_options = require("./options.json").map(JSON.stringify);
|
||||||
var original_code, original_result, errored;
|
var original_code, original_result, errored;
|
||||||
var uglify_code, uglify_result, ok;
|
var uglify_code, uglify_result, ok;
|
||||||
@@ -1269,10 +1321,19 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
process.stdout.write(round + " of " + num_iterations + "\r");
|
process.stdout.write(round + " of " + num_iterations + "\r");
|
||||||
|
|
||||||
original_code = createTopLevelCode();
|
original_code = createTopLevelCode();
|
||||||
var orig_result = [ sandbox.run_code(original_code) ];
|
var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ];
|
||||||
errored = typeof orig_result[0] != "string";
|
errored = typeof orig_result[0] != "string";
|
||||||
if (!errored) orig_result.push(sandbox.run_code(original_code, true));
|
if (errored) {
|
||||||
(errored ? fallback_options : minify_options).forEach(function(options) {
|
println("//=============================================================");
|
||||||
|
println("// original code");
|
||||||
|
try_beautify(original_code, false, orig_result[0], println);
|
||||||
|
println();
|
||||||
|
println();
|
||||||
|
println("original result:");
|
||||||
|
println(orig_result[0]);
|
||||||
|
println();
|
||||||
|
}
|
||||||
|
minify_options.forEach(function(options) {
|
||||||
var o = JSON.parse(options);
|
var o = JSON.parse(options);
|
||||||
var toplevel = sandbox.has_toplevel(o);
|
var toplevel = sandbox.has_toplevel(o);
|
||||||
o.validate = true;
|
o.validate = true;
|
||||||
@@ -1294,6 +1355,8 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
ok = sandbox.same_stdout(fuzzy_result, uglify_result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ignore difference in error message caused by Temporal Dead Zone
|
||||||
|
if (!ok && errored) ok = uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError";
|
||||||
// ignore difference in error message caused by `in`
|
// ignore difference in error message caused by `in`
|
||||||
// ignore difference in depth of termination caused by infinite recursion
|
// ignore difference in depth of termination caused by infinite recursion
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -1308,16 +1371,6 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
ok = errored && uglify_code.name == original_result.name;
|
ok = errored && uglify_code.name == original_result.name;
|
||||||
}
|
}
|
||||||
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options);
|
||||||
else if (errored) {
|
|
||||||
println("//=============================================================");
|
|
||||||
println("// original code");
|
|
||||||
try_beautify(original_code, toplevel, original_result, println);
|
|
||||||
println();
|
|
||||||
println();
|
|
||||||
println("original result:");
|
|
||||||
println(original_result);
|
|
||||||
println();
|
|
||||||
}
|
|
||||||
if (!ok && isFinite(num_iterations)) {
|
if (!ok && isFinite(num_iterations)) {
|
||||||
println();
|
println();
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
Reference in New Issue
Block a user