Compare commits
25 Commits
harmony-v3
...
harmony-v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6653e2102 | ||
|
|
3bbe839518 | ||
|
|
e2ec270b04 | ||
|
|
ace272f0c5 | ||
|
|
ed7a0a454e | ||
|
|
725aac8b46 | ||
|
|
d819559a01 | ||
|
|
53600e9869 | ||
|
|
7dea749f58 | ||
|
|
8ca49155a8 | ||
|
|
b95e3338d9 | ||
|
|
e40a0ee9c6 | ||
|
|
0a3fac6e68 | ||
|
|
cb62bd98d3 | ||
|
|
9f7d1f7ac6 | ||
|
|
f30790b11b | ||
|
|
5205dbcbf4 | ||
|
|
3ff625de7e | ||
|
|
4832bc5d88 | ||
|
|
7f342cb3e3 | ||
|
|
05e7d34ed4 | ||
|
|
ef74f2eaaf | ||
|
|
96082f7a9b | ||
|
|
86607156e3 | ||
|
|
0fe259e9c5 |
167
lib/compress.js
167
lib/compress.js
@@ -326,6 +326,7 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
}
|
}
|
||||||
|
def.recursive_refs = 0;
|
||||||
def.references = [];
|
def.references = [];
|
||||||
def.should_replace = undefined;
|
def.should_replace = undefined;
|
||||||
def.single_use = undefined;
|
def.single_use = undefined;
|
||||||
@@ -383,7 +384,7 @@ merge(Compressor.prototype, {
|
|||||||
return compressor.option("unused")
|
return compressor.option("unused")
|
||||||
&& !def.scope.uses_eval
|
&& !def.scope.uses_eval
|
||||||
&& !def.scope.uses_with
|
&& !def.scope.uses_with
|
||||||
&& def.references.length == 1
|
&& def.references.length - def.recursive_refs == 1
|
||||||
&& tw.loop_ids[def.id] === tw.in_loop;
|
&& tw.loop_ids[def.id] === tw.in_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,6 +483,10 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Arrow, mark_func_expr);
|
def(AST_Arrow, mark_func_expr);
|
||||||
def(AST_Assign, function(tw) {
|
def(AST_Assign, function(tw) {
|
||||||
var node = this;
|
var node = this;
|
||||||
|
if (node.left instanceof AST_Destructuring) {
|
||||||
|
node.left.walk(suppressor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
if (node.operator != "=" || !(node.left instanceof AST_SymbolRef)) return;
|
||||||
var d = node.left.definition();
|
var d = node.left.definition();
|
||||||
if (safe_to_assign(tw, d, node.right)
|
if (safe_to_assign(tw, d, node.right)
|
||||||
@@ -665,7 +670,9 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else if (d.fixed) {
|
} else if (d.fixed) {
|
||||||
value = this.fixed_value();
|
value = this.fixed_value();
|
||||||
if (value && !compressor.exposed(d) && ref_once(tw, compressor, d)) {
|
if (value instanceof AST_Lambda && recursive_ref(tw, d)) {
|
||||||
|
d.recursive_refs++;
|
||||||
|
} else if (value && !compressor.exposed(d) && ref_once(tw, compressor, d)) {
|
||||||
d.single_use = value instanceof AST_Lambda
|
d.single_use = value instanceof AST_Lambda
|
||||||
|| value instanceof AST_Class
|
|| value instanceof AST_Class
|
||||||
|| d.scope === this.scope && value.is_constant_expression();
|
|| d.scope === this.scope && value.is_constant_expression();
|
||||||
@@ -705,7 +712,7 @@ merge(Compressor.prototype, {
|
|||||||
var node = this;
|
var node = this;
|
||||||
if (node.name instanceof AST_Destructuring) {
|
if (node.name instanceof AST_Destructuring) {
|
||||||
node.name.walk(suppressor);
|
node.name.walk(suppressor);
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
if (d.fixed === undefined || safe_to_assign(tw, d, node.value)) {
|
||||||
@@ -1816,15 +1823,8 @@ merge(Compressor.prototype, {
|
|||||||
return this.operator == "void";
|
return this.operator == "void";
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(compressor) {
|
def(AST_Binary, function(compressor) {
|
||||||
switch (this.operator) {
|
return (this.operator == "&&" || this.operator == "||")
|
||||||
case "&&":
|
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||||
return this.left._dot_throw(compressor);
|
|
||||||
case "||":
|
|
||||||
return this.left._dot_throw(compressor)
|
|
||||||
&& this.right._dot_throw(compressor);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
def(AST_Assign, function(compressor) {
|
def(AST_Assign, function(compressor) {
|
||||||
return this.operator == "="
|
return this.operator == "="
|
||||||
@@ -2809,15 +2809,15 @@ merge(Compressor.prototype, {
|
|||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node === self) return;
|
if (node === self) return;
|
||||||
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
if (node instanceof AST_Defun || node instanceof AST_DefClass) {
|
||||||
|
var node_def = node.name.definition();
|
||||||
var in_export = tw.parent() instanceof AST_Export;
|
var in_export = tw.parent() instanceof AST_Export;
|
||||||
if (in_export || !drop_funcs && scope === self) {
|
if (in_export || !drop_funcs && scope === self) {
|
||||||
var node_def = node.name.definition();
|
|
||||||
if (node_def.global && !(node_def.id in in_use_ids)) {
|
if (node_def.global && !(node_def.id in in_use_ids)) {
|
||||||
in_use_ids[node_def.id] = true;
|
in_use_ids[node_def.id] = true;
|
||||||
in_use.push(node_def);
|
in_use.push(node_def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initializations.add(node.name.name, node);
|
initializations.add(node_def.id, node);
|
||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolFunarg && scope === self) {
|
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||||
@@ -2847,7 +2847,7 @@ merge(Compressor.prototype, {
|
|||||||
def.walk(tw);
|
def.walk(tw);
|
||||||
destructuring_value = destructuring_cache;
|
destructuring_value = destructuring_cache;
|
||||||
} else {
|
} else {
|
||||||
initializations.add(def.name.name, def.value);
|
initializations.add(def.name.definition().id, def.value);
|
||||||
}
|
}
|
||||||
if (def.value.has_side_effects(compressor)) {
|
if (def.value.has_side_effects(compressor)) {
|
||||||
def.value.walk(tw);
|
def.value.walk(tw);
|
||||||
@@ -2866,13 +2866,10 @@ merge(Compressor.prototype, {
|
|||||||
// initialization code to figure out if it uses other
|
// initialization code to figure out if it uses other
|
||||||
// symbols (that may not be in_use).
|
// symbols (that may not be in_use).
|
||||||
tw = new TreeWalker(scan_ref_scoped);
|
tw = new TreeWalker(scan_ref_scoped);
|
||||||
for (var i = 0; i < in_use.length; ++i) {
|
for (var i = 0; i < in_use.length; i++) {
|
||||||
in_use[i].orig.forEach(function(decl){
|
var init = initializations.get(in_use[i].id);
|
||||||
// undeclared globals will be instanceof AST_SymbolRef
|
if (init) init.forEach(function(init) {
|
||||||
var init = initializations.get(decl.name);
|
init.walk(tw);
|
||||||
if (init) init.forEach(function(init){
|
|
||||||
init.walk(tw);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
@@ -3938,9 +3935,10 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
||||||
fn = fn.fixed_value();
|
fn = fn.fixed_value();
|
||||||
}
|
}
|
||||||
|
var is_func = fn instanceof AST_Lambda;
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& simple_args
|
&& simple_args
|
||||||
&& is_func_expr(fn)
|
&& is_func
|
||||||
&& !fn.uses_arguments
|
&& !fn.uses_arguments
|
||||||
&& !fn.uses_eval) {
|
&& !fn.uses_eval) {
|
||||||
var pos = 0, last = 0;
|
var pos = 0, last = 0;
|
||||||
@@ -4127,7 +4125,7 @@ merge(Compressor.prototype, {
|
|||||||
if (func instanceof AST_SymbolRef) {
|
if (func instanceof AST_SymbolRef) {
|
||||||
func = func.fixed_value();
|
func = func.fixed_value();
|
||||||
}
|
}
|
||||||
if (func instanceof AST_Function && !func.contains_this()) {
|
if (func instanceof AST_Lambda && !func.contains_this()) {
|
||||||
return make_sequence(this, [
|
return make_sequence(this, [
|
||||||
self.args[0],
|
self.args[0],
|
||||||
make_node(AST_Call, self, {
|
make_node(AST_Call, self, {
|
||||||
@@ -4204,7 +4202,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var stat = is_func_expr(fn) && fn.body;
|
var stat = is_func && fn.body;
|
||||||
if (stat instanceof AST_Node) {
|
if (stat instanceof AST_Node) {
|
||||||
stat = make_node(AST_Return, stat, {
|
stat = make_node(AST_Return, stat, {
|
||||||
value: stat
|
value: stat
|
||||||
@@ -4219,7 +4217,7 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(self, args).optimize(compressor);
|
return make_sequence(self, args).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_func_expr(fn) && !fn.is_generator && !fn.async) {
|
if (is_func && !fn.is_generator && !fn.async) {
|
||||||
var def, value, scope, level = -1;
|
var def, value, scope, level = -1;
|
||||||
if (compressor.option("inline")
|
if (compressor.option("inline")
|
||||||
&& simple_args
|
&& simple_args
|
||||||
@@ -4268,26 +4266,39 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
|
|
||||||
function can_flatten_args(fn) {
|
function can_flatten_args(fn) {
|
||||||
var catches = Object.create(null);
|
var catches = Object.create(null), defs;
|
||||||
do {
|
do {
|
||||||
scope = compressor.parent(++level);
|
scope = compressor.parent(++level);
|
||||||
if (scope instanceof AST_SymbolRef) {
|
if (scope instanceof AST_Catch) {
|
||||||
scope = scope.fixed_value();
|
|
||||||
} else if (scope instanceof AST_Catch) {
|
|
||||||
catches[scope.argname.name] = true;
|
catches[scope.argname.name] = true;
|
||||||
|
} else if (scope instanceof AST_IterationStatement) {
|
||||||
|
defs = [];
|
||||||
|
} else if (scope instanceof AST_SymbolRef) {
|
||||||
|
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||||
}
|
}
|
||||||
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
|
} while (!(scope instanceof AST_Scope) || scope instanceof AST_Arrow);
|
||||||
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
var safe_to_inject = compressor.toplevel.vars || !(scope instanceof AST_Toplevel);
|
||||||
return all(fn.argnames, function(arg) {
|
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||||
if (arg instanceof AST_DefaultAssign) return arg.left.__unused;
|
var arg = fn.argnames[i];
|
||||||
|
if (arg instanceof AST_DefaultAssign) {
|
||||||
|
if (arg.left.__unused) continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (arg instanceof AST_Destructuring) return false;
|
if (arg instanceof AST_Destructuring) return false;
|
||||||
if (arg instanceof AST_Expansion) return arg.expression.__unused;
|
if (arg instanceof AST_Expansion) {
|
||||||
return arg.__unused
|
if (arg.expression.__unused) continue;
|
||||||
|| safe_to_inject
|
return false;
|
||||||
&& !catches[arg.name]
|
}
|
||||||
&& !identifier_atom(arg.name)
|
if (arg.__unused) continue;
|
||||||
&& !scope.var_names()[arg.name];
|
if (!safe_to_inject
|
||||||
});
|
|| catches[arg.name]
|
||||||
|
|| identifier_atom(arg.name)
|
||||||
|
|| scope.var_names()[arg.name]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (defs) defs.push(arg.definition());
|
||||||
|
}
|
||||||
|
return !defs || defs.length == 0 || !is_reachable(stat, defs);
|
||||||
}
|
}
|
||||||
|
|
||||||
function flatten_args(fn) {
|
function flatten_args(fn) {
|
||||||
@@ -4965,23 +4976,18 @@ merge(Compressor.prototype, {
|
|||||||
&& is_lhs(self, compressor.parent()) !== self) {
|
&& is_lhs(self, compressor.parent()) !== self) {
|
||||||
var d = self.definition();
|
var d = self.definition();
|
||||||
var fixed = self.fixed_value();
|
var fixed = self.fixed_value();
|
||||||
if (fixed instanceof AST_DefClass) {
|
var single_use = d.single_use;
|
||||||
d.fixed = fixed = make_node(AST_ClassExpression, fixed, fixed);
|
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
|
||||||
}
|
|
||||||
if (fixed instanceof AST_Defun) {
|
|
||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
|
||||||
}
|
|
||||||
if (d.single_use && (is_func_expr(fixed) || fixed instanceof AST_ClassExpression)) {
|
|
||||||
if (d.scope !== self.scope
|
if (d.scope !== self.scope
|
||||||
&& (!compressor.option("reduce_funcs") && is_func_expr(fixed)
|
&& (!compressor.option("reduce_funcs") && fixed instanceof AST_Lambda
|
||||||
|| d.escaped == 1
|
|| d.escaped == 1
|
||||||
|| fixed.inlined)) {
|
|| fixed.inlined)) {
|
||||||
d.single_use = false;
|
single_use = false;
|
||||||
} else if (recursive_ref(compressor, d)) {
|
} else if (recursive_ref(compressor, d)) {
|
||||||
d.single_use = false;
|
single_use = false;
|
||||||
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
|
} else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) {
|
||||||
d.single_use = fixed.is_constant_expression(self.scope);
|
single_use = fixed.is_constant_expression(self.scope);
|
||||||
if (d.single_use == "f") {
|
if (single_use == "f") {
|
||||||
var scope = self.scope;
|
var scope = self.scope;
|
||||||
do {
|
do {
|
||||||
if (scope instanceof AST_Defun || is_func_expr(scope)) {
|
if (scope instanceof AST_Defun || is_func_expr(scope)) {
|
||||||
@@ -4991,9 +4997,36 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d.single_use && fixed) {
|
if (single_use && fixed) {
|
||||||
var value = fixed.optimize(compressor);
|
if (fixed instanceof AST_DefClass) {
|
||||||
return value === fixed ? fixed.clone(true) : value;
|
fixed = make_node(AST_ClassExpression, fixed, fixed);
|
||||||
|
}
|
||||||
|
if (fixed instanceof AST_Defun) {
|
||||||
|
fixed = make_node(AST_Function, fixed, fixed);
|
||||||
|
}
|
||||||
|
var value;
|
||||||
|
if (d.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
|
||||||
|
value = fixed.clone(true);
|
||||||
|
var defun_def = value.name.definition();
|
||||||
|
var lambda_def = value.variables.get(value.name.name);
|
||||||
|
var name = lambda_def && lambda_def.orig[0];
|
||||||
|
if (!(name instanceof AST_SymbolLambda)) {
|
||||||
|
name = make_node(AST_SymbolLambda, value.name, value.name);
|
||||||
|
name.scope = value;
|
||||||
|
value.name = name;
|
||||||
|
lambda_def = value.def_function(name);
|
||||||
|
}
|
||||||
|
value.walk(new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
|
||||||
|
node.thedef = lambda_def;
|
||||||
|
lambda_def.references.push(node);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
value = fixed.optimize(compressor);
|
||||||
|
if (value === fixed) value = fixed.clone(true);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
if (fixed && d.should_replace === undefined) {
|
if (fixed && d.should_replace === undefined) {
|
||||||
var init;
|
var init;
|
||||||
@@ -5115,18 +5148,42 @@ merge(Compressor.prototype, {
|
|||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function is_reachable(self, defs) {
|
||||||
|
var reachable = false;
|
||||||
|
var find_ref = new TreeWalker(function(node) {
|
||||||
|
if (reachable) return true;
|
||||||
|
if (node instanceof AST_SymbolRef && member(node.definition(), defs)) {
|
||||||
|
return reachable = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var scan_scope = new TreeWalker(function(node) {
|
||||||
|
if (reachable) return true;
|
||||||
|
if (node instanceof AST_Scope && node !== self) {
|
||||||
|
var parent = scan_scope.parent();
|
||||||
|
if (!(parent instanceof AST_Call && parent.expression === node)) {
|
||||||
|
node.walk(find_ref);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
self.walk(scan_scope);
|
||||||
|
return reachable;
|
||||||
|
}
|
||||||
|
|
||||||
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
|
||||||
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
var ASSIGN_OPS_COMMUTATIVE = [ '*', '|', '^', '&' ];
|
||||||
OPT(AST_Assign, function(self, compressor){
|
OPT(AST_Assign, function(self, compressor){
|
||||||
|
var def;
|
||||||
if (compressor.option("dead_code")
|
if (compressor.option("dead_code")
|
||||||
&& self.left instanceof AST_SymbolRef
|
&& self.left instanceof AST_SymbolRef
|
||||||
&& self.left.definition().scope === compressor.find_parent(AST_Lambda)) {
|
&& (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) {
|
||||||
var level = 0, node, parent = self;
|
var level = 0, node, parent = self;
|
||||||
do {
|
do {
|
||||||
node = parent;
|
node = parent;
|
||||||
parent = compressor.parent(level++);
|
parent = compressor.parent(level++);
|
||||||
if (parent instanceof AST_Exit) {
|
if (parent instanceof AST_Exit) {
|
||||||
if (in_try(level, parent instanceof AST_Throw)) break;
|
if (in_try(level, parent instanceof AST_Throw)) break;
|
||||||
|
if (is_reachable(def.scope, [ def ])) break;
|
||||||
if (self.operator == "=") return self.right;
|
if (self.operator == "=") return self.right;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: self.operator.slice(0, -1),
|
operator: self.operator.slice(0, -1),
|
||||||
|
|||||||
@@ -699,9 +699,7 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PARENS(AST_Node, function(){
|
PARENS(AST_Node, return_false);
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// a function expression needs parens around it when it's provably
|
// a function expression needs parens around it when it's provably
|
||||||
// the first token to appear in a statement.
|
// the first token to appear in a statement.
|
||||||
@@ -730,15 +728,9 @@ function OutputStream(options) {
|
|||||||
return p instanceof AST_PropAccess && p.expression === this;
|
return p instanceof AST_PropAccess && p.expression === this;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_ClassExpression, function(output){
|
|
||||||
return output.parent() instanceof AST_SimpleStatement;
|
|
||||||
});
|
|
||||||
|
|
||||||
// same goes for an object literal, because otherwise it would be
|
// same goes for an object literal, because otherwise it would be
|
||||||
// interpreted as a block of code.
|
// interpreted as a block of code.
|
||||||
PARENS(AST_Object, function(output){
|
PARENS([ AST_ClassExpression, AST_Object ], first_in_statement);
|
||||||
return first_in_statement(output);
|
|
||||||
});
|
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output){
|
PARENS(AST_Unary, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
@@ -805,6 +797,10 @@ function OutputStream(options) {
|
|||||||
// a = yield 3
|
// a = yield 3
|
||||||
if (p instanceof AST_Binary && p.operator !== "=")
|
if (p instanceof AST_Binary && p.operator !== "=")
|
||||||
return true;
|
return true;
|
||||||
|
// (yield 1)()
|
||||||
|
// new (yield 1)()
|
||||||
|
if (p instanceof AST_Call && p.expression === this)
|
||||||
|
return true;
|
||||||
// (yield 1) ? yield 2 : yield 3
|
// (yield 1) ? yield 2 : yield 3
|
||||||
if (p instanceof AST_Conditional && p.condition === this)
|
if (p instanceof AST_Conditional && p.condition === this)
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
104
lib/parse.js
104
lib/parse.js
@@ -934,10 +934,15 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function expect(punc) { return expect_token("punc", punc); };
|
function expect(punc) { return expect_token("punc", punc); };
|
||||||
|
|
||||||
|
function has_newline_before(token) {
|
||||||
|
return token.nlb || !all(token.comments_before, function(comment) {
|
||||||
|
return !comment.nlb;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function can_insert_semicolon() {
|
function can_insert_semicolon() {
|
||||||
return !options.strict && (
|
return !options.strict
|
||||||
S.token.nlb || is("eof") || is("punc", "}")
|
&& (is("eof") || is("punc", "}") || has_newline_before(S.token));
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function is_in_generator() {
|
function is_in_generator() {
|
||||||
@@ -985,10 +990,10 @@ function parse($TEXT, options) {
|
|||||||
if (S.in_directives) {
|
if (S.in_directives) {
|
||||||
var token = peek();
|
var token = peek();
|
||||||
if (S.token.raw.indexOf("\\") == -1
|
if (S.token.raw.indexOf("\\") == -1
|
||||||
&& (token.nlb
|
&& (is_token(token, "punc", ";")
|
||||||
|| is_token(token, "eof")
|
|| is_token(token, "punc", "}")
|
||||||
|| is_token(token, "punc", ";")
|
|| has_newline_before(token)
|
||||||
|| is_token(token, "punc", "}"))) {
|
|| is_token(token, "eof"))) {
|
||||||
S.input.add_directive(S.token.value);
|
S.input.add_directive(S.token.value);
|
||||||
} else {
|
} else {
|
||||||
S.in_directives = false;
|
S.in_directives = false;
|
||||||
@@ -1111,7 +1116,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "throw":
|
case "throw":
|
||||||
next();
|
next();
|
||||||
if (S.token.nlb)
|
if (has_newline_before(S.token))
|
||||||
croak("Illegal newline after 'throw'");
|
croak("Illegal newline after 'throw'");
|
||||||
var value = expression(true);
|
var value = expression(true);
|
||||||
semicolon();
|
semicolon();
|
||||||
@@ -1163,10 +1168,6 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function labeled_statement() {
|
function labeled_statement() {
|
||||||
var label = as_symbol(AST_Label);
|
var label = as_symbol(AST_Label);
|
||||||
if (label.name === "yield" && is_in_generator()) {
|
|
||||||
// Ecma-262, 12.1.1 Static Semantics: Early Errors
|
|
||||||
token_error(S.prev, "Yield cannot be used as label inside generators");
|
|
||||||
}
|
|
||||||
if (label.name === "await" && is_in_async()) {
|
if (label.name === "await" && is_in_async()) {
|
||||||
token_error(S.prev, "await cannot be used as label inside async function");
|
token_error(S.prev, "await cannot be used as label inside async function");
|
||||||
}
|
}
|
||||||
@@ -1287,7 +1288,7 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var arrow_function = function(start, argnames, is_async) {
|
var arrow_function = function(start, argnames, is_async) {
|
||||||
if (S.token.nlb) {
|
if (has_newline_before(S.token)) {
|
||||||
croak("Unexpected newline before arrow (=>)");
|
croak("Unexpected newline before arrow (=>)");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1326,7 +1327,7 @@ function parse($TEXT, options) {
|
|||||||
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||||
unexpected(prev());
|
unexpected(prev());
|
||||||
|
|
||||||
var args = parameters();
|
var args = [];
|
||||||
var body = _function_body(true, is_generator || is_generator_property, is_async, name, args);
|
var body = _function_body(true, is_generator || is_generator_property, is_async, name, args);
|
||||||
return new ctor({
|
return new ctor({
|
||||||
start : args.start,
|
start : args.start,
|
||||||
@@ -1397,9 +1398,8 @@ function parse($TEXT, options) {
|
|||||||
return tracker;
|
return tracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parameters() {
|
function parameters(params) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var params = [];
|
|
||||||
var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict"));
|
var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict"));
|
||||||
|
|
||||||
expect("(");
|
expect("(");
|
||||||
@@ -1419,7 +1419,6 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
return params;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function parameter(used_parameters, symbol_type) {
|
function parameter(used_parameters, symbol_type) {
|
||||||
@@ -1506,12 +1505,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
} else if (is("name")) {
|
} else if (is("name")) {
|
||||||
used_parameters.add_parameter(S.token);
|
used_parameters.add_parameter(S.token);
|
||||||
elements.push(new symbol_type({
|
elements.push(as_symbol(symbol_type));
|
||||||
start: S.token,
|
|
||||||
name: S.token.value,
|
|
||||||
end: S.token
|
|
||||||
}));
|
|
||||||
next();
|
|
||||||
} else {
|
} else {
|
||||||
croak("Invalid function parameter");
|
croak("Invalid function parameter");
|
||||||
}
|
}
|
||||||
@@ -1561,11 +1555,8 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
|
if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].indexOf(peek().value) !== -1) {
|
||||||
used_parameters.add_parameter(S.token);
|
used_parameters.add_parameter(S.token);
|
||||||
var value = new symbol_type({
|
var start = prev();
|
||||||
start: S.token,
|
var value = as_symbol(symbol_type);
|
||||||
name: S.token.value,
|
|
||||||
end: S.token,
|
|
||||||
});
|
|
||||||
if (is_expand) {
|
if (is_expand) {
|
||||||
elements.push(new AST_Expansion({
|
elements.push(new AST_Expansion({
|
||||||
start: expand_token,
|
start: expand_token,
|
||||||
@@ -1574,13 +1565,12 @@ function parse($TEXT, options) {
|
|||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
elements.push(new AST_ObjectKeyVal({
|
elements.push(new AST_ObjectKeyVal({
|
||||||
start: prev(),
|
start: start,
|
||||||
key: S.token.value,
|
key: value.name,
|
||||||
value: value,
|
value: value,
|
||||||
end: value.end,
|
end: value.end,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
next();
|
|
||||||
} else if (is("punc", "}")) {
|
} else if (is("punc", "}")) {
|
||||||
continue; // Allow trailing hole
|
continue; // Allow trailing hole
|
||||||
} else {
|
} else {
|
||||||
@@ -1637,12 +1627,7 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
} else if (is("name")) {
|
} else if (is("name")) {
|
||||||
used_parameters.add_parameter(S.token);
|
used_parameters.add_parameter(S.token);
|
||||||
next();
|
return as_symbol(symbol_type);
|
||||||
return new symbol_type({
|
|
||||||
start: prev(),
|
|
||||||
name: prev().value,
|
|
||||||
end: prev()
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
croak("Invalid function parameter");
|
croak("Invalid function parameter");
|
||||||
}
|
}
|
||||||
@@ -1696,6 +1681,7 @@ function parse($TEXT, options) {
|
|||||||
S.in_generator = S.in_function;
|
S.in_generator = S.in_function;
|
||||||
if (is_async)
|
if (is_async)
|
||||||
S.in_async = S.in_function;
|
S.in_async = S.in_function;
|
||||||
|
if (args) parameters(args);
|
||||||
if (block)
|
if (block)
|
||||||
S.in_directives = true;
|
S.in_directives = true;
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
@@ -1703,10 +1689,8 @@ function parse($TEXT, options) {
|
|||||||
if (block) {
|
if (block) {
|
||||||
S.input.push_directives_stack();
|
S.input.push_directives_stack();
|
||||||
var a = block_();
|
var a = block_();
|
||||||
if (S.input.has_directive("use strict")) {
|
if (name) _verify_symbol(name);
|
||||||
if (name) strict_verify_symbol(name);
|
if (args) args.forEach(_verify_symbol);
|
||||||
if (args) args.forEach(strict_verify_symbol);
|
|
||||||
}
|
|
||||||
S.input.pop_directives_stack();
|
S.input.pop_directives_stack();
|
||||||
} else {
|
} else {
|
||||||
var a = expression(false);
|
var a = expression(false);
|
||||||
@@ -2588,9 +2572,14 @@ function parse($TEXT, options) {
|
|||||||
unexpected(tmp);
|
unexpected(tmp);
|
||||||
}
|
}
|
||||||
case "name":
|
case "name":
|
||||||
if (tmp.value == "yield" && !is_token(peek(), "punc", ":") && !is_token(peek(), "punc", "(")
|
if (tmp.value == "yield") {
|
||||||
&& S.input.has_directive("use strict") && !is_in_generator()) {
|
if (is_in_generator()) {
|
||||||
token_error(tmp, "Unexpected yield identifier inside strict mode");
|
token_error(tmp, "Yield cannot be used as identifier inside generators");
|
||||||
|
} else if (!is_token(peek(), "punc", ":")
|
||||||
|
&& !is_token(peek(), "punc", "(")
|
||||||
|
&& S.input.has_directive("use strict")) {
|
||||||
|
token_error(tmp, "Unexpected yield identifier inside strict mode");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "string":
|
case "string":
|
||||||
case "num":
|
case "num":
|
||||||
@@ -2621,9 +2610,19 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function strict_verify_symbol(sym) {
|
function _verify_symbol(sym) {
|
||||||
if (sym.name == "arguments" || sym.name == "eval")
|
var name = sym.name;
|
||||||
croak("Unexpected " + sym.name + " in strict mode", sym.start.line, sym.start.col, sym.start.pos);
|
if (is_in_generator() && name == "yield") {
|
||||||
|
token_error(sym.start, "Yield cannot be used as identifier inside generators");
|
||||||
|
}
|
||||||
|
if (S.input.has_directive("use strict")) {
|
||||||
|
if (name == "yield") {
|
||||||
|
token_error(sym.start, "Unexpected yield identifier inside strict mode");
|
||||||
|
}
|
||||||
|
if (sym instanceof AST_SymbolDeclaration && (name == "arguments" || name == "eval")) {
|
||||||
|
token_error(sym.start, "Unexpected " + name + " in strict mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function as_symbol(type, noerror) {
|
function as_symbol(type, noerror) {
|
||||||
@@ -2631,13 +2630,8 @@ function parse($TEXT, options) {
|
|||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (is("name", "yield") && S.input.has_directive("use strict")) {
|
|
||||||
token_error(S.prev, "Unexpected yield identifier inside strict mode");
|
|
||||||
}
|
|
||||||
var sym = _make_symbol(type);
|
var sym = _make_symbol(type);
|
||||||
if (S.input.has_directive("use strict") && sym instanceof AST_SymbolDeclaration) {
|
_verify_symbol(sym);
|
||||||
strict_verify_symbol(sym);
|
|
||||||
}
|
|
||||||
next();
|
next();
|
||||||
return sym;
|
return sym;
|
||||||
};
|
};
|
||||||
@@ -2738,7 +2732,7 @@ function parse($TEXT, options) {
|
|||||||
return ex;
|
return ex;
|
||||||
}
|
}
|
||||||
var val = expr_atom(allow_calls, allow_arrows);
|
var val = expr_atom(allow_calls, allow_arrows);
|
||||||
while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) {
|
while (is("operator") && UNARY_POSTFIX(S.token.value) && !has_newline_before(S.token)) {
|
||||||
if (val instanceof AST_Arrow) unexpected();
|
if (val instanceof AST_Arrow) unexpected();
|
||||||
val = make_unary(AST_UnaryPostfix, S.token, val);
|
val = make_unary(AST_UnaryPostfix, S.token, val);
|
||||||
val.start = start;
|
val.start = start;
|
||||||
@@ -2865,7 +2859,7 @@ function parse($TEXT, options) {
|
|||||||
next();
|
next();
|
||||||
return _yield_expression();
|
return _yield_expression();
|
||||||
} else if (S.input.has_directive("use strict")) {
|
} else if (S.input.has_directive("use strict")) {
|
||||||
token_error(S.token, "Unexpected yield identifier inside strict mode")
|
token_error(S.token, "Unexpected yield identifier inside strict mode");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.3.1",
|
"version": "3.3.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4180,10 +4180,9 @@ recursive_function_replacement: {
|
|||||||
console.log(f(c));
|
console.log(f(c));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(n) {
|
console.log(function n(o) {
|
||||||
return x(y(f(n)));
|
return x(y(n(o)));
|
||||||
}
|
}(c));
|
||||||
console.log(f(c));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1047,3 +1047,56 @@ issue_2597: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2666: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a = {
|
||||||
|
p: function() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
console.log(typeof f().p());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = {
|
||||||
|
p: function() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
console.log(typeof f().p());
|
||||||
|
}
|
||||||
|
expect_stdout: "object"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2692: {
|
||||||
|
options = {
|
||||||
|
dead_code: true,
|
||||||
|
reduce_vars: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
return a = g;
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
return a = g;
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(typeof f()());
|
||||||
|
}
|
||||||
|
expect_stdout: "function"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1786,3 +1786,112 @@ issue_2418_5: {
|
|||||||
(function f() {});
|
(function f() {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defun_lambda_same_name: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}
|
||||||
|
console.log(function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}(5));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}(5));
|
||||||
|
}
|
||||||
|
expect_stdout: "120"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2660_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 2;
|
||||||
|
function f(b) {
|
||||||
|
return b && f() || a--;
|
||||||
|
}
|
||||||
|
f(1);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 2;
|
||||||
|
(function f(b) {
|
||||||
|
return b && f() || a--;
|
||||||
|
})(1);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2660_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function f(b) {
|
||||||
|
b && f();
|
||||||
|
--a, a.toString();
|
||||||
|
}
|
||||||
|
f();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
(function f(b) {
|
||||||
|
b && f(),
|
||||||
|
(--a).toString();
|
||||||
|
})(),
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2665: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 2,
|
||||||
|
reduce_funcs: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
typeofs: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1;
|
||||||
|
function g() {
|
||||||
|
a-- && g();
|
||||||
|
}
|
||||||
|
typeof h == "function" && h();
|
||||||
|
function h() {
|
||||||
|
typeof g == "function" && g();
|
||||||
|
}
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
!function g() {
|
||||||
|
a-- && g();
|
||||||
|
}();
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "-1"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1378,11 +1378,10 @@ issue_2630_3: {
|
|||||||
expect: {
|
expect: {
|
||||||
var x = 2, a = 1;
|
var x = 2, a = 1;
|
||||||
(function() {
|
(function() {
|
||||||
function f1(a) {
|
(function f1(a) {
|
||||||
f2();
|
f2();
|
||||||
--x >= 0 && f1({});
|
--x >= 0 && f1({});
|
||||||
}
|
})(a++);
|
||||||
f1(a++);
|
|
||||||
function f2() {
|
function f2() {
|
||||||
a++;
|
a++;
|
||||||
}
|
}
|
||||||
@@ -1549,7 +1548,7 @@ issue_2647_3: {
|
|||||||
node_version: ">=4"
|
node_version: ">=4"
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_inline: {
|
recursive_inline_1: {
|
||||||
options = {
|
options = {
|
||||||
inline: true,
|
inline: true,
|
||||||
reduce_funcs: true,
|
reduce_funcs: true,
|
||||||
@@ -1572,3 +1571,203 @@ recursive_inline: {
|
|||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recursive_inline_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}
|
||||||
|
console.log(f(5));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function f(n) {
|
||||||
|
return n ? n * f(n - 1) : 1;
|
||||||
|
}(5));
|
||||||
|
}
|
||||||
|
expect_stdout: "120"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2657: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function f() {
|
||||||
|
return h;
|
||||||
|
function g(b) {
|
||||||
|
return b || b();
|
||||||
|
}
|
||||||
|
function h(a) {
|
||||||
|
g(a);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}()(42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return b = a, b || b(), a;
|
||||||
|
var b;
|
||||||
|
}(42));
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2663_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var i, o = {};
|
||||||
|
function createFn(j) {
|
||||||
|
return function() {
|
||||||
|
console.log(j);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
o[i] = createFn(i);
|
||||||
|
for (i in o)
|
||||||
|
o[i]();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
var i, o = {};
|
||||||
|
function createFn(j) {
|
||||||
|
return function() {
|
||||||
|
console.log(j);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
o[i] = createFn(i);
|
||||||
|
for (i in o)
|
||||||
|
o[i]();
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2663_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
var i;
|
||||||
|
function fn(j) {
|
||||||
|
return function() {
|
||||||
|
console.log(j);
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
fn(i);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
var i;
|
||||||
|
for (i in { a: 1, b: 2, c: 3 })
|
||||||
|
j = i, console.log(j);
|
||||||
|
var j;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2663_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function () {
|
||||||
|
var outputs = [
|
||||||
|
{ type: 0, target: null, eventName: "ngSubmit", propName: null },
|
||||||
|
{ type: 0, target: null, eventName: "submit", propName: null },
|
||||||
|
{ type: 0, target: null, eventName: "reset", propName: null },
|
||||||
|
];
|
||||||
|
function listenToElementOutputs(outputs) {
|
||||||
|
var handlers = [];
|
||||||
|
for (var i = 0; i < outputs.length; i++) {
|
||||||
|
var output = outputs[i];
|
||||||
|
var handleEventClosure = renderEventHandlerClosure(output.eventName);
|
||||||
|
handlers.push(handleEventClosure)
|
||||||
|
}
|
||||||
|
var target, name;
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
function renderEventHandlerClosure(eventName) {
|
||||||
|
return function () {
|
||||||
|
return console.log(eventName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
listenToElementOutputs(outputs).forEach(function (handler) {
|
||||||
|
return handler()
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function() {
|
||||||
|
function renderEventHandlerClosure(eventName) {
|
||||||
|
return function() {
|
||||||
|
return console.log(eventName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(function(outputs) {
|
||||||
|
var handlers = [];
|
||||||
|
for (var i = 0; i < outputs.length; i++) {
|
||||||
|
var output = outputs[i];
|
||||||
|
var handleEventClosure = renderEventHandlerClosure(output.eventName);
|
||||||
|
handlers.push(handleEventClosure);
|
||||||
|
}
|
||||||
|
return handlers;
|
||||||
|
})([ {
|
||||||
|
type: 0,
|
||||||
|
target: null,
|
||||||
|
eventName: "ngSubmit",
|
||||||
|
propName: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
target: null,
|
||||||
|
eventName: "submit",
|
||||||
|
propName: null
|
||||||
|
}, {
|
||||||
|
type: 0,
|
||||||
|
target: null,
|
||||||
|
eventName: "reset",
|
||||||
|
propName: null
|
||||||
|
} ]).forEach(function(handler) {
|
||||||
|
return handler();
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"ngSubmit",
|
||||||
|
"submit",
|
||||||
|
"reset",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -1197,3 +1197,18 @@ class_method_using_arguments: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2676: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
class A {}
|
||||||
|
A.a = 42;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(class {}).a = 42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
33
test/compress/issue-2652.js
Normal file
33
test/compress/issue-2652.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
insert_semicolon: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
comments: "all",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a
|
||||||
|
/* foo */ var b
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"var a",
|
||||||
|
"/* foo */;",
|
||||||
|
"",
|
||||||
|
"var b;",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
unary_postfix: {
|
||||||
|
beautify = {
|
||||||
|
beautify: true,
|
||||||
|
comments: "all",
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a
|
||||||
|
/* foo */++b
|
||||||
|
}
|
||||||
|
expect_exact: [
|
||||||
|
"a",
|
||||||
|
"/* foo */;",
|
||||||
|
"",
|
||||||
|
"++b;",
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -735,3 +735,35 @@ issue_2313_7: {
|
|||||||
expect_stdout: "2 1"
|
expect_stdout: "2 1"
|
||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2678: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 1, c = "FAIL";
|
||||||
|
(function f() {
|
||||||
|
(a-- && f()).p;
|
||||||
|
return {
|
||||||
|
get p() {
|
||||||
|
c = "PASS";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1, c = "FAIL";
|
||||||
|
(function f() {
|
||||||
|
(a-- && f()).p;
|
||||||
|
return {
|
||||||
|
get p() {
|
||||||
|
c = "PASS";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1355,10 +1355,9 @@ defun_inline_1: {
|
|||||||
function f() {
|
function f() {
|
||||||
return function(b) {
|
return function(b) {
|
||||||
return b;
|
return b;
|
||||||
}(2) + h();
|
}(2) + function h() {
|
||||||
function h() {
|
|
||||||
return h();
|
return h();
|
||||||
}
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1382,12 +1381,11 @@ defun_inline_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
function h() {
|
|
||||||
return h();
|
|
||||||
}
|
|
||||||
return function(b) {
|
return function(b) {
|
||||||
return b;
|
return b;
|
||||||
}(2) + h();
|
}(2) + function h() {
|
||||||
|
return h();
|
||||||
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5446,3 +5444,44 @@ issue_2598: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "true"
|
expect_stdout: "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2669: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
let foo;
|
||||||
|
console.log(([ foo ] = [ "PASS" ]) && foo);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
let foo;
|
||||||
|
console.log(([ foo ] = [ "PASS" ]) && foo);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2670: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const obj = {};
|
||||||
|
obj.prop = "PASS";
|
||||||
|
const {prop: value} = obj;
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const obj = {};
|
||||||
|
obj.prop = "PASS";
|
||||||
|
const {prop: value} = obj;
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,9 +88,8 @@ yield_before_punctuators: {
|
|||||||
})();
|
})();
|
||||||
function* g1() { (yield) }
|
function* g1() { (yield) }
|
||||||
function* g2() { [yield] }
|
function* g2() { [yield] }
|
||||||
function* g3() { return {yield} } // Added return to avoid {} drop
|
function* g3() { yield, yield; }
|
||||||
function* g4() { yield, yield; }
|
function* g4() { (yield) ? yield : yield; }
|
||||||
function* g5() { (yield) ? yield : yield; }
|
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
iter = (function*() {
|
iter = (function*() {
|
||||||
@@ -98,9 +97,8 @@ yield_before_punctuators: {
|
|||||||
})();
|
})();
|
||||||
function* g1() { (yield) }
|
function* g1() { (yield) }
|
||||||
function* g2() { [yield] }
|
function* g2() { [yield] }
|
||||||
function* g3() { return {yield} }
|
function* g3() { yield, yield; }
|
||||||
function* g4() { yield, yield; }
|
function* g4() { (yield) ? yield : yield; }
|
||||||
function* g5() { (yield) ? yield : yield; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,3 +197,17 @@ yield_as_ES5_property: {
|
|||||||
expect_exact: '"use strict";console.log({yield:42}.yield);'
|
expect_exact: '"use strict";console.log({yield:42}.yield);'
|
||||||
expect_stdout: "42"
|
expect_stdout: "42"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2689: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function* y() {
|
||||||
|
var t = yield x();
|
||||||
|
return new t();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: "function*y(){return new(yield x())}"
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,18 +8,6 @@ describe("Yield", function() {
|
|||||||
assert.strictEqual(result.code, 'function*foo(e){return yield 1,yield 2,3}');
|
assert.strictEqual(result.code, 'function*foo(e){return yield 1,yield 2,3}');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should not allow yield as labelIdentifier within generators", function() {
|
|
||||||
var js = "function* g() {yield: 1}"
|
|
||||||
var test = function() {
|
|
||||||
UglifyJS.parse(js);
|
|
||||||
}
|
|
||||||
var expect = function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
|
||||||
e.message === "Yield cannot be used as label inside generators";
|
|
||||||
}
|
|
||||||
assert.throws(test, expect);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Should not allow yield* followed by a semicolon in generators", function() {
|
it("Should not allow yield* followed by a semicolon in generators", function() {
|
||||||
var js = "function* test() {yield*\n;}";
|
var js = "function* test() {yield*\n;}";
|
||||||
var test = function() {
|
var test = function() {
|
||||||
@@ -65,42 +53,68 @@ describe("Yield", function() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var identifiers = [
|
||||||
|
// Fail in as_symbol
|
||||||
|
'import yield from "bar";',
|
||||||
|
'yield = 123;',
|
||||||
|
'yield: "123";',
|
||||||
|
'for(;;){break yield;}',
|
||||||
|
'for(;;){continue yield;}',
|
||||||
|
'function yield(){}',
|
||||||
|
'try { new Error("")} catch (yield) {}',
|
||||||
|
'var yield = "foo";',
|
||||||
|
'class yield {}',
|
||||||
|
// Fail in as_property_name
|
||||||
|
'var foo = {yield};',
|
||||||
|
];
|
||||||
|
|
||||||
it("Should not allow yield to be used as symbol, identifier or shorthand property outside generators in strict mode", function() {
|
it("Should not allow yield to be used as symbol, identifier or shorthand property outside generators in strict mode", function() {
|
||||||
var tests = [
|
function fail(e) {
|
||||||
// Fail in as_symbol
|
|
||||||
'"use strict"; import yield from "bar";',
|
|
||||||
'"use strict"; yield = 123;',
|
|
||||||
'"use strict"; yield: "123";',
|
|
||||||
'"use strict"; for(;;){break yield;}',
|
|
||||||
'"use strict"; for(;;){continue yield;}',
|
|
||||||
'"use strict"; function yield(){}',
|
|
||||||
'"use strict"; function foo(...yield){}',
|
|
||||||
'"use strict"; try { new Error("")} catch (yield) {}',
|
|
||||||
'"use strict"; var yield = "foo";',
|
|
||||||
'"use strict"; class yield {}',
|
|
||||||
|
|
||||||
// Fail in maybe_assign
|
|
||||||
'"use strict"; var foo = yield;',
|
|
||||||
'"use strict"; var foo = bar = yield',
|
|
||||||
|
|
||||||
// Fail in as_property_name
|
|
||||||
'"use strict"; var foo = {yield};',
|
|
||||||
];
|
|
||||||
|
|
||||||
var fail = function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error &&
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
/^Unexpected yield identifier (?:as parameter )?inside strict mode/.test(e.message);
|
/^Unexpected yield identifier (?:as parameter )?inside strict mode/.test(e.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
var test = function(input) {
|
function test(input) {
|
||||||
return function() {
|
return function() {
|
||||||
UglifyJS.parse(input);
|
UglifyJS.parse(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
identifiers.concat([
|
||||||
assert.throws(test(tests[i]), fail, tests[i]);
|
// Fail in as_symbol
|
||||||
|
"function foo(...yield){}",
|
||||||
|
// Fail in maybe_assign
|
||||||
|
'var foo = yield;',
|
||||||
|
'var foo = bar = yield',
|
||||||
|
]).map(function(code) {
|
||||||
|
return '"use strict"; ' + code;
|
||||||
|
}).forEach(function(code) {
|
||||||
|
assert.throws(test(code), fail, code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not allow yield to be used as symbol, identifier or shorthand property inside generators", function() {
|
||||||
|
function fail(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error && [
|
||||||
|
"Unexpected token: operator (=)",
|
||||||
|
"Yield cannot be used as identifier inside generators",
|
||||||
|
].indexOf(e.message) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test(input) {
|
||||||
|
return function() {
|
||||||
|
UglifyJS.parse(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
identifiers.map(function(code) {
|
||||||
|
return "function* f() { " + code + " }";
|
||||||
|
}).concat([
|
||||||
|
// Fail in as_symbol
|
||||||
|
"function* f(yield) {}",
|
||||||
|
]).forEach(function(code) {
|
||||||
|
assert.throws(test(code), fail, code);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should allow yield to be used as class/object property name", function() {
|
it("Should allow yield to be used as class/object property name", function() {
|
||||||
|
|||||||
@@ -329,7 +329,8 @@ function createTopLevelCode() {
|
|||||||
rng(2) == 0
|
rng(2) == 0
|
||||||
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
? createStatements(3, MAX_GENERATION_RECURSION_DEPTH, CANNOT_THROW, CANNOT_BREAK, CANNOT_CONTINUE, CANNOT_RETURN, 0)
|
||||||
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
: createFunctions(rng(MAX_GENERATED_TOPLEVELS_PER_RUN) + 1, MAX_GENERATION_RECURSION_DEPTH, DEFUN_OK, CANNOT_THROW, 0),
|
||||||
'console.log(null, a, b, c);' // preceding `null` makes for a cleaner output (empty string still shows up etc)
|
// preceding `null` makes for a cleaner output (empty string still shows up etc)
|
||||||
|
'console.log(null, a, b, c, Infinity, NaN, undefined);'
|
||||||
].join('\n');
|
].join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,6 +636,8 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
|||||||
case p++:
|
case p++:
|
||||||
case p++:
|
case p++:
|
||||||
return getVarName();
|
return getVarName();
|
||||||
|
case p++:
|
||||||
|
return getVarName() + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow);
|
||||||
case p++:
|
case p++:
|
||||||
|
|||||||
Reference in New Issue
Block a user