support default values (#4442)
This commit is contained in:
68
lib/ast.js
68
lib/ast.js
@@ -207,13 +207,23 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
|
|||||||
$documentation: "The empty statement (empty block or simply a semicolon)"
|
$documentation: "The empty statement (empty block or simply a semicolon)"
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
function must_be_expression(node, prop) {
|
function validate_expression(value, prop, multiple, allow_spread, allow_hole) {
|
||||||
if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
|
multiple = multiple ? "contain" : "be";
|
||||||
if (node[prop] instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
|
if (!(value instanceof AST_Node)) throw new Error(prop + " must " + multiple + " AST_Node");
|
||||||
if (node[prop] instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
|
if (value instanceof AST_DefaultValue) throw new Error(prop + " cannot " + multiple + " AST_DefaultValue");
|
||||||
if (node[prop] instanceof AST_Statement && !is_function(node[prop])) {
|
if (value instanceof AST_Destructured) throw new Error(prop + " cannot " + multiple + " AST_Destructured");
|
||||||
throw new Error(prop + " cannot be AST_Statement");
|
if (value instanceof AST_Hole && !allow_hole) throw new Error(prop + " cannot " + multiple + " AST_Hole");
|
||||||
|
if (value instanceof AST_Spread && !allow_spread) throw new Error(prop + " cannot " + multiple + " AST_Spread");
|
||||||
|
if (value instanceof AST_Statement && !is_function(value)) {
|
||||||
|
throw new Error(prop + " cannot " + multiple + " AST_Statement");
|
||||||
}
|
}
|
||||||
|
if (value instanceof AST_SymbolDeclaration) {
|
||||||
|
throw new Error(prop + " cannot " + multiple + " AST_SymbolDeclaration");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function must_be_expression(node, prop) {
|
||||||
|
validate_expression(node[prop], prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
|
||||||
@@ -534,7 +544,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
|
|||||||
this.argnames.forEach(function(node) {
|
this.argnames.forEach(function(node) {
|
||||||
validate_destructured(node, function(node) {
|
validate_destructured(node, function(node) {
|
||||||
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
|
||||||
});
|
}, true);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
@@ -838,7 +848,6 @@ var AST_Const = DEFNODE("Const", null, {
|
|||||||
validate_destructured(node.name, function(node) {
|
validate_destructured(node.name, function(node) {
|
||||||
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
|
||||||
});
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -851,7 +860,6 @@ var AST_Let = DEFNODE("Let", null, {
|
|||||||
validate_destructured(node.name, function(node) {
|
validate_destructured(node.name, function(node) {
|
||||||
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
|
||||||
});
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -864,7 +872,6 @@ var AST_Var = DEFNODE("Var", null, {
|
|||||||
validate_destructured(node.name, function(node) {
|
validate_destructured(node.name, function(node) {
|
||||||
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
|
||||||
});
|
});
|
||||||
if (node.value != null) must_be_expression(node, "value");
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}, AST_Definitions);
|
}, AST_Definitions);
|
||||||
@@ -873,7 +880,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
|
|||||||
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
$documentation: "A variable declaration; only appears in a AST_Definitions node",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
|
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
|
||||||
value: "[AST_Node?] initializer, or null of there's no initializer"
|
value: "[AST_Node?] initializer, or null of there's no initializer",
|
||||||
},
|
},
|
||||||
walk: function(visitor) {
|
walk: function(visitor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
@@ -882,18 +889,34 @@ 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.value != null) must_be_expression(this, "value");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ OTHER ]----- */
|
/* -----[ OTHER ]----- */
|
||||||
|
|
||||||
|
var AST_DefaultValue = DEFNODE("DefaultValue", "name value", {
|
||||||
|
$documentation: "A default value declaration",
|
||||||
|
$propdoc: {
|
||||||
|
name: "[AST_Destructured|AST_SymbolDeclaration] name of the variable",
|
||||||
|
value: "[AST_Node] value to assign if variable is `undefined`",
|
||||||
|
},
|
||||||
|
walk: function(visitor) {
|
||||||
|
var node = this;
|
||||||
|
visitor.visit(node, function() {
|
||||||
|
node.name.walk(visitor);
|
||||||
|
node.value.walk(visitor);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
_validate: function() {
|
||||||
|
must_be_expression(this, "value");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
function must_be_expressions(node, prop, allow_spread, allow_hole) {
|
function must_be_expressions(node, prop, allow_spread, allow_hole) {
|
||||||
node[prop].forEach(function(node) {
|
node[prop].forEach(function(node) {
|
||||||
if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
|
validate_expression(node, prop, true, allow_spread, allow_hole);
|
||||||
if (!allow_hole && node instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
|
|
||||||
if (!allow_spread && node instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
|
|
||||||
if (node instanceof AST_Statement && !is_function(node)) {
|
|
||||||
throw new Error(prop + " cannot contain AST_Statement");
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1048,7 +1071,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
_validate: function() {
|
_validate: function() {
|
||||||
must_be_expression(this, "left");
|
if (!(this instanceof AST_Assign)) must_be_expression(this, "left");
|
||||||
if (typeof this.operator != "string") throw new Error("operator must be string");
|
if (typeof this.operator != "string") throw new Error("operator must be string");
|
||||||
must_be_expression(this, "right");
|
must_be_expression(this, "right");
|
||||||
},
|
},
|
||||||
@@ -1131,12 +1154,13 @@ var AST_Destructured = DEFNODE("Destructured", null, {
|
|||||||
$documentation: "Base class for destructured literal",
|
$documentation: "Base class for destructured literal",
|
||||||
});
|
});
|
||||||
|
|
||||||
function validate_destructured(node, check) {
|
function validate_destructured(node, check, allow_default) {
|
||||||
|
if (node instanceof AST_DefaultValue && allow_default) return validate_destructured(node.name, check);
|
||||||
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
|
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
|
||||||
if (!(node instanceof AST_Hole)) validate_destructured(node, check);
|
if (!(node instanceof AST_Hole)) validate_destructured(node, check, true);
|
||||||
});
|
});
|
||||||
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
|
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
|
||||||
validate_destructured(prop.value, check);
|
validate_destructured(prop.value, check, true);
|
||||||
});
|
});
|
||||||
check(node);
|
check(node);
|
||||||
}
|
}
|
||||||
@@ -1174,7 +1198,7 @@ var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
|
|||||||
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
|
||||||
must_be_expression(this, "key");
|
must_be_expression(this, "key");
|
||||||
}
|
}
|
||||||
must_be_expression(this, "value");
|
if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
258
lib/compress.js
258
lib/compress.js
@@ -56,6 +56,7 @@ function Compressor(options, false_by_default) {
|
|||||||
comparisons : !false_by_default,
|
comparisons : !false_by_default,
|
||||||
conditionals : !false_by_default,
|
conditionals : !false_by_default,
|
||||||
dead_code : !false_by_default,
|
dead_code : !false_by_default,
|
||||||
|
default_values : !false_by_default,
|
||||||
directives : !false_by_default,
|
directives : !false_by_default,
|
||||||
drop_console : false,
|
drop_console : false,
|
||||||
drop_debugger : !false_by_default,
|
drop_debugger : !false_by_default,
|
||||||
@@ -607,6 +608,20 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function scan_declaration(tw, lhs, fixed, visit) {
|
function scan_declaration(tw, lhs, fixed, visit) {
|
||||||
var scanner = new TreeWalker(function(node) {
|
var scanner = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_DefaultValue) {
|
||||||
|
reset_flags(node);
|
||||||
|
push(tw);
|
||||||
|
node.value.walk(tw);
|
||||||
|
pop(tw);
|
||||||
|
var save = fixed;
|
||||||
|
fixed = function() {
|
||||||
|
var value = save();
|
||||||
|
return is_undefined(value) ? make_sequence(node, [ value, node.value ]) : node.name;
|
||||||
|
};
|
||||||
|
node.name.walk(scanner);
|
||||||
|
fixed = save;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_DestructuredArray) {
|
if (node instanceof AST_DestructuredArray) {
|
||||||
reset_flags(node);
|
reset_flags(node);
|
||||||
var save = fixed;
|
var save = fixed;
|
||||||
@@ -1184,6 +1199,11 @@ merge(Compressor.prototype, {
|
|||||||
AST_Node.DEFMETHOD("convert_symbol", noop);
|
AST_Node.DEFMETHOD("convert_symbol", noop);
|
||||||
AST_Destructured.DEFMETHOD("convert_symbol", function(type, process) {
|
AST_Destructured.DEFMETHOD("convert_symbol", function(type, process) {
|
||||||
return this.transform(new TreeTransformer(function(node, descend) {
|
return this.transform(new TreeTransformer(function(node, descend) {
|
||||||
|
if (node instanceof AST_DefaultValue) {
|
||||||
|
node = node.clone();
|
||||||
|
node.name = node.name.transform(this);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
if (node instanceof AST_Destructured) {
|
if (node instanceof AST_Destructured) {
|
||||||
node = node.clone();
|
node = node.clone();
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
@@ -1205,8 +1225,13 @@ merge(Compressor.prototype, {
|
|||||||
AST_SymbolDeclaration.DEFMETHOD("convert_symbol", convert_symbol);
|
AST_SymbolDeclaration.DEFMETHOD("convert_symbol", convert_symbol);
|
||||||
AST_SymbolRef.DEFMETHOD("convert_symbol", convert_symbol);
|
AST_SymbolRef.DEFMETHOD("convert_symbol", convert_symbol);
|
||||||
|
|
||||||
AST_Destructured.DEFMETHOD("mark_symbol", function(process, tw) {
|
function mark_destructured(process, tw) {
|
||||||
var marker = new TreeWalker(function(node) {
|
var marker = new TreeWalker(function(node) {
|
||||||
|
if (node instanceof AST_DefaultValue) {
|
||||||
|
node.value.walk(tw);
|
||||||
|
node.name.walk(marker);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_DestructuredKeyVal) {
|
if (node instanceof AST_DestructuredKeyVal) {
|
||||||
if (node.key instanceof AST_Node) node.key.walk(tw);
|
if (node.key instanceof AST_Node) node.key.walk(tw);
|
||||||
node.value.walk(marker);
|
node.value.walk(marker);
|
||||||
@@ -1215,7 +1240,9 @@ merge(Compressor.prototype, {
|
|||||||
return process(node);
|
return process(node);
|
||||||
});
|
});
|
||||||
this.walk(marker);
|
this.walk(marker);
|
||||||
});
|
}
|
||||||
|
AST_DefaultValue.DEFMETHOD("mark_symbol", mark_destructured);
|
||||||
|
AST_Destructured.DEFMETHOD("mark_symbol", mark_destructured);
|
||||||
function mark_symbol(process) {
|
function mark_symbol(process) {
|
||||||
return process(this);
|
return process(this);
|
||||||
}
|
}
|
||||||
@@ -1229,6 +1256,10 @@ merge(Compressor.prototype, {
|
|||||||
var found = false;
|
var found = false;
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
if (found) return true;
|
if (found) return true;
|
||||||
|
if (node instanceof AST_DefaultValue) {
|
||||||
|
node.name.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_DestructuredKeyVal) {
|
if (node instanceof AST_DestructuredKeyVal) {
|
||||||
if (!allow_computed_keys && node.key instanceof AST_Node) return found = true;
|
if (!allow_computed_keys && node.key instanceof AST_Node) return found = true;
|
||||||
node.value.walk(tw);
|
node.value.walk(tw);
|
||||||
@@ -1658,7 +1689,7 @@ merge(Compressor.prototype, {
|
|||||||
var assign_used = false;
|
var assign_used = false;
|
||||||
var can_replace = !args || !hit;
|
var can_replace = !args || !hit;
|
||||||
if (!can_replace) {
|
if (!can_replace) {
|
||||||
for (var j = scope.argnames.lastIndexOf(candidate.name) + 1; !abort && j < args.length; j++) {
|
for (var j = candidate.index + 1; !abort && j < args.length; j++) {
|
||||||
args[j].transform(scanner);
|
args[j].transform(scanner);
|
||||||
}
|
}
|
||||||
can_replace = true;
|
can_replace = true;
|
||||||
@@ -1895,9 +1926,14 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = len; --i >= 0;) {
|
for (var i = len; --i >= 0;) {
|
||||||
var sym = fn.argnames[i];
|
var sym = fn.argnames[i];
|
||||||
var arg = iife.args[i];
|
var arg = iife.args[i];
|
||||||
|
var value;
|
||||||
|
if (sym instanceof AST_DefaultValue) {
|
||||||
|
value = sym.value;
|
||||||
|
sym = sym.name;
|
||||||
|
}
|
||||||
args.unshift(make_node(AST_VarDef, sym, {
|
args.unshift(make_node(AST_VarDef, sym, {
|
||||||
name: sym,
|
name: sym,
|
||||||
value: arg
|
value: value ? arg ? make_sequence(iife, [ arg, value ]) : value : arg,
|
||||||
}));
|
}));
|
||||||
if (sym instanceof AST_Destructured) {
|
if (sym instanceof AST_Destructured) {
|
||||||
if (!sym.match_symbol(return_false)) continue;
|
if (!sym.match_symbol(return_false)) continue;
|
||||||
@@ -1906,17 +1942,21 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (sym.name in names) continue;
|
if (sym.name in names) continue;
|
||||||
names[sym.name] = true;
|
names[sym.name] = true;
|
||||||
if (!arg) {
|
if (value) arg = !arg || is_undefined(arg) ? value : null;
|
||||||
|
if (!arg && !value) {
|
||||||
arg = make_node(AST_Undefined, sym).transform(compressor);
|
arg = make_node(AST_Undefined, sym).transform(compressor);
|
||||||
} else if (arg instanceof AST_Lambda && arg.pinned()) {
|
} else if (arg instanceof AST_Lambda && arg.pinned()) {
|
||||||
arg = null;
|
arg = null;
|
||||||
} else {
|
} else if (arg) {
|
||||||
arg.walk(tw);
|
arg.walk(tw);
|
||||||
}
|
}
|
||||||
if (arg) candidates.unshift([ make_node(AST_VarDef, sym, {
|
if (!arg) continue;
|
||||||
|
var candidate = make_node(AST_VarDef, sym, {
|
||||||
name: sym,
|
name: sym,
|
||||||
value: arg
|
value: arg
|
||||||
}) ]);
|
});
|
||||||
|
candidate.index = i;
|
||||||
|
candidates.unshift([ candidate ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2310,14 +2350,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function remove_candidate(expr) {
|
function remove_candidate(expr) {
|
||||||
if (expr.name instanceof AST_SymbolFunarg) {
|
var index = expr.index;
|
||||||
var index = compressor.self().argnames.indexOf(expr.name);
|
if (index >= 0) {
|
||||||
var args = compressor.parent().args;
|
var argname = scope.argnames[index];
|
||||||
if (args[index]) {
|
if (argname instanceof AST_DefaultValue) {
|
||||||
args[index] = make_node(AST_Number, args[index], {
|
argname.value = make_node(AST_Number, argname, {
|
||||||
value: 0
|
value: 0
|
||||||
});
|
});
|
||||||
expr.name.definition().fixed = false;
|
argname.name.definition().fixed = false;
|
||||||
|
} else {
|
||||||
|
var args = compressor.parent().args;
|
||||||
|
if (args[index]) {
|
||||||
|
args[index] = make_node(AST_Number, args[index], {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
argname.definition().fixed = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3097,7 +3145,7 @@ merge(Compressor.prototype, {
|
|||||||
|| node instanceof AST_Undefined
|
|| node instanceof AST_Undefined
|
||||||
|| node instanceof AST_UnaryPrefix
|
|| node instanceof AST_UnaryPrefix
|
||||||
&& node.operator == "void"
|
&& node.operator == "void"
|
||||||
&& !node.expression.has_side_effects(compressor);
|
&& !(compressor && node.expression.has_side_effects(compressor));
|
||||||
}
|
}
|
||||||
|
|
||||||
// is_truthy()
|
// is_truthy()
|
||||||
@@ -4077,10 +4125,18 @@ merge(Compressor.prototype, {
|
|||||||
if (fn.evaluating) return this;
|
if (fn.evaluating) return this;
|
||||||
if (fn.name && fn.name.definition().recursive_refs > 0) return this;
|
if (fn.name && fn.name.definition().recursive_refs > 0) return this;
|
||||||
if (this.is_expr_pure(compressor)) return this;
|
if (this.is_expr_pure(compressor)) return this;
|
||||||
if (!all(fn.argnames, function(sym) {
|
var args = eval_args(this.args);
|
||||||
|
if (!all(fn.argnames, function(sym, index) {
|
||||||
|
if (sym instanceof AST_DefaultValue) {
|
||||||
|
if (!args) return false;
|
||||||
|
if (args[index] !== undefined) return false;
|
||||||
|
var value = sym.value._eval(compressor, ignore_side_effects, cached, depth);
|
||||||
|
if (value === sym.value) return false;
|
||||||
|
args[index] = value;
|
||||||
|
sym = sym.name;
|
||||||
|
}
|
||||||
return !(sym instanceof AST_Destructured);
|
return !(sym instanceof AST_Destructured);
|
||||||
})) return this;
|
})) return this;
|
||||||
var args = eval_args(this.args);
|
|
||||||
if (!args && !ignore_side_effects) return this;
|
if (!args && !ignore_side_effects) return this;
|
||||||
var stat = fn.first_statement();
|
var stat = fn.first_statement();
|
||||||
if (!(stat instanceof AST_Return)) {
|
if (!(stat instanceof AST_Return)) {
|
||||||
@@ -4104,9 +4160,10 @@ merge(Compressor.prototype, {
|
|||||||
if (!val) return;
|
if (!val) return;
|
||||||
var cached_args = [];
|
var cached_args = [];
|
||||||
if (!args || all(fn.argnames, function(sym, i) {
|
if (!args || all(fn.argnames, function(sym, i) {
|
||||||
var value = args[i];
|
if (sym instanceof AST_DefaultValue) sym = sym.name;
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
if (def.orig[def.orig.length - 1] !== sym) return false;
|
if (def.orig[def.orig.length - 1] !== sym) return false;
|
||||||
|
var value = args[i];
|
||||||
def.references.forEach(function(node) {
|
def.references.forEach(function(node) {
|
||||||
node._eval = function() {
|
node._eval = function() {
|
||||||
return value;
|
return value;
|
||||||
@@ -5340,32 +5397,35 @@ merge(Compressor.prototype, {
|
|||||||
var calls_to_drop_args = [];
|
var calls_to_drop_args = [];
|
||||||
var fns_with_marked_args = [];
|
var fns_with_marked_args = [];
|
||||||
var trimmer = new TreeTransformer(function(node) {
|
var trimmer = new TreeTransformer(function(node) {
|
||||||
|
if (node instanceof AST_DefaultValue) return trim_default(tt, trimmer, node);
|
||||||
if (node instanceof AST_DestructuredArray) {
|
if (node instanceof AST_DestructuredArray) {
|
||||||
var trim = true;
|
var trim = true;
|
||||||
for (var i = node.elements.length; --i >= 0;) {
|
for (var i = node.elements.length; --i >= 0;) {
|
||||||
var sym = node.elements[i];
|
var element = node.elements[i].transform(trimmer);
|
||||||
if (!(sym instanceof AST_SymbolDeclaration)) {
|
if (element) {
|
||||||
node.elements[i] = sym.transform(trimmer);
|
node.elements[i] = element;
|
||||||
trim = false;
|
|
||||||
} else if (sym.definition().id in in_use_ids) {
|
|
||||||
trim = false;
|
trim = false;
|
||||||
} else if (trim) {
|
} else if (trim) {
|
||||||
node.elements.pop();
|
node.elements.pop();
|
||||||
} else {
|
} else {
|
||||||
node.elements[i] = make_node(AST_Hole, sym);
|
node.elements[i] = make_node(AST_Hole, node.elements[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_DestructuredKeyVal) {
|
if (node instanceof AST_DestructuredKeyVal) {
|
||||||
if (!(node.value instanceof AST_SymbolDeclaration)) {
|
var retain = false;
|
||||||
node.value = node.value.transform(trimmer);
|
if (node.key instanceof AST_Node) {
|
||||||
return node;
|
node.key = node.key.transform(tt);
|
||||||
|
retain = node.key.has_side_effects(compressor);
|
||||||
}
|
}
|
||||||
if (typeof node.key != "string") return node;
|
if (retain && is_decl(node.value)) return node;
|
||||||
if (node.value.definition().id in in_use_ids) return node;
|
var value = node.value.transform(trimmer);
|
||||||
return List.skip;
|
if (!value) return List.skip;
|
||||||
|
node.value = value;
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_SymbolDeclaration) return node.definition().id in in_use_ids ? node : null;
|
||||||
});
|
});
|
||||||
var tt = new TreeTransformer(function(node, descend, in_list) {
|
var tt = new TreeTransformer(function(node, descend, in_list) {
|
||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
@@ -5432,21 +5492,28 @@ merge(Compressor.prototype, {
|
|||||||
var trim = compressor.drop_fargs(node, parent);
|
var trim = compressor.drop_fargs(node, parent);
|
||||||
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
||||||
var sym = a[i];
|
var sym = a[i];
|
||||||
if (sym instanceof AST_Destructured) {
|
if (!(sym instanceof AST_SymbolFunarg)) {
|
||||||
sym.transform(trimmer);
|
var arg = sym.transform(trimmer);
|
||||||
trim = false;
|
if (arg) {
|
||||||
|
trim = false;
|
||||||
|
} else if (trim) {
|
||||||
|
log(sym.name, "Dropping unused function argument {name}");
|
||||||
|
a.pop();
|
||||||
|
} else {
|
||||||
|
sym.name.__unused = true;
|
||||||
|
a[i] = sym.name;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
if (def.id in in_use_ids) {
|
if (def.id in in_use_ids) {
|
||||||
trim = false;
|
trim = false;
|
||||||
if (indexOf_assign(def, sym) < 0) sym.__unused = null;
|
if (indexOf_assign(def, sym) < 0) sym.__unused = null;
|
||||||
|
} else if (trim) {
|
||||||
|
log(sym, "Dropping unused function argument {name}");
|
||||||
|
a.pop();
|
||||||
} else {
|
} else {
|
||||||
sym.__unused = true;
|
sym.__unused = true;
|
||||||
if (trim) {
|
|
||||||
log(sym, "Dropping unused function argument {name}");
|
|
||||||
a.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fns_with_marked_args.push(node);
|
fns_with_marked_args.push(node);
|
||||||
@@ -5469,6 +5536,7 @@ merge(Compressor.prototype, {
|
|||||||
if (def.name instanceof AST_Destructured) {
|
if (def.name instanceof AST_Destructured) {
|
||||||
var value = def.value;
|
var value = def.value;
|
||||||
var trimmer = new TreeTransformer(function(node) {
|
var trimmer = new TreeTransformer(function(node) {
|
||||||
|
if (node instanceof AST_DefaultValue) return trim_default(tt, trimmer, node);
|
||||||
if (node instanceof AST_DestructuredArray) {
|
if (node instanceof AST_DestructuredArray) {
|
||||||
var save = value;
|
var save = value;
|
||||||
if (value instanceof AST_SymbolRef) value = value.fixed_value();
|
if (value instanceof AST_SymbolRef) value = value.fixed_value();
|
||||||
@@ -5514,7 +5582,7 @@ merge(Compressor.prototype, {
|
|||||||
value = values && values[prop.key];
|
value = values && values[prop.key];
|
||||||
retain = false;
|
retain = false;
|
||||||
}
|
}
|
||||||
if (retain && prop.value instanceof AST_SymbolDeclaration) {
|
if (retain && is_decl(prop.value)) {
|
||||||
properties.push(prop);
|
properties.push(prop);
|
||||||
} else {
|
} else {
|
||||||
var newValue = prop.value.transform(trimmer);
|
var newValue = prop.value.transform(trimmer);
|
||||||
@@ -5962,6 +6030,38 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_decl(node) {
|
||||||
|
return (node instanceof AST_DefaultValue ? node.name : node) instanceof AST_SymbolDeclaration;
|
||||||
|
}
|
||||||
|
|
||||||
|
function trim_default(tt, trimmer, node) {
|
||||||
|
node.value = node.value.transform(tt);
|
||||||
|
var name = node.name.transform(trimmer);
|
||||||
|
if (!name) {
|
||||||
|
var value = node.value.drop_side_effect_free(compressor);
|
||||||
|
if (!value) return null;
|
||||||
|
name = node.name;
|
||||||
|
if (name instanceof AST_Destructured) {
|
||||||
|
name = name.clone();
|
||||||
|
name[name instanceof AST_DestructuredArray ? "elements" : "properties"] = [];
|
||||||
|
if (!(value instanceof AST_Array || value.is_string(compressor)
|
||||||
|
|| name instanceof AST_DestructuredObject
|
||||||
|
&& (value instanceof AST_Object
|
||||||
|
|| value.is_boolean(compressor)
|
||||||
|
|| value.is_number(compressor)))) {
|
||||||
|
value = make_node(AST_Array, value, {
|
||||||
|
elements: [ value ],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
node.name = name;
|
||||||
|
} else {
|
||||||
|
log(name, "Side effects in default value of unused variable {name}");
|
||||||
|
}
|
||||||
|
node.value = value;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
|
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) {
|
||||||
@@ -6168,7 +6268,8 @@ merge(Compressor.prototype, {
|
|||||||
if (!(exp instanceof AST_Lambda)) return;
|
if (!(exp instanceof AST_Lambda)) return;
|
||||||
if (exp.uses_arguments || exp.pinned()) return;
|
if (exp.uses_arguments || exp.pinned()) return;
|
||||||
var sym = exp.argnames[parent.args.indexOf(this)];
|
var sym = exp.argnames[parent.args.indexOf(this)];
|
||||||
if (sym && !all_bool(sym.definition(), bool_returns, compressor)) return;
|
if (sym instanceof AST_DefaultValue) sym = sym.name;
|
||||||
|
if (sym instanceof AST_SymbolFunarg && !all_bool(sym.definition(), bool_returns, compressor)) return;
|
||||||
} else if (parent.TYPE == "Call") {
|
} else if (parent.TYPE == "Call") {
|
||||||
compressor.pop();
|
compressor.pop();
|
||||||
var in_bool = compressor.in_boolean_context();
|
var in_bool = compressor.in_boolean_context();
|
||||||
@@ -7447,6 +7548,11 @@ merge(Compressor.prototype, {
|
|||||||
var side_effects = [];
|
var side_effects = [];
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
var argname = fn.argnames[i];
|
var argname = fn.argnames[i];
|
||||||
|
if (compressor.option("default_values")
|
||||||
|
&& argname instanceof AST_DefaultValue
|
||||||
|
&& args[i].is_defined(compressor)) {
|
||||||
|
fn.argnames[i] = argname = argname.name;
|
||||||
|
}
|
||||||
if (!argname || "__unused" in argname) {
|
if (!argname || "__unused" in argname) {
|
||||||
var node = args[i].drop_side_effect_free(compressor);
|
var node = args[i].drop_side_effect_free(compressor);
|
||||||
if (drop_fargs(argname)) {
|
if (drop_fargs(argname)) {
|
||||||
@@ -7779,22 +7885,31 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
var is_func = fn instanceof AST_Arrow || fn instanceof AST_Defun || fn instanceof AST_Function;
|
var is_func = fn instanceof AST_Arrow || fn instanceof AST_Defun || fn instanceof AST_Function;
|
||||||
var stat = is_func && fn.first_statement();
|
var stat = is_func && fn.first_statement();
|
||||||
var can_inline = is_func
|
var has_default = false;
|
||||||
&& compressor.option("inline")
|
var can_drop = is_func && all(fn.argnames, function(argname, index) {
|
||||||
&& !self.is_expr_pure(compressor)
|
if (argname instanceof AST_DefaultValue) {
|
||||||
&& all(fn.argnames, function(argname) {
|
has_default = true;
|
||||||
return !(argname instanceof AST_Destructured);
|
var arg = self.args[index];
|
||||||
})
|
if (arg && !is_undefined(arg)) return false;
|
||||||
&& all(self.args, function(arg) {
|
var abort = false;
|
||||||
return !(arg instanceof AST_Spread);
|
argname.value.walk(new TreeWalker(function(node) {
|
||||||
});
|
if (abort) return true;
|
||||||
|
if (node instanceof AST_SymbolRef && fn.find_variable(node.name) === node.definition()) {
|
||||||
|
return abort = true;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
if (abort) return false;
|
||||||
|
argname = argname.name;
|
||||||
|
}
|
||||||
|
return !(argname instanceof AST_Destructured);
|
||||||
|
});
|
||||||
|
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||||
if (can_inline && stat instanceof AST_Return) {
|
if (can_inline && stat instanceof AST_Return) {
|
||||||
var value = stat.value;
|
var value = stat.value;
|
||||||
if (exp === fn && (!value || value.is_constant_expression() && safe_from_await(value))) {
|
if (exp === fn && (!value || value.is_constant_expression() && safe_from_await(value))) {
|
||||||
var args = self.args.concat(value || make_node(AST_Undefined, self));
|
return make_sequence(self, convert_args(value)).optimize(compressor);
|
||||||
return make_sequence(self, args).optimize(compressor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_func) {
|
if (is_func) {
|
||||||
@@ -7805,6 +7920,9 @@ merge(Compressor.prototype, {
|
|||||||
&& !(fn.name && fn instanceof AST_Function)
|
&& !(fn.name && fn instanceof AST_Function)
|
||||||
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
|
||||||
&& fn.is_constant_expression(find_scope(compressor)))
|
&& fn.is_constant_expression(find_scope(compressor)))
|
||||||
|
&& all(self.args, function(arg) {
|
||||||
|
return !(arg instanceof AST_Spread);
|
||||||
|
})
|
||||||
&& (value = can_flatten_body(stat))
|
&& (value = can_flatten_body(stat))
|
||||||
&& !fn.contains_this()) {
|
&& !fn.contains_this()) {
|
||||||
var replacing = exp === fn || def.single_use && def.references.length - def.replaced == 1;
|
var replacing = exp === fn || def.single_use && def.references.length - def.replaced == 1;
|
||||||
@@ -7848,19 +7966,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("side_effects")
|
if (compressor.option("side_effects")
|
||||||
|
&& can_drop
|
||||||
&& all(fn.body, is_empty)
|
&& all(fn.body, is_empty)
|
||||||
&& (fn !== exp || fn_name_unused(fn, compressor))
|
&& (fn !== exp || fn_name_unused(fn, compressor))
|
||||||
&& !(fn instanceof AST_Arrow && fn.value)
|
&& !(fn instanceof AST_Arrow && fn.value)) {
|
||||||
&& all(fn.argnames, function(argname) {
|
return make_sequence(self, convert_args()).optimize(compressor);
|
||||||
return !(argname instanceof AST_Destructured);
|
|
||||||
})) {
|
|
||||||
var args = self.args.map(function(arg) {
|
|
||||||
return arg instanceof AST_Spread ? make_node(AST_Array, arg, {
|
|
||||||
elements: [ arg ],
|
|
||||||
}) : arg;
|
|
||||||
});
|
|
||||||
args.push(make_node(AST_Undefined, self));
|
|
||||||
return make_sequence(self, args).optimize(compressor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("drop_console")) {
|
if (compressor.option("drop_console")) {
|
||||||
@@ -7881,6 +7991,19 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return try_evaluate(compressor, self);
|
return try_evaluate(compressor, self);
|
||||||
|
|
||||||
|
function convert_args(value) {
|
||||||
|
var args = self.args.map(function(arg) {
|
||||||
|
return arg instanceof AST_Spread ? make_node(AST_Array, arg, {
|
||||||
|
elements: [ arg ],
|
||||||
|
}) : arg;
|
||||||
|
});
|
||||||
|
fn.argnames.forEach(function(argname, index) {
|
||||||
|
if (argname instanceof AST_DefaultValue) args.push(argname.value);
|
||||||
|
});
|
||||||
|
args.push(value || make_node(AST_Undefined, self));
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
function safe_from_await(node) {
|
function safe_from_await(node) {
|
||||||
if (!is_async(scope || compressor.find_parent(AST_Scope))) return true;
|
if (!is_async(scope || compressor.find_parent(AST_Scope))) return true;
|
||||||
var safe = true;
|
var safe = true;
|
||||||
@@ -7948,6 +8071,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function can_substitute_directly() {
|
function can_substitute_directly() {
|
||||||
|
if (has_default) return;
|
||||||
if (var_assigned) return;
|
if (var_assigned) return;
|
||||||
if (compressor.option("inline") < 2 && fn.argnames.length) return;
|
if (compressor.option("inline") < 2 && fn.argnames.length) return;
|
||||||
if (!fn.variables.all(function(def) {
|
if (!fn.variables.all(function(def) {
|
||||||
@@ -8017,6 +8141,7 @@ merge(Compressor.prototype, {
|
|||||||
for (var i = 0; i < fn.argnames.length; i++) {
|
for (var i = 0; i < fn.argnames.length; i++) {
|
||||||
var arg = fn.argnames[i];
|
var arg = fn.argnames[i];
|
||||||
if (arg.__unused) continue;
|
if (arg.__unused) continue;
|
||||||
|
if (arg instanceof AST_DefaultValue) arg = arg.name;
|
||||||
if (!safe_to_inject || var_exists(defined, arg.name)) return false;
|
if (!safe_to_inject || var_exists(defined, arg.name)) return false;
|
||||||
used[arg.name] = true;
|
used[arg.name] = true;
|
||||||
if (in_loop) in_loop.push(arg.definition());
|
if (in_loop) in_loop.push(arg.definition());
|
||||||
@@ -8115,6 +8240,10 @@ merge(Compressor.prototype, {
|
|||||||
for (i = len; --i >= 0;) {
|
for (i = len; --i >= 0;) {
|
||||||
var name = fn.argnames[i];
|
var name = fn.argnames[i];
|
||||||
var value = self.args[i];
|
var value = self.args[i];
|
||||||
|
if (name instanceof AST_DefaultValue) {
|
||||||
|
value = value ? make_sequence(self, [ value, name.value ]) : name.value;
|
||||||
|
name = name.name;
|
||||||
|
}
|
||||||
if (name.__unused || scope.var_names()[name.name]) {
|
if (name.__unused || scope.var_names()[name.name]) {
|
||||||
if (value) expressions.push(value);
|
if (value) expressions.push(value);
|
||||||
} else {
|
} else {
|
||||||
@@ -8148,6 +8277,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
append_var(decls, expressions, name, var_def.value);
|
append_var(decls, expressions, name, var_def.value);
|
||||||
if (in_loop && all(fn.argnames, function(argname) {
|
if (in_loop && all(fn.argnames, function(argname) {
|
||||||
|
if (argname instanceof AST_DefaultValue) argname = argname.name;
|
||||||
return argname.name != name.name;
|
return argname.name != name.name;
|
||||||
})) {
|
})) {
|
||||||
var def = fn.variables.get(name.name);
|
var def = fn.variables.get(name.name);
|
||||||
@@ -9936,13 +10066,13 @@ merge(Compressor.prototype, {
|
|||||||
var argname = fn.argnames[index];
|
var argname = fn.argnames[index];
|
||||||
if (def.deleted && def.deleted[index]) {
|
if (def.deleted && def.deleted[index]) {
|
||||||
argname = null;
|
argname = null;
|
||||||
} else if (argname instanceof AST_Destructured) {
|
} else if (argname && !(argname instanceof AST_SymbolFunarg)) {
|
||||||
argname = null;
|
argname = null;
|
||||||
} else if (argname && (compressor.has_directive("use strict")
|
} else if (argname && (compressor.has_directive("use strict")
|
||||||
|| fn.name
|
|| fn.name
|
||||||
|| !(fn_parent instanceof AST_Call && index < fn_parent.args.length)
|
|| !(fn_parent instanceof AST_Call && index < fn_parent.args.length)
|
||||||
|| !all(fn.argnames, function(argname) {
|
|| !all(fn.argnames, function(argname) {
|
||||||
return !(argname instanceof AST_Destructured);
|
return argname instanceof AST_SymbolFunarg;
|
||||||
}))) {
|
}))) {
|
||||||
var arg_def = argname.definition();
|
var arg_def = argname.definition();
|
||||||
if (!compressor.option("reduce_vars")
|
if (!compressor.option("reduce_vars")
|
||||||
|
|||||||
@@ -702,6 +702,8 @@ function OutputStream(options) {
|
|||||||
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
// (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
// ==> 20 (side effect, set a := 10 and b := 20)
|
// ==> 20 (side effect, set a := 10 and b := 20)
|
||||||
|| p instanceof AST_Conditional
|
|| p instanceof AST_Conditional
|
||||||
|
// [ a = (1, 2) ] = [] ==> a == 2
|
||||||
|
|| p instanceof AST_DefaultValue
|
||||||
// { [(1, 2)]: 3 }[2] ==> 3
|
// { [(1, 2)]: 3 }[2] ==> 3
|
||||||
// { foo: (1, 2) }.foo ==> 2
|
// { foo: (1, 2) }.foo ==> 2
|
||||||
|| p instanceof AST_DestructuredKeyVal
|
|| p instanceof AST_DestructuredKeyVal
|
||||||
@@ -1218,6 +1220,15 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DEFPRINT(AST_DefaultValue, function(output) {
|
||||||
|
var self = this;
|
||||||
|
self.name.print(output);
|
||||||
|
output.space();
|
||||||
|
output.print("=");
|
||||||
|
output.space();
|
||||||
|
self.value.print(output);
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ other expressions ]----- */
|
/* -----[ other expressions ]----- */
|
||||||
function print_call_args(self, output) {
|
function print_call_args(self, output) {
|
||||||
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {
|
||||||
|
|||||||
109
lib/parse.js
109
lib/parse.js
@@ -1041,11 +1041,30 @@ function parse($TEXT, options) {
|
|||||||
function to_funarg(node) {
|
function to_funarg(node) {
|
||||||
if (node instanceof AST_Array) return new AST_DestructuredArray({
|
if (node instanceof AST_Array) return new AST_DestructuredArray({
|
||||||
start: node.start,
|
start: node.start,
|
||||||
elements: node.elements.map(function(node) {
|
elements: node.elements.map(to_funarg),
|
||||||
return node instanceof AST_Hole ? node : to_funarg(node);
|
|
||||||
}),
|
|
||||||
end: node.end,
|
end: node.end,
|
||||||
});
|
});
|
||||||
|
if (node instanceof AST_Assign) return new AST_DefaultValue({
|
||||||
|
start: node.start,
|
||||||
|
name: to_funarg(node.left),
|
||||||
|
value: node.right,
|
||||||
|
end: node.end,
|
||||||
|
});
|
||||||
|
if (node instanceof AST_DefaultValue) {
|
||||||
|
node.name = to_funarg(node.name);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_DestructuredArray) {
|
||||||
|
node.elements = node.elements.map(to_funarg);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_DestructuredObject) {
|
||||||
|
node.properties.forEach(function(prop) {
|
||||||
|
prop.value = to_funarg(prop.value);
|
||||||
|
});
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Hole) return node;
|
||||||
if (node instanceof AST_Object) return new AST_DestructuredObject({
|
if (node instanceof AST_Object) return new AST_DestructuredObject({
|
||||||
start: node.start,
|
start: node.start,
|
||||||
properties: node.properties.map(function(prop) {
|
properties: node.properties.map(function(prop) {
|
||||||
@@ -1122,7 +1141,7 @@ function parse($TEXT, options) {
|
|||||||
var was_funarg = S.in_funarg;
|
var was_funarg = S.in_funarg;
|
||||||
S.in_funarg = S.in_function;
|
S.in_funarg = S.in_function;
|
||||||
var argnames = expr_list(")", !options.strict, false, function() {
|
var argnames = expr_list(")", !options.strict, false, function() {
|
||||||
return maybe_destructured(AST_SymbolFunarg);
|
return maybe_default(AST_SymbolFunarg);
|
||||||
});
|
});
|
||||||
S.in_funarg = was_funarg;
|
S.in_funarg = was_funarg;
|
||||||
var loop = S.in_loop;
|
var loop = S.in_loop;
|
||||||
@@ -1468,6 +1487,32 @@ function parse($TEXT, options) {
|
|||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (is_token(peek(), "operator", "=")) {
|
||||||
|
var name = as_symbol(AST_SymbolRef);
|
||||||
|
next();
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: start.value,
|
||||||
|
value: new AST_Assign({
|
||||||
|
start: start,
|
||||||
|
left: name,
|
||||||
|
operator: "=",
|
||||||
|
right: maybe_assign(),
|
||||||
|
end: prev(),
|
||||||
|
}),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_token(peek(), "punc", ",") || is_token(peek(), "punc", "}")) {
|
||||||
|
a.push(new AST_ObjectKeyVal({
|
||||||
|
start: start,
|
||||||
|
key: start.value,
|
||||||
|
value: as_symbol(AST_SymbolRef),
|
||||||
|
end: prev(),
|
||||||
|
}));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var key = as_property_key();
|
var key = as_property_key();
|
||||||
if (is("punc", "(")) {
|
if (is("punc", "(")) {
|
||||||
var func_start = S.token;
|
var func_start = S.token;
|
||||||
@@ -1492,15 +1537,6 @@ function parse($TEXT, options) {
|
|||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (is("punc", ",") || is("punc", "}")) {
|
|
||||||
a.push(new AST_ObjectKeyVal({
|
|
||||||
start: start,
|
|
||||||
key: key,
|
|
||||||
value: _make_symbol(AST_SymbolRef, start),
|
|
||||||
end: prev(),
|
|
||||||
}));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (start.type == "name") switch (key) {
|
if (start.type == "name") switch (key) {
|
||||||
case "async":
|
case "async":
|
||||||
key = as_property_key();
|
key = as_property_key();
|
||||||
@@ -1601,7 +1637,7 @@ function parse($TEXT, options) {
|
|||||||
return new AST_DestructuredArray({
|
return new AST_DestructuredArray({
|
||||||
start: start,
|
start: start,
|
||||||
elements: expr_list("]", !options.strict, true, function() {
|
elements: expr_list("]", !options.strict, true, function() {
|
||||||
return maybe_destructured(type);
|
return maybe_default(type);
|
||||||
}),
|
}),
|
||||||
end: prev(),
|
end: prev(),
|
||||||
});
|
});
|
||||||
@@ -1620,15 +1656,25 @@ function parse($TEXT, options) {
|
|||||||
a.push(new AST_DestructuredKeyVal({
|
a.push(new AST_DestructuredKeyVal({
|
||||||
start: key_start,
|
start: key_start,
|
||||||
key: key,
|
key: key,
|
||||||
value: maybe_destructured(type),
|
value: maybe_default(type),
|
||||||
end: prev(),
|
end: prev(),
|
||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var name = as_symbol(type);
|
||||||
|
if (is("operator", "=")) {
|
||||||
|
next();
|
||||||
|
name = new AST_DefaultValue({
|
||||||
|
start: name.start,
|
||||||
|
name: name,
|
||||||
|
value: maybe_assign(),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
a.push(new AST_DestructuredKeyVal({
|
a.push(new AST_DestructuredKeyVal({
|
||||||
start: key_start,
|
start: key_start,
|
||||||
key: key_start.value,
|
key: key_start.value,
|
||||||
value: as_symbol(type),
|
value: name,
|
||||||
end: prev(),
|
end: prev(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -1642,6 +1688,19 @@ function parse($TEXT, options) {
|
|||||||
return as_symbol(type);
|
return as_symbol(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybe_default(type) {
|
||||||
|
var start = S.token;
|
||||||
|
var name = maybe_destructured(type);
|
||||||
|
if (!is("operator", "=")) return name;
|
||||||
|
next();
|
||||||
|
return new AST_DefaultValue({
|
||||||
|
start: start,
|
||||||
|
name: name,
|
||||||
|
value: maybe_assign(),
|
||||||
|
end: prev(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function mark_pure(call) {
|
function mark_pure(call) {
|
||||||
var start = call.start;
|
var start = call.start;
|
||||||
var comments = start.comments_before;
|
var comments = start.comments_before;
|
||||||
@@ -1788,20 +1847,34 @@ function parse($TEXT, options) {
|
|||||||
if (node instanceof AST_Array) {
|
if (node instanceof AST_Array) {
|
||||||
var elements = node.elements.map(to_destructured);
|
var elements = node.elements.map(to_destructured);
|
||||||
return all(elements, function(node) {
|
return all(elements, function(node) {
|
||||||
return node instanceof AST_Destructured || node instanceof AST_Hole || is_assignable(node);
|
return node instanceof AST_DefaultValue
|
||||||
|
|| node instanceof AST_Destructured
|
||||||
|
|| node instanceof AST_Hole
|
||||||
|
|| is_assignable(node);
|
||||||
}) ? new AST_DestructuredArray({
|
}) ? new AST_DestructuredArray({
|
||||||
start: node.start,
|
start: node.start,
|
||||||
elements: elements,
|
elements: elements,
|
||||||
end: node.end,
|
end: node.end,
|
||||||
}) : node;
|
}) : node;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Assign) {
|
||||||
|
var name = to_destructured(node.left);
|
||||||
|
return name instanceof AST_Destructured || is_assignable(name) ? new AST_DefaultValue({
|
||||||
|
start: node.start,
|
||||||
|
name: name,
|
||||||
|
value: node.right,
|
||||||
|
end: node.end,
|
||||||
|
}) : node;
|
||||||
|
}
|
||||||
if (!(node instanceof AST_Object)) return node;
|
if (!(node instanceof AST_Object)) return node;
|
||||||
var props = [];
|
var props = [];
|
||||||
for (var i = 0; i < node.properties.length; i++) {
|
for (var i = 0; i < node.properties.length; i++) {
|
||||||
var prop = node.properties[i];
|
var prop = node.properties[i];
|
||||||
if (!(prop instanceof AST_ObjectKeyVal)) return node;
|
if (!(prop instanceof AST_ObjectKeyVal)) return node;
|
||||||
var value = to_destructured(prop.value);
|
var value = to_destructured(prop.value);
|
||||||
if (!(value instanceof AST_Destructured || is_assignable(value))) return node;
|
if (!(value instanceof AST_DefaultValue || value instanceof AST_Destructured || is_assignable(value))) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
props.push(new AST_DestructuredKeyVal({
|
props.push(new AST_DestructuredKeyVal({
|
||||||
start: prop.start,
|
start: prop.start,
|
||||||
key: prop.key,
|
key: prop.key,
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
self.name = self.name.transform(tw);
|
self.name = self.name.transform(tw);
|
||||||
if (self.value) self.value = self.value.transform(tw);
|
if (self.value) self.value = self.value.transform(tw);
|
||||||
});
|
});
|
||||||
|
DEF(AST_DefaultValue, function(self, tw) {
|
||||||
|
self.name = self.name.transform(tw);
|
||||||
|
self.value = self.value.transform(tw);
|
||||||
|
});
|
||||||
DEF(AST_Lambda, function(self, tw) {
|
DEF(AST_Lambda, function(self, tw) {
|
||||||
if (self.name) self.name = self.name.transform(tw);
|
if (self.name) self.name = self.name.transform(tw);
|
||||||
self.argnames = do_list(self.argnames, tw);
|
self.argnames = do_list(self.argnames, tw);
|
||||||
|
|||||||
952
test/compress/default-values.js
Normal file
952
test/compress/default-values.js
Normal file
@@ -0,0 +1,952 @@
|
|||||||
|
arrow_1: {
|
||||||
|
input: {
|
||||||
|
console.log(((a = "PASS") => a)());
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log(((a="PASS")=>a)());'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
arrow_2: {
|
||||||
|
input: {
|
||||||
|
console.log((([ a = "FAIL" ]) => a)([ "PASS" ]));
|
||||||
|
}
|
||||||
|
expect_exact: 'console.log((([a="FAIL"])=>a)(["PASS"]));'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
arrow_3: {
|
||||||
|
input: {
|
||||||
|
(([ a = console ] = null) => a.log("PASS"))("");
|
||||||
|
}
|
||||||
|
expect_exact: '(([a=console]=null)=>a.log("PASS"))("");'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
assign: {
|
||||||
|
input: {
|
||||||
|
[ a = "PASS" ] = [];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_exact: '[a="PASS"]=[];console.log(a);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration_var: {
|
||||||
|
input: {
|
||||||
|
var [ a = "PASS" ] = [ , ];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_exact: 'var[a="PASS"]=[,];console.log(a);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration_const: {
|
||||||
|
input: {
|
||||||
|
const [ a = "FAIL" ] = [ "PASS" ];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_exact: 'const[a="FAIL"]=["PASS"];console.log(a);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
declaration_let: {
|
||||||
|
input: {
|
||||||
|
let [ a = "PASS" ] = [ void 42 ];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_exact: 'let[a="PASS"]=[void 42];console.log(a);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_shorthand_assign: {
|
||||||
|
input: {
|
||||||
|
({ a = "PASS" } = 42);
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_exact: '({a:a="PASS"}=42);console.log(a);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_shorthand_declaration: {
|
||||||
|
input: {
|
||||||
|
var { a = "PASS" } = 42;
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_exact: 'var{a:a="PASS"}=42;console.log(a);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
object_shorthand_function: {
|
||||||
|
input: {
|
||||||
|
(function({ a = "PASS" }) {
|
||||||
|
console.log(a);
|
||||||
|
})(42);
|
||||||
|
}
|
||||||
|
expect_exact: '(function({a:a="PASS"}){console.log(a)})(42);'
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
retain_arguments_1: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = "FAIL") {
|
||||||
|
return arguments[0];
|
||||||
|
}() || "PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a = "FAIL") {
|
||||||
|
return arguments[0];
|
||||||
|
}() || "PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
retain_arguments_2: {
|
||||||
|
options = {
|
||||||
|
arguments: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a, b = null) {
|
||||||
|
a = "FAIL";
|
||||||
|
return arguments[0];
|
||||||
|
}("PASS", 42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a, b = null) {
|
||||||
|
a = "FAIL";
|
||||||
|
return arguments[0];
|
||||||
|
}("PASS", 42));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
process_boolean_returns: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = console.log("FAIL 1")) {
|
||||||
|
return a() ? "PASS" : "FAIL 2";
|
||||||
|
}(function() {
|
||||||
|
return 42;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a = console.log("FAIL 1")) {
|
||||||
|
return a() ? "PASS" : "FAIL 2";
|
||||||
|
}(function() {
|
||||||
|
return 1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_value_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = "PASS") {
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return "PASS";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
collapse_value_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a = console) {
|
||||||
|
return a;
|
||||||
|
})().log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(a) {
|
||||||
|
return console;
|
||||||
|
})().log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
flatten_if: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (console.log("PASS")) {
|
||||||
|
var [
|
||||||
|
a = function b() {
|
||||||
|
for (c in b);
|
||||||
|
},
|
||||||
|
] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
console.log("PASS") && ([
|
||||||
|
a = function b() {
|
||||||
|
for (c in b);
|
||||||
|
},
|
||||||
|
] = 0);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
maintain_if: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
if (a)
|
||||||
|
for (;;);
|
||||||
|
else
|
||||||
|
var [ a = "PASS" ] = [];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
if (a)
|
||||||
|
for (;;);
|
||||||
|
else
|
||||||
|
var [ a = "PASS" ] = [];
|
||||||
|
console.log(a);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce_value: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = "PASS") {
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate_iife: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = "PASS") {
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_iife_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function([ a ] = []) {
|
||||||
|
return "PASS";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function([ a ] = []) {
|
||||||
|
return "PASS";
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe_evaluate_iife_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function([ a ] = []) {
|
||||||
|
return a[0];
|
||||||
|
}([ [ "PASS" ] ]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function([ a ] = []) {
|
||||||
|
return a[0];
|
||||||
|
}([ [ "PASS" ] ]));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_direct: {
|
||||||
|
options = {
|
||||||
|
default_values: true,
|
||||||
|
inline: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = "FAIL") {
|
||||||
|
return a;
|
||||||
|
}("PASS"));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_constant: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = console.log("foo")) {
|
||||||
|
return "bar";
|
||||||
|
}(void console.log("baz")));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((void console.log("baz"), console.log("foo"), "bar"));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"baz",
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_function: {
|
||||||
|
options = {
|
||||||
|
default_values: true,
|
||||||
|
inline: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function(a = console.log("foo"), b = console.log("bar")) {
|
||||||
|
console.log("baz");
|
||||||
|
}(void console.log("moo"), 42));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("moo"),
|
||||||
|
console.log("foo"),
|
||||||
|
console.log("baz");
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"moo",
|
||||||
|
"foo",
|
||||||
|
"baz",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_loop_1: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (function f(a = "PASS") {
|
||||||
|
console.log(a);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
while (a = "PASS", void console.log(a));
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline_loop_2: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
while (function(a = [ "PASS" ]) {
|
||||||
|
var a = function f(b) {
|
||||||
|
console.log(a[b]);
|
||||||
|
}(0);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
while (a = [ "PASS" ], a = function f(b) {
|
||||||
|
console.log(a[b]);
|
||||||
|
}(0), void 0) ;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_empty_iife: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = console.log("foo")) {}(void console.log("baz")));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log((console.log("baz"), void console.log("foo")));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"baz",
|
||||||
|
"foo",
|
||||||
|
"undefined",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
retain_empty_iife: {
|
||||||
|
options = {
|
||||||
|
side_effects: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
try {
|
||||||
|
(function(a = a) {})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
try {
|
||||||
|
(function(a = a) {})();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
retain_fargs: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function([ a = console.log("PASS") ]) {})([]);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function([ a = console.log("PASS") ]) {})([]);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_fargs: {
|
||||||
|
options = {
|
||||||
|
keep_fargs: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a = 42, b = console.log("foo"), c = true) {
|
||||||
|
return "bar";
|
||||||
|
}(console.log("baz"), "moo", false));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(b = console.log("foo")) {
|
||||||
|
return "bar";
|
||||||
|
}((console.log("baz"), "moo")));
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"baz",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Dropping unused function argument c [test/compress/default-values.js:1,61]",
|
||||||
|
"WARN: Side effects in default value of unused variable b [test/compress/default-values.js:1,37]",
|
||||||
|
]
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
unused_var_1: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var [ a = 42 ] = [ console.log("PASS") ];
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
unused_var_2: {
|
||||||
|
options = {
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var {
|
||||||
|
p: [ a ] = "" + console.log("FAIL"),
|
||||||
|
} = {
|
||||||
|
p: [ console.log("PASS") ],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var {
|
||||||
|
p: [] = [ console.log("FAIL") ],
|
||||||
|
} = {
|
||||||
|
p: [ console.log("PASS") ],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_var_1: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1, [ {
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
} ] = [ {}, {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(v);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var N = 1, [ {
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
} ] = [ {}, {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(v);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_var_1_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1, [ {
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
} ] = [ {}, {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(v);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = 1, [ {
|
||||||
|
pname: a = "x",
|
||||||
|
i: e = o,
|
||||||
|
}, {
|
||||||
|
[a + e]: l,
|
||||||
|
} ] = [ {}, {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(l);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_var_2: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1, [ {
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
} = {}, {
|
||||||
|
[p + n]: v,
|
||||||
|
} ] = [ , {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(v);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var N = 1, [ {
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
} = {}, {
|
||||||
|
[p + n]: v,
|
||||||
|
} ] = [ , {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(v);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_var_2_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1, [ {
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
} = {}, {
|
||||||
|
[p + n]: v,
|
||||||
|
} ] = [ , {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(v);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = 1, [ {
|
||||||
|
pname: a = "x",
|
||||||
|
i: e = o,
|
||||||
|
} = {}, {
|
||||||
|
[a + e]: l,
|
||||||
|
} ] = [ , {
|
||||||
|
x1: "PASS",
|
||||||
|
} ];
|
||||||
|
console.log(l);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_function_1: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
(function(o, {
|
||||||
|
pname: p,
|
||||||
|
} = o, {
|
||||||
|
[p + N]: v,
|
||||||
|
} = o) {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var N = 1;
|
||||||
|
(function(n, {
|
||||||
|
pname: e,
|
||||||
|
} = n, {
|
||||||
|
[e + N]: o,
|
||||||
|
} = n) {
|
||||||
|
let a;
|
||||||
|
console.log(o);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_function_1_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
(function(o, {
|
||||||
|
pname: p,
|
||||||
|
} = o, {
|
||||||
|
[p + N]: v,
|
||||||
|
} = o) {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var l = 1;
|
||||||
|
(function(n, {
|
||||||
|
pname: e,
|
||||||
|
} = n, {
|
||||||
|
[e + l]: o,
|
||||||
|
} = n) {
|
||||||
|
let a;
|
||||||
|
console.log(o);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_function_2: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
(function({
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
}) {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var N = 1;
|
||||||
|
(function({
|
||||||
|
pname: n = "x",
|
||||||
|
i: o = N,
|
||||||
|
}, {
|
||||||
|
[n + o]: e,
|
||||||
|
}) {
|
||||||
|
let l;
|
||||||
|
console.log(e);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_function_2_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
(function({
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
}) {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 1;
|
||||||
|
(function({
|
||||||
|
pname: n = "x",
|
||||||
|
i: o = a,
|
||||||
|
}, {
|
||||||
|
[n + o]: e,
|
||||||
|
}) {
|
||||||
|
let l;
|
||||||
|
console.log(e);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_arrow_1: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
((o, {
|
||||||
|
pname: p,
|
||||||
|
} = o, {
|
||||||
|
[p + N]: v,
|
||||||
|
} = o) => {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var N = 1;
|
||||||
|
((e, {
|
||||||
|
pname: a,
|
||||||
|
} = e, {
|
||||||
|
[a + N]: l,
|
||||||
|
} = e) => {
|
||||||
|
let n;
|
||||||
|
console.log(l);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_arrow_1_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
((o, {
|
||||||
|
pname: p,
|
||||||
|
} = o, {
|
||||||
|
[p + N]: v,
|
||||||
|
} = o) => {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = 1;
|
||||||
|
((e, {
|
||||||
|
pname: a,
|
||||||
|
} = e, {
|
||||||
|
[a + o]: l,
|
||||||
|
} = e) => {
|
||||||
|
let n;
|
||||||
|
console.log(l);
|
||||||
|
})({
|
||||||
|
pname: "x",
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_arrow_2: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
(({
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
}) => {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var N = 1;
|
||||||
|
(({
|
||||||
|
pname: e = "x",
|
||||||
|
i: l = N,
|
||||||
|
}, {
|
||||||
|
[e + l]: o,
|
||||||
|
}) => {
|
||||||
|
let a;
|
||||||
|
console.log(o);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_arrow_2_toplevel: {
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var N = 1;
|
||||||
|
(({
|
||||||
|
pname: p = "x",
|
||||||
|
i: n = N,
|
||||||
|
}, {
|
||||||
|
[p + n]: v,
|
||||||
|
}) => {
|
||||||
|
let N;
|
||||||
|
console.log(v);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var n = 1;
|
||||||
|
(({
|
||||||
|
pname: e = "x",
|
||||||
|
i: l = n,
|
||||||
|
}, {
|
||||||
|
[e + l]: o,
|
||||||
|
}) => {
|
||||||
|
let a;
|
||||||
|
console.log(o);
|
||||||
|
})({}, {
|
||||||
|
x1: "PASS",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
@@ -691,6 +691,28 @@ funarg_inline: {
|
|||||||
node_version: ">=6"
|
node_version: ">=6"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process_boolean_returns: {
|
||||||
|
options = {
|
||||||
|
booleans: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function({ length }) {
|
||||||
|
return length ? "FAIL" : "PASS";
|
||||||
|
}(function() {
|
||||||
|
return 42;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function({ length }) {
|
||||||
|
return length ? "FAIL" : "PASS";
|
||||||
|
}(function() {
|
||||||
|
return 42;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
|
|
||||||
simple_const: {
|
simple_const: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ var UglifyJS = require("../node");
|
|||||||
|
|
||||||
describe("Getters and setters", function() {
|
describe("Getters and setters", function() {
|
||||||
it("Should not accept operator symbols as getter/setter name", function() {
|
it("Should not accept operator symbols as getter/setter name", function() {
|
||||||
var illegalOperators = [
|
[
|
||||||
"++",
|
"++",
|
||||||
"--",
|
"--",
|
||||||
"+",
|
"+",
|
||||||
@@ -42,43 +42,26 @@ describe("Getters and setters", function() {
|
|||||||
"&=",
|
"&=",
|
||||||
"&&",
|
"&&",
|
||||||
"||"
|
"||"
|
||||||
];
|
].reduce(function(tests, illegalOperator) {
|
||||||
var generator = function() {
|
tests.push({
|
||||||
var results = [];
|
code: "var obj = { get " + illegalOperator + "() { return test; }};",
|
||||||
|
operator: illegalOperator,
|
||||||
for (var i in illegalOperators) {
|
});
|
||||||
results.push({
|
tests.push({
|
||||||
code: "var obj = { get " + illegalOperators[i] + "() { return test; }};",
|
code: "var obj = { set " + illegalOperator + "(value) { test = value; }};",
|
||||||
operator: illegalOperators[i],
|
operator: illegalOperator,
|
||||||
method: "get"
|
});
|
||||||
});
|
return tests;
|
||||||
results.push({
|
}, []).forEach(function(test) {
|
||||||
code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};",
|
assert.throws(function() {
|
||||||
operator: illegalOperators[i],
|
UglifyJS.parse(test.code);
|
||||||
method: "set"
|
}, test.operator == "=" ? function(e) {
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
var testCase = function(data) {
|
|
||||||
return function() {
|
|
||||||
UglifyJS.parse(data.code);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
var fail = function(data) {
|
|
||||||
return function(e) {
|
|
||||||
return e instanceof UglifyJS.JS_Parse_Error
|
return e instanceof UglifyJS.JS_Parse_Error
|
||||||
&& e.message === "Unexpected token: operator «" + data.operator + "»";
|
&& /^Unexpected token: punc «{», expected: punc «.*?»$/.test(e.message);
|
||||||
};
|
} : function(e) {
|
||||||
};
|
return e instanceof UglifyJS.JS_Parse_Error
|
||||||
var errorMessage = function(data) {
|
&& e.message === "Unexpected token: operator «" + test.operator + "»";
|
||||||
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
|
}, "Expected but didn't get a syntax error while parsing following line:\n" + test.code);
|
||||||
};
|
});
|
||||||
var tests = generator();
|
|
||||||
for (var i = 0; i < tests.length; i++) {
|
|
||||||
var test = tests[i];
|
|
||||||
assert.throws(testCase(test), fail(test), errorMessage(test));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -211,6 +211,11 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
|||||||
node.alternative,
|
node.alternative,
|
||||||
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
][ ((node.start._permute += step) * steps | 0) % 3 ];
|
||||||
}
|
}
|
||||||
|
else if (node instanceof U.AST_DefaultValue) {
|
||||||
|
node.start._permute++;
|
||||||
|
CHANGED = true;
|
||||||
|
return node.name;
|
||||||
|
}
|
||||||
else if (node instanceof U.AST_Defun) {
|
else if (node instanceof U.AST_Defun) {
|
||||||
switch (((node.start._permute += step) * steps | 0) % 2) {
|
switch (((node.start._permute += step) * steps | 0) % 2) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ var SUPPORT = function(matrix) {
|
|||||||
catch_omit_var: "try {} catch {}",
|
catch_omit_var: "try {} catch {}",
|
||||||
computed_key: "({[0]: 0});",
|
computed_key: "({[0]: 0});",
|
||||||
const_block: "var a; { const a = 0; }",
|
const_block: "var a; { const a = 0; }",
|
||||||
|
default_value: "[ a = 0 ] = [];",
|
||||||
destructuring: "[] = [];",
|
destructuring: "[] = [];",
|
||||||
let: "let a;",
|
let: "let a;",
|
||||||
spread: "[...[]];",
|
spread: "[...[]];",
|
||||||
@@ -425,18 +426,35 @@ function createArgs(recurmax, stmtDepth, canThrow) {
|
|||||||
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async) {
|
function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was_async) {
|
||||||
var avoid = [];
|
var avoid = [];
|
||||||
var len = unique_vars.length;
|
var len = unique_vars.length;
|
||||||
var pairs = createPairs(recurmax);
|
var pairs = createPairs(recurmax, !nameLenBefore);
|
||||||
unique_vars.length = len;
|
unique_vars.length = len;
|
||||||
return pairs;
|
return pairs;
|
||||||
|
|
||||||
function createAssignmentValue(recurmax) {
|
function fill(nameFn, valueFn) {
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
if (was_async != null) async = was_async;
|
if (was_async != null) {
|
||||||
|
async = false;
|
||||||
|
if (save_async || was_async) addAvoidVar("await");
|
||||||
|
}
|
||||||
|
avoid.forEach(addAvoidVar);
|
||||||
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
||||||
var value = nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
if (nameFn) nameFn();
|
||||||
|
if (was_async != null) {
|
||||||
|
async = was_async;
|
||||||
|
if (save_async || was_async) removeAvoidVar("await");
|
||||||
|
}
|
||||||
|
if (valueFn) valueFn();
|
||||||
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
||||||
|
avoid.forEach(removeAvoidVar);
|
||||||
async = save_async;
|
async = save_async;
|
||||||
return value;
|
}
|
||||||
|
|
||||||
|
function createAssignmentValue(recurmax) {
|
||||||
|
return nameLenBefore && rng(2) ? createValue() : createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDefaultValue(recurmax, noDefault) {
|
||||||
|
return !noDefault && SUPPORT.default_value && rng(20) == 0 ? " = " + createAssignmentValue(recurmax) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function createKey(recurmax, keys) {
|
function createKey(recurmax, keys) {
|
||||||
@@ -459,20 +477,22 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createPairs(recurmax) {
|
function createPairs(recurmax, noDefault) {
|
||||||
var names = [], values = [];
|
var names = [], values = [];
|
||||||
var m = rng(4), n = rng(4);
|
var m = rng(4), n = rng(4);
|
||||||
if (!nameLenBefore) m = Math.max(m, n, 1);
|
if (!nameLenBefore) m = Math.max(m, n, 1);
|
||||||
for (var i = Math.max(m, n); --i >= 0;) {
|
for (var i = Math.max(m, n); --i >= 0;) {
|
||||||
if (i < m && i < n) {
|
if (i < m && i < n) {
|
||||||
createDestructured(recurmax, names, values);
|
createDestructured(recurmax, noDefault, names, values);
|
||||||
continue;
|
} else if (i < m) {
|
||||||
}
|
var name = createName();
|
||||||
if (i < m) {
|
fill(function() {
|
||||||
names.unshift(createName());
|
names.unshift(name + createDefaultValue(recurmax, noDefault));
|
||||||
}
|
});
|
||||||
if (i < n) {
|
} else {
|
||||||
values.unshift(createAssignmentValue(recurmax));
|
fill(null, function() {
|
||||||
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -481,7 +501,7 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDestructured(recurmax, names, values) {
|
function createDestructured(recurmax, noDefault, names, values) {
|
||||||
switch (rng(20)) {
|
switch (rng(20)) {
|
||||||
case 0:
|
case 0:
|
||||||
if (--recurmax < 0) {
|
if (--recurmax < 0) {
|
||||||
@@ -489,20 +509,25 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
values.unshift('""');
|
values.unshift('""');
|
||||||
} else {
|
} else {
|
||||||
var pairs = createPairs(recurmax);
|
var pairs = createPairs(recurmax);
|
||||||
while (!rng(10)) {
|
var default_value;
|
||||||
var index = rng(pairs.names.length + 1);
|
fill(function() {
|
||||||
pairs.names.splice(index, 0, "");
|
default_value = createDefaultValue(recurmax, noDefault);
|
||||||
if (index < pairs.values.length) {
|
}, function() {
|
||||||
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
while (!rng(10)) {
|
||||||
} else switch (rng(5)) {
|
var index = rng(pairs.names.length + 1);
|
||||||
case 0:
|
pairs.names.splice(index, 0, "");
|
||||||
pairs.values[index] = createAssignmentValue(recurmax);
|
if (index < pairs.values.length) {
|
||||||
case 1:
|
pairs.values.splice(index, 0, rng(2) ? createAssignmentValue(recurmax) : "");
|
||||||
pairs.values.length = index + 1;
|
} else switch (rng(5)) {
|
||||||
|
case 0:
|
||||||
|
pairs.values[index] = createAssignmentValue(recurmax);
|
||||||
|
case 1:
|
||||||
|
pairs.values.length = index + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
names.unshift("[ " + pairs.names.join(", ") + " ]" + default_value);
|
||||||
names.unshift("[ " + pairs.names.join(", ") + " ]");
|
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
||||||
values.unshift("[ " + pairs.values.join(", ") + " ]");
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@@ -521,33 +546,26 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
keys[index] = key;
|
keys[index] = key;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var save_async = async;
|
fill(function() {
|
||||||
if (was_async != null) {
|
names.unshift("{ " + addTrailingComma(pairs.names.map(function(name, index) {
|
||||||
async = false;
|
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
||||||
if (save_async || was_async) avoid.push("await");
|
return key ? key + ": " + name : name;
|
||||||
}
|
}).join(", ")) + " }" + createDefaultValue(recurmax, noDefault));
|
||||||
addAvoidVars(avoid);
|
}, function() {
|
||||||
var save_vars = nameLenBefore && VAR_NAMES.splice(nameLenBefore);
|
values.unshift("{ " + addTrailingComma(pairs.values.map(function(value, index) {
|
||||||
names.unshift("{ " + addTrailingComma(pairs.names.map(function(name, index) {
|
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
||||||
var key = index in keys ? keys[index] : rng(10) && createKey(recurmax, keys);
|
return key + ": " + value;
|
||||||
return key ? key + ": " + name : name;
|
}).join(", ")) + " }");
|
||||||
}).join(", ")) + " }");
|
});
|
||||||
if (was_async != null) {
|
|
||||||
async = was_async;
|
|
||||||
if (save_async || was_async) removeAvoidVars([ avoid.pop() ]);
|
|
||||||
}
|
|
||||||
values.unshift("{ " + addTrailingComma(pairs.values.map(function(value, index) {
|
|
||||||
var key = index in keys ? keys[index] : createKey(recurmax, keys);
|
|
||||||
return key + ": " + value;
|
|
||||||
}).join(", ")) + " }");
|
|
||||||
if (save_vars) [].push.apply(VAR_NAMES, save_vars);
|
|
||||||
removeAvoidVars(avoid);
|
|
||||||
async = save_async;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
names.unshift(createName());
|
var name = createName();
|
||||||
values.unshift(createAssignmentValue(recurmax));
|
fill(function() {
|
||||||
|
names.unshift(name + createDefaultValue(recurmax, noDefault));
|
||||||
|
}, function() {
|
||||||
|
values.unshift(createAssignmentValue(recurmax));
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -575,8 +593,8 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
}
|
}
|
||||||
unique_vars.length -= 6;
|
unique_vars.length -= 6;
|
||||||
fn(function() {
|
fn(function() {
|
||||||
addAvoidVars(consts);
|
consts.forEach(addAvoidVar);
|
||||||
addAvoidVars(lets);
|
lets.forEach(addAvoidVar);
|
||||||
if (rng(2)) {
|
if (rng(2)) {
|
||||||
return createDefinitions("const", consts) + "\n" + createDefinitions("let", lets) + "\n";
|
return createDefinitions("const", consts) + "\n" + createDefinitions("let", lets) + "\n";
|
||||||
} else {
|
} else {
|
||||||
@@ -610,17 +628,17 @@ function createBlockVariables(recurmax, stmtDepth, canThrow, fn) {
|
|||||||
default:
|
default:
|
||||||
s += names.map(function(name) {
|
s += names.map(function(name) {
|
||||||
if (type == "let" && !rng(10)) {
|
if (type == "let" && !rng(10)) {
|
||||||
removeAvoidVars([ name ]);
|
removeAvoidVar(name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow);
|
||||||
removeAvoidVars([ name ]);
|
removeAvoidVar(name);
|
||||||
return name + " = " + value;
|
return name + " = " + value;
|
||||||
}).join(", ") + ";";
|
}).join(", ") + ";";
|
||||||
names.length = 0;
|
names.length = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
removeAvoidVars(names);
|
names.forEach(removeAvoidVar);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -877,9 +895,9 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
unique_vars.length -= 6;
|
unique_vars.length -= 6;
|
||||||
if (SUPPORT.computed_key && rng(10) == 0) {
|
if (SUPPORT.computed_key && rng(10) == 0) {
|
||||||
s += " catch ({ message: " + message + ", ";
|
s += " catch ({ message: " + message + ", ";
|
||||||
addAvoidVars([ name ]);
|
addAvoidVar(name);
|
||||||
s += "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]: " + name;
|
s += "[" + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + "]: " + name;
|
||||||
removeAvoidVars([ name ]);
|
removeAvoidVar(name);
|
||||||
s += " }) { ";
|
s += " }) { ";
|
||||||
} else {
|
} else {
|
||||||
s += " catch ({ name: " + name + ", message: " + message + " }) { ";
|
s += " catch ({ name: " + name + ", message: " + message + " }) { ";
|
||||||
@@ -1483,15 +1501,13 @@ function createUnaryPostfix() {
|
|||||||
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAvoidVars(names) {
|
function addAvoidVar(name) {
|
||||||
avoid_vars = avoid_vars.concat(names);
|
avoid_vars.push(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeAvoidVars(names) {
|
function removeAvoidVar(name) {
|
||||||
names.forEach(function(name) {
|
var index = avoid_vars.lastIndexOf(name);
|
||||||
var index = avoid_vars.lastIndexOf(name);
|
if (index >= 0) avoid_vars.splice(index, 1);
|
||||||
if (index >= 0) avoid_vars.splice(index, 1);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVarName(noConst) {
|
function getVarName(noConst) {
|
||||||
@@ -1799,6 +1815,8 @@ for (var round = 1; round <= num_iterations; round++) {
|
|||||||
var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ];
|
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) {
|
if (errored) {
|
||||||
|
println();
|
||||||
|
println();
|
||||||
println("//=============================================================");
|
println("//=============================================================");
|
||||||
println("// original code");
|
println("// original code");
|
||||||
try_beautify(original_code, false, orig_result[0], println);
|
try_beautify(original_code, false, orig_result[0], println);
|
||||||
|
|||||||
Reference in New Issue
Block a user