fix merge
This commit is contained in:
parent
af167f0ede
commit
352bdaecb6
419
lib/compress.js
419
lib/compress.js
|
|
@ -99,10 +99,10 @@ function Compressor(options, false_by_default) {
|
||||||
this.top_retain = function(def) {
|
this.top_retain = function(def) {
|
||||||
return top_retain.test(def.name);
|
return top_retain.test(def.name);
|
||||||
};
|
};
|
||||||
} else if (typeof top_retain === "function") {
|
} else if (typeof top_retain == "function") {
|
||||||
this.top_retain = top_retain;
|
this.top_retain = top_retain;
|
||||||
} else if (top_retain) {
|
} else if (top_retain) {
|
||||||
if (typeof top_retain === "string") {
|
if (typeof top_retain == "string") {
|
||||||
top_retain = top_retain.split(/,/);
|
top_retain = top_retain.split(/,/);
|
||||||
}
|
}
|
||||||
this.top_retain = function(def) {
|
this.top_retain = function(def) {
|
||||||
|
|
@ -152,14 +152,25 @@ merge(Compressor.prototype, {
|
||||||
node = node.hoist_declarations(this);
|
node = node.hoist_declarations(this);
|
||||||
was_scope = true;
|
was_scope = true;
|
||||||
}
|
}
|
||||||
|
// Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize()
|
||||||
|
// would call AST_Node.transform() if a different instance of AST_Node is
|
||||||
|
// produced after OPT().
|
||||||
|
// This corrupts TreeWalker.stack, which cause AST look-ups to malfunction.
|
||||||
|
// Migrate and defer all children's AST_Node.transform() to below, which
|
||||||
|
// will now happen after this parent AST_Node has been properly substituted
|
||||||
|
// thus gives a consistent AST snapshot.
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
node = node.optimize(this);
|
// Existing code relies on how AST_Node.optimize() worked, and omitting the
|
||||||
if (was_scope && node instanceof AST_Scope) {
|
// following replacement call would result in degraded efficiency of both
|
||||||
node.drop_unused(this);
|
// output and performance.
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
|
var opt = node.optimize(this);
|
||||||
|
if (was_scope && opt instanceof AST_Scope) {
|
||||||
|
opt.drop_unused(this);
|
||||||
|
descend(opt, this);
|
||||||
}
|
}
|
||||||
node._squeezed = true;
|
if (opt === node) opt._squeezed = true;
|
||||||
return node;
|
return opt;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -172,8 +183,7 @@ merge(Compressor.prototype, {
|
||||||
if (compressor.has_directive("use asm")) return self;
|
if (compressor.has_directive("use asm")) return self;
|
||||||
var opt = optimizer(self, compressor);
|
var opt = optimizer(self, compressor);
|
||||||
opt._optimized = true;
|
opt._optimized = true;
|
||||||
if (opt === self) return opt;
|
return opt;
|
||||||
return opt.transform(compressor);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -280,8 +290,12 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
var iife;
|
var iife;
|
||||||
if (node instanceof AST_Function
|
if (node instanceof AST_Function
|
||||||
|
&& !node.name
|
||||||
&& (iife = tw.parent()) instanceof AST_Call
|
&& (iife = tw.parent()) instanceof AST_Call
|
||||||
&& iife.expression === node) {
|
&& iife.expression === node) {
|
||||||
|
// Virtually turn IIFE parameters into variable definitions:
|
||||||
|
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
||||||
|
// So existing transformation rules can work on them.
|
||||||
node.argnames.forEach(function(arg, i) {
|
node.argnames.forEach(function(arg, i) {
|
||||||
var d = arg.definition();
|
var d = arg.definition();
|
||||||
d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
|
d.fixed = iife.args[i] || make_node(AST_Undefined, iife);
|
||||||
|
|
@ -381,7 +395,7 @@ merge(Compressor.prototype, {
|
||||||
return new ctor(props);
|
return new ctor(props);
|
||||||
};
|
};
|
||||||
|
|
||||||
function make_node_from_constant(compressor, val, orig) {
|
function make_node_from_constant(val, orig) {
|
||||||
switch (typeof val) {
|
switch (typeof val) {
|
||||||
case "string":
|
case "string":
|
||||||
return make_node(AST_String, orig, {
|
return make_node(AST_String, orig, {
|
||||||
|
|
@ -401,9 +415,9 @@ merge(Compressor.prototype, {
|
||||||
|
|
||||||
return make_node(AST_Number, orig, { value: val });
|
return make_node(AST_Number, orig, { value: val });
|
||||||
case "boolean":
|
case "boolean":
|
||||||
return make_node(val ? AST_True : AST_False, orig).transform(compressor);
|
return make_node(val ? AST_True : AST_False, orig);
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return make_node(AST_Undefined, orig).transform(compressor);
|
return make_node(AST_Undefined, orig);
|
||||||
default:
|
default:
|
||||||
if (val === null) {
|
if (val === null) {
|
||||||
return make_node(AST_Null, orig, { value: null });
|
return make_node(AST_Null, orig, { value: null });
|
||||||
|
|
@ -508,6 +522,7 @@ merge(Compressor.prototype, {
|
||||||
|
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
var var_defs_removed = false;
|
var var_defs_removed = false;
|
||||||
|
var toplevel = compressor.option("toplevel");
|
||||||
for (var stat_index = statements.length; --stat_index >= 0;) {
|
for (var stat_index = statements.length; --stat_index >= 0;) {
|
||||||
var stat = statements[stat_index];
|
var stat = statements[stat_index];
|
||||||
if (stat instanceof AST_Definitions) continue;
|
if (stat instanceof AST_Definitions) continue;
|
||||||
|
|
@ -545,7 +560,8 @@ merge(Compressor.prototype, {
|
||||||
|
|
||||||
// Only interested in cases with just one reference to the variable.
|
// Only interested in cases with just one reference to the variable.
|
||||||
var def = self.find_variable && self.find_variable(var_name);
|
var def = self.find_variable && self.find_variable(var_name);
|
||||||
if (!def || !def.references || def.references.length !== 1 || var_name == "arguments") {
|
if (!def || !def.references || def.references.length !== 1
|
||||||
|
|| var_name == "arguments" || (!toplevel && def.global)) {
|
||||||
side_effects_encountered = true;
|
side_effects_encountered = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -911,7 +927,7 @@ merge(Compressor.prototype, {
|
||||||
if (stat instanceof AST_LoopControl) {
|
if (stat instanceof AST_LoopControl) {
|
||||||
var lct = compressor.loopcontrol_target(stat.label);
|
var lct = compressor.loopcontrol_target(stat.label);
|
||||||
if ((stat instanceof AST_Break
|
if ((stat instanceof AST_Break
|
||||||
&& lct instanceof AST_BlockStatement
|
&& !(lct instanceof AST_IterationStatement)
|
||||||
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
&& loop_body(lct) === self) || (stat instanceof AST_Continue
|
||||||
&& loop_body(lct) === self)) {
|
&& loop_body(lct) === self)) {
|
||||||
if (stat.label) {
|
if (stat.label) {
|
||||||
|
|
@ -1195,11 +1211,11 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
function to_node(compressor, value, orig) {
|
function to_node(value, orig) {
|
||||||
if (value instanceof AST_Node) return make_node(value.CTOR, orig, value);
|
if (value instanceof AST_Node) return make_node(value.CTOR, orig, value);
|
||||||
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
||||||
elements: value.map(function(value) {
|
elements: value.map(function(value) {
|
||||||
return to_node(compressor, value, orig);
|
return to_node(value, orig);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
if (value && typeof value == "object") {
|
if (value && typeof value == "object") {
|
||||||
|
|
@ -1207,14 +1223,14 @@ merge(Compressor.prototype, {
|
||||||
for (var key in value) {
|
for (var key in value) {
|
||||||
props.push(make_node(AST_ObjectKeyVal, orig, {
|
props.push(make_node(AST_ObjectKeyVal, orig, {
|
||||||
key: key,
|
key: key,
|
||||||
value: to_node(compressor, value[key], orig)
|
value: to_node(value[key], orig)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
return make_node(AST_Object, orig, {
|
return make_node(AST_Object, orig, {
|
||||||
properties: props
|
properties: props
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return make_node_from_constant(compressor, value, orig);
|
return make_node_from_constant(value, orig);
|
||||||
}
|
}
|
||||||
def(AST_Node, noop);
|
def(AST_Node, noop);
|
||||||
def(AST_Dot, function(compressor, suffix){
|
def(AST_Dot, function(compressor, suffix){
|
||||||
|
|
@ -1225,7 +1241,7 @@ merge(Compressor.prototype, {
|
||||||
var name;
|
var name;
|
||||||
var defines = compressor.option("global_defs");
|
var defines = compressor.option("global_defs");
|
||||||
if (defines && HOP(defines, (name = this.name + suffix))) {
|
if (defines && HOP(defines, (name = this.name + suffix))) {
|
||||||
var node = to_node(compressor, defines[name], this);
|
var node = to_node(defines[name], this);
|
||||||
var top = compressor.find_parent(AST_Toplevel);
|
var top = compressor.find_parent(AST_Toplevel);
|
||||||
node.walk(new TreeWalker(function(node) {
|
node.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
|
@ -1240,45 +1256,40 @@ merge(Compressor.prototype, {
|
||||||
node.DEFMETHOD("_find_defs", func);
|
node.DEFMETHOD("_find_defs", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
function best_of(ast1, ast2) {
|
function best_of_expression(ast1, ast2) {
|
||||||
return ast1.print_to_string().length >
|
return ast1.print_to_string().length >
|
||||||
ast2.print_to_string().length
|
ast2.print_to_string().length
|
||||||
? ast2 : ast1;
|
? ast2 : ast1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function best_of_statement(ast1, ast2) {
|
function best_of_statement(ast1, ast2) {
|
||||||
return best_of(make_node(AST_SimpleStatement, ast1, {
|
return best_of_expression(make_node(AST_SimpleStatement, ast1, {
|
||||||
body: ast1
|
body: ast1
|
||||||
}), make_node(AST_SimpleStatement, ast2, {
|
}), make_node(AST_SimpleStatement, ast2, {
|
||||||
body: ast2
|
body: ast2
|
||||||
})).body;
|
})).body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function best_of(compressor, ast1, ast2) {
|
||||||
|
return (first_in_statement(compressor) ? best_of_statement : best_of_expression)(ast1, ast2);
|
||||||
|
}
|
||||||
|
|
||||||
// methods to evaluate a constant expression
|
// methods to evaluate a constant expression
|
||||||
(function (def){
|
(function (def){
|
||||||
// The evaluate method returns an array with one or two
|
// If the node has been successfully reduced to a constant,
|
||||||
// elements. If the node has been successfully reduced to a
|
// then its value is returned; otherwise the element itself
|
||||||
// constant, then the second element tells us the value;
|
// is returned.
|
||||||
// otherwise the second element is missing. The first element
|
// They can be distinguished as constant value is never a
|
||||||
// of the array is always an AST_Node descendant; if
|
// descendant of AST_Node.
|
||||||
// evaluation was successful it's a node that represents the
|
|
||||||
// constant; otherwise it's the original or a replacement node.
|
|
||||||
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
AST_Node.DEFMETHOD("evaluate", function(compressor){
|
||||||
if (!compressor.option("evaluate")) return [ this ];
|
if (!compressor.option("evaluate")) return this;
|
||||||
var val;
|
|
||||||
try {
|
try {
|
||||||
val = this._eval(compressor);
|
var val = this._eval(compressor);
|
||||||
|
return !val || val instanceof RegExp || typeof val != "object" ? val : this;
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex !== def) throw ex;
|
if (ex !== def) throw ex;
|
||||||
return [ this ];
|
return this;
|
||||||
}
|
}
|
||||||
var node;
|
|
||||||
try {
|
|
||||||
node = make_node_from_constant(compressor, val, this);
|
|
||||||
} catch(ex) {
|
|
||||||
return [ this ];
|
|
||||||
}
|
|
||||||
return [ best_of(node, this), val ];
|
|
||||||
});
|
});
|
||||||
var unaryPrefix = makePredicate("! ~ - +");
|
var unaryPrefix = makePredicate("! ~ - +");
|
||||||
AST_Node.DEFMETHOD("is_constant", function(){
|
AST_Node.DEFMETHOD("is_constant", function(){
|
||||||
|
|
@ -1316,8 +1327,8 @@ merge(Compressor.prototype, {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
var result = this.evaluate(compressor);
|
var result = this.evaluate(compressor);
|
||||||
if (result.length > 1) {
|
if (result !== this) {
|
||||||
return result[1];
|
return result;
|
||||||
}
|
}
|
||||||
throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start));
|
||||||
});
|
});
|
||||||
|
|
@ -1477,9 +1488,9 @@ merge(Compressor.prototype, {
|
||||||
var stat = make_node(AST_SimpleStatement, alt, {
|
var stat = make_node(AST_SimpleStatement, alt, {
|
||||||
body: alt
|
body: alt
|
||||||
});
|
});
|
||||||
return best_of(negated, stat) === stat ? alt : negated;
|
return best_of_expression(negated, stat) === stat ? alt : negated;
|
||||||
}
|
}
|
||||||
return best_of(negated, alt);
|
return best_of_expression(negated, alt);
|
||||||
}
|
}
|
||||||
def(AST_Node, function(){
|
def(AST_Node, function(){
|
||||||
return basic_negation(this);
|
return basic_negation(this);
|
||||||
|
|
@ -1643,8 +1654,8 @@ merge(Compressor.prototype, {
|
||||||
return thing && thing.aborts();
|
return thing && thing.aborts();
|
||||||
};
|
};
|
||||||
(function(def){
|
(function(def){
|
||||||
def(AST_Statement, function(){ return null });
|
def(AST_Statement, return_null);
|
||||||
def(AST_Jump, function(){ return this });
|
def(AST_Jump, return_this);
|
||||||
function block_aborts(){
|
function block_aborts(){
|
||||||
var n = this.body.length;
|
var n = this.body.length;
|
||||||
return n > 0 && aborts(this.body[n - 1]);
|
return n > 0 && aborts(this.body[n - 1]);
|
||||||
|
|
@ -1661,7 +1672,7 @@ merge(Compressor.prototype, {
|
||||||
/* -----[ optimizers ]----- */
|
/* -----[ optimizers ]----- */
|
||||||
|
|
||||||
OPT(AST_Directive, function(self, compressor){
|
OPT(AST_Directive, function(self, compressor){
|
||||||
if (compressor.has_directive(self.value) === "up") {
|
if (compressor.has_directive(self.value) !== self) {
|
||||||
return make_node(AST_EmptyStatement, self);
|
return make_node(AST_EmptyStatement, self);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|
@ -1811,10 +1822,12 @@ merge(Compressor.prototype, {
|
||||||
node.name = null;
|
node.name = null;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
||||||
if (!compressor.option("keep_fargs")) {
|
var trim = !compressor.option("keep_fargs");
|
||||||
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.definition().id in in_use_ids)) {
|
if (!(sym.definition().id in in_use_ids)) {
|
||||||
|
sym.__unused = true;
|
||||||
|
if (trim) {
|
||||||
a.pop();
|
a.pop();
|
||||||
compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
|
compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", {
|
||||||
name : sym.name,
|
name : sym.name,
|
||||||
|
|
@ -1823,7 +1836,9 @@ merge(Compressor.prototype, {
|
||||||
col : sym.start.col
|
col : sym.start.col
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else break;
|
}
|
||||||
|
else {
|
||||||
|
trim = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1902,17 +1917,15 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (drop_vars && assign_as_unused) {
|
if (drop_vars && assign_as_unused
|
||||||
var n = node;
|
&& node instanceof AST_Assign
|
||||||
while (n instanceof AST_Assign
|
&& node.operator == "="
|
||||||
&& n.operator == "="
|
&& node.left instanceof AST_SymbolRef) {
|
||||||
&& n.left instanceof AST_SymbolRef) {
|
var def = node.left.definition();
|
||||||
var def = n.left.definition();
|
if (!(def.id in in_use_ids)
|
||||||
if (def.id in in_use_ids
|
&& self.variables.get(def.name) === def) {
|
||||||
|| self.variables.get(def.name) !== def) break;
|
return maintain_this_binding(tt.parent(), node, node.right.transform(tt));
|
||||||
n = n.right;
|
|
||||||
}
|
}
|
||||||
if (n !== node) return n;
|
|
||||||
}
|
}
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_For) {
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
|
|
@ -1976,7 +1989,7 @@ merge(Compressor.prototype, {
|
||||||
vars.set(def.name.name, def);
|
vars.set(def.name.name, def);
|
||||||
++vars_found;
|
++vars_found;
|
||||||
});
|
});
|
||||||
var seq = node.to_assignments();
|
var seq = node.to_assignments(compressor);
|
||||||
var p = tt.parent();
|
var p = tt.parent();
|
||||||
if (p instanceof AST_ForIn && p.init === node) {
|
if (p instanceof AST_ForIn && p.init === node) {
|
||||||
if (seq == null) {
|
if (seq == null) {
|
||||||
|
|
@ -2072,14 +2085,6 @@ merge(Compressor.prototype, {
|
||||||
// drop_side_effect_free()
|
// drop_side_effect_free()
|
||||||
// remove side-effect-free parts which only affects return value
|
// remove side-effect-free parts which only affects return value
|
||||||
(function(def){
|
(function(def){
|
||||||
function return_this() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
function return_null() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop side-effect-free elements from an array of expressions.
|
// Drop side-effect-free elements from an array of expressions.
|
||||||
// Returns an array of expressions with side-effects or null
|
// Returns an array of expressions with side-effects or null
|
||||||
// if all elements were dropped. Note: original array may be
|
// if all elements were dropped. Note: original array may be
|
||||||
|
|
@ -2236,27 +2241,24 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_DWLoop, function(self, compressor){
|
OPT(AST_DWLoop, function(self, compressor){
|
||||||
var cond = self.condition.evaluate(compressor);
|
|
||||||
self.condition = cond[0];
|
|
||||||
if (!compressor.option("loops")) return self;
|
if (!compressor.option("loops")) return self;
|
||||||
if (cond.length > 1) {
|
var cond = self.condition.evaluate(compressor);
|
||||||
if (cond[1]) {
|
if (cond !== self.condition) {
|
||||||
|
if (cond) {
|
||||||
return make_node(AST_For, self, {
|
return make_node(AST_For, self, {
|
||||||
body: self.body
|
body: self.body
|
||||||
});
|
});
|
||||||
} else if (self instanceof AST_While) {
|
} else if (compressor.option("dead_code") && self instanceof AST_While) {
|
||||||
if (compressor.option("dead_code")) {
|
var a = [];
|
||||||
var a = [];
|
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
return make_node(AST_BlockStatement, self, { body: a });
|
||||||
return make_node(AST_BlockStatement, self, { body: a });
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// self instanceof AST_Do
|
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||||
return self;
|
self.condition = best_of_expression(cond, self.condition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self instanceof AST_While) {
|
if (self instanceof AST_While) {
|
||||||
return make_node(AST_For, self, self).transform(compressor);
|
return make_node(AST_For, self, self).optimize(compressor);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
@ -2278,7 +2280,7 @@ merge(Compressor.prototype, {
|
||||||
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body;
|
||||||
if (first instanceof AST_If) {
|
if (first instanceof AST_If) {
|
||||||
if (first.body instanceof AST_Break
|
if (first.body instanceof AST_Break
|
||||||
&& compressor.loopcontrol_target(first.body.label) === self) {
|
&& compressor.loopcontrol_target(first.body.label) === compressor.self()) {
|
||||||
if (self.condition) {
|
if (self.condition) {
|
||||||
self.condition = make_node(AST_Binary, self.condition, {
|
self.condition = make_node(AST_Binary, self.condition, {
|
||||||
left: self.condition,
|
left: self.condition,
|
||||||
|
|
@ -2291,7 +2293,7 @@ merge(Compressor.prototype, {
|
||||||
drop_it(first.alternative);
|
drop_it(first.alternative);
|
||||||
}
|
}
|
||||||
else if (first.alternative instanceof AST_Break
|
else if (first.alternative instanceof AST_Break
|
||||||
&& compressor.loopcontrol_target(first.alternative.label) === self) {
|
&& compressor.loopcontrol_target(first.alternative.label) === compressor.self()) {
|
||||||
if (self.condition) {
|
if (self.condition) {
|
||||||
self.condition = make_node(AST_Binary, self.condition, {
|
self.condition = make_node(AST_Binary, self.condition, {
|
||||||
left: self.condition,
|
left: self.condition,
|
||||||
|
|
@ -2307,27 +2309,25 @@ merge(Compressor.prototype, {
|
||||||
};
|
};
|
||||||
|
|
||||||
OPT(AST_For, function(self, compressor){
|
OPT(AST_For, function(self, compressor){
|
||||||
var cond = self.condition;
|
|
||||||
if (cond) {
|
|
||||||
cond = cond.evaluate(compressor);
|
|
||||||
self.condition = cond[0];
|
|
||||||
}
|
|
||||||
if (!compressor.option("loops")) return self;
|
if (!compressor.option("loops")) return self;
|
||||||
if (cond) {
|
if (self.condition) {
|
||||||
if (cond.length > 1 && !cond[1]) {
|
var cond = self.condition.evaluate(compressor);
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code") && !cond) {
|
||||||
var a = [];
|
var a = [];
|
||||||
if (self.init instanceof AST_Statement) {
|
if (self.init instanceof AST_Statement) {
|
||||||
a.push(self.init);
|
a.push(self.init);
|
||||||
}
|
|
||||||
else if (self.init) {
|
|
||||||
a.push(make_node(AST_SimpleStatement, self.init, {
|
|
||||||
body: self.init
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
|
||||||
return make_node(AST_BlockStatement, self, { body: a });
|
|
||||||
}
|
}
|
||||||
|
else if (self.init) {
|
||||||
|
a.push(make_node(AST_SimpleStatement, self.init, {
|
||||||
|
body: self.init
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||||
|
return make_node(AST_BlockStatement, self, { body: a });
|
||||||
|
}
|
||||||
|
if (cond !== self.condition) {
|
||||||
|
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||||
|
self.condition = best_of_expression(cond, self.condition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if_break_in_loop(self, compressor);
|
if_break_in_loop(self, compressor);
|
||||||
|
|
@ -2343,9 +2343,8 @@ merge(Compressor.prototype, {
|
||||||
// “has no side effects”; also it doesn't work for cases like
|
// “has no side effects”; also it doesn't work for cases like
|
||||||
// `x && true`, though it probably should.
|
// `x && true`, though it probably should.
|
||||||
var cond = self.condition.evaluate(compressor);
|
var cond = self.condition.evaluate(compressor);
|
||||||
self.condition = cond[0];
|
if (cond !== self.condition) {
|
||||||
if (cond.length > 1) {
|
if (cond) {
|
||||||
if (cond[1]) {
|
|
||||||
compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
|
compressor.warn("Condition always true [{file}:{line},{col}]", self.condition.start);
|
||||||
if (compressor.option("dead_code")) {
|
if (compressor.option("dead_code")) {
|
||||||
var a = [];
|
var a = [];
|
||||||
|
|
@ -2353,7 +2352,7 @@ merge(Compressor.prototype, {
|
||||||
extract_declarations_from_unreachable_code(compressor, self.alternative, a);
|
extract_declarations_from_unreachable_code(compressor, self.alternative, a);
|
||||||
}
|
}
|
||||||
a.push(self.body);
|
a.push(self.body);
|
||||||
return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
|
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
compressor.warn("Condition always false [{file}:{line},{col}]", self.condition.start);
|
||||||
|
|
@ -2361,9 +2360,11 @@ merge(Compressor.prototype, {
|
||||||
var a = [];
|
var a = [];
|
||||||
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
extract_declarations_from_unreachable_code(compressor, self.body, a);
|
||||||
if (self.alternative) a.push(self.alternative);
|
if (self.alternative) a.push(self.alternative);
|
||||||
return make_node(AST_BlockStatement, self, { body: a }).transform(compressor);
|
return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cond = make_node_from_constant(cond, self.condition).transform(compressor);
|
||||||
|
self.condition = best_of_expression(cond, self.condition);
|
||||||
}
|
}
|
||||||
var negated = self.condition.negate(compressor);
|
var negated = self.condition.negate(compressor);
|
||||||
var self_condition_length = self.condition.print_to_string().length;
|
var self_condition_length = self.condition.print_to_string().length;
|
||||||
|
|
@ -2380,8 +2381,8 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
if (is_empty(self.body) && is_empty(self.alternative)) {
|
if (is_empty(self.body) && is_empty(self.alternative)) {
|
||||||
return make_node(AST_SimpleStatement, self.condition, {
|
return make_node(AST_SimpleStatement, self.condition, {
|
||||||
body: self.condition
|
body: self.condition.clone()
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_SimpleStatement
|
if (self.body instanceof AST_SimpleStatement
|
||||||
&& self.alternative instanceof AST_SimpleStatement) {
|
&& self.alternative instanceof AST_SimpleStatement) {
|
||||||
|
|
@ -2391,7 +2392,7 @@ merge(Compressor.prototype, {
|
||||||
consequent : statement_to_expression(self.body),
|
consequent : statement_to_expression(self.body),
|
||||||
alternative : statement_to_expression(self.alternative)
|
alternative : statement_to_expression(self.alternative)
|
||||||
})
|
})
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
|
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
|
||||||
if (self_condition_length === negated_length && !negated_is_best
|
if (self_condition_length === negated_length && !negated_is_best
|
||||||
|
|
@ -2407,14 +2408,14 @@ merge(Compressor.prototype, {
|
||||||
left : negated,
|
left : negated,
|
||||||
right : statement_to_expression(self.body)
|
right : statement_to_expression(self.body)
|
||||||
})
|
})
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
return make_node(AST_SimpleStatement, self, {
|
return make_node(AST_SimpleStatement, self, {
|
||||||
body: make_node(AST_Binary, self, {
|
body: make_node(AST_Binary, self, {
|
||||||
operator : "&&",
|
operator : "&&",
|
||||||
left : self.condition,
|
left : self.condition,
|
||||||
right : statement_to_expression(self.body)
|
right : statement_to_expression(self.body)
|
||||||
})
|
})
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_EmptyStatement
|
if (self.body instanceof AST_EmptyStatement
|
||||||
&& self.alternative
|
&& self.alternative
|
||||||
|
|
@ -2425,7 +2426,7 @@ merge(Compressor.prototype, {
|
||||||
left : self.condition,
|
left : self.condition,
|
||||||
right : statement_to_expression(self.alternative)
|
right : statement_to_expression(self.alternative)
|
||||||
})
|
})
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_Exit
|
if (self.body instanceof AST_Exit
|
||||||
&& self.alternative instanceof AST_Exit
|
&& self.alternative instanceof AST_Exit
|
||||||
|
|
@ -2435,18 +2436,21 @@ merge(Compressor.prototype, {
|
||||||
condition : self.condition,
|
condition : self.condition,
|
||||||
consequent : self.body.value || make_node(AST_Undefined, self.body),
|
consequent : self.body.value || make_node(AST_Undefined, self.body),
|
||||||
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative)
|
alternative : self.alternative.value || make_node(AST_Undefined, self.alternative)
|
||||||
})
|
}).transform(compressor)
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.body instanceof AST_If
|
if (self.body instanceof AST_If
|
||||||
&& !self.body.alternative
|
&& !self.body.alternative
|
||||||
&& !self.alternative) {
|
&& !self.alternative) {
|
||||||
self.condition = make_node(AST_Binary, self.condition, {
|
self = make_node(AST_If, self, {
|
||||||
operator: "&&",
|
condition: make_node(AST_Binary, self.condition, {
|
||||||
left: self.condition,
|
operator: "&&",
|
||||||
right: self.body.condition
|
left: self.condition,
|
||||||
}).transform(compressor);
|
right: self.body.condition
|
||||||
self.body = self.body.body;
|
}),
|
||||||
|
body: self.body.body,
|
||||||
|
alternative: null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (aborts(self.body)) {
|
if (aborts(self.body)) {
|
||||||
if (self.alternative) {
|
if (self.alternative) {
|
||||||
|
|
@ -2454,7 +2458,7 @@ merge(Compressor.prototype, {
|
||||||
self.alternative = null;
|
self.alternative = null;
|
||||||
return make_node(AST_BlockStatement, self, {
|
return make_node(AST_BlockStatement, self, {
|
||||||
body: [ self, alt ]
|
body: [ self, alt ]
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (aborts(self.alternative)) {
|
if (aborts(self.alternative)) {
|
||||||
|
|
@ -2464,7 +2468,7 @@ merge(Compressor.prototype, {
|
||||||
self.alternative = null;
|
self.alternative = null;
|
||||||
return make_node(AST_BlockStatement, self, {
|
return make_node(AST_BlockStatement, self, {
|
||||||
body: [ self, body ]
|
body: [ self, body ]
|
||||||
}).transform(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
@ -2488,12 +2492,12 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var exp = self.expression.evaluate(compressor);
|
var value = self.expression.evaluate(compressor);
|
||||||
out: if (exp.length == 2) try {
|
out: if (value !== self.expression) try {
|
||||||
// constant expression
|
// constant expression
|
||||||
self.expression = exp[0];
|
var expression = make_node_from_constant(value, self.expression);
|
||||||
|
self.expression = best_of_expression(expression, self.expression);
|
||||||
if (!compressor.option("dead_code")) break out;
|
if (!compressor.option("dead_code")) break out;
|
||||||
var value = exp[1];
|
|
||||||
var in_if = false;
|
var in_if = false;
|
||||||
var in_block = false;
|
var in_block = false;
|
||||||
var started = false;
|
var started = false;
|
||||||
|
|
@ -2540,11 +2544,11 @@ merge(Compressor.prototype, {
|
||||||
if (stopped) return MAP.skip;
|
if (stopped) return MAP.skip;
|
||||||
if (node instanceof AST_Case) {
|
if (node instanceof AST_Case) {
|
||||||
var exp = node.expression.evaluate(compressor);
|
var exp = node.expression.evaluate(compressor);
|
||||||
if (exp.length < 2) {
|
if (exp === node.expression) {
|
||||||
// got a case with non-constant expression, baling out
|
// got a case with non-constant expression, baling out
|
||||||
throw self;
|
throw self;
|
||||||
}
|
}
|
||||||
if (exp[1] === value || started) {
|
if (exp === value || started) {
|
||||||
started = true;
|
started = true;
|
||||||
if (aborts(node)) stopped = true;
|
if (aborts(node)) stopped = true;
|
||||||
descend(node, this);
|
descend(node, this);
|
||||||
|
|
@ -2578,7 +2582,8 @@ merge(Compressor.prototype, {
|
||||||
this.definitions.forEach(function(def){ def.value = null });
|
this.definitions.forEach(function(def){ def.value = null });
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Definitions.DEFMETHOD("to_assignments", function(){
|
AST_Definitions.DEFMETHOD("to_assignments", function(compressor){
|
||||||
|
var reduce_vars = compressor.option("reduce_vars");
|
||||||
var assignments = this.definitions.reduce(function(a, def){
|
var assignments = this.definitions.reduce(function(a, def){
|
||||||
if (def.value) {
|
if (def.value) {
|
||||||
var name = make_node(AST_SymbolRef, def.name, def.name);
|
var name = make_node(AST_SymbolRef, def.name, def.name);
|
||||||
|
|
@ -2587,6 +2592,7 @@ merge(Compressor.prototype, {
|
||||||
left : name,
|
left : name,
|
||||||
right : def.value
|
right : def.value
|
||||||
}));
|
}));
|
||||||
|
if (reduce_vars) name.definition().fixed = false;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
@ -2612,6 +2618,9 @@ merge(Compressor.prototype, {
|
||||||
exp = def.fixed;
|
exp = def.fixed;
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& def.references.length == 1
|
&& def.references.length == 1
|
||||||
|
&& !(def.scope.uses_arguments
|
||||||
|
&& def.orig[0] instanceof AST_SymbolFunarg)
|
||||||
|
&& !def.scope.uses_eval
|
||||||
&& compressor.find_parent(AST_Scope) === def.scope) {
|
&& compressor.find_parent(AST_Scope) === def.scope) {
|
||||||
self.expression = exp;
|
self.expression = exp;
|
||||||
}
|
}
|
||||||
|
|
@ -2620,16 +2629,26 @@ merge(Compressor.prototype, {
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& exp instanceof AST_Function
|
&& exp instanceof AST_Function
|
||||||
&& !exp.uses_arguments
|
&& !exp.uses_arguments
|
||||||
&& !exp.uses_eval
|
&& !exp.uses_eval) {
|
||||||
&& self.args.length > exp.argnames.length) {
|
var pos = 0, last = 0;
|
||||||
var end = exp.argnames.length;
|
for (var i = 0, len = self.args.length; i < len; i++) {
|
||||||
for (var i = end, len = self.args.length; i < len; i++) {
|
var trim = i >= exp.argnames.length;
|
||||||
var node = self.args[i].drop_side_effect_free(compressor);
|
if (trim || exp.argnames[i].__unused) {
|
||||||
if (node) {
|
var node = self.args[i].drop_side_effect_free(compressor);
|
||||||
self.args[end++] = node;
|
if (node) {
|
||||||
|
self.args[pos++] = node;
|
||||||
|
} else if (!trim) {
|
||||||
|
self.args[pos++] = make_node(AST_Number, self.args[i], {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.args[pos++] = self.args[i];
|
||||||
}
|
}
|
||||||
|
last = pos;
|
||||||
}
|
}
|
||||||
self.args.length = end;
|
self.args.length = last;
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
||||||
|
|
@ -2745,15 +2764,14 @@ merge(Compressor.prototype, {
|
||||||
var separator;
|
var separator;
|
||||||
if (self.args.length > 0) {
|
if (self.args.length > 0) {
|
||||||
separator = self.args[0].evaluate(compressor);
|
separator = self.args[0].evaluate(compressor);
|
||||||
if (separator.length < 2) break EXIT; // not a constant
|
if (separator === self.args[0]) break EXIT; // not a constant
|
||||||
separator = separator[1];
|
|
||||||
}
|
}
|
||||||
var elements = [];
|
var elements = [];
|
||||||
var consts = [];
|
var consts = [];
|
||||||
exp.expression.elements.forEach(function(el) {
|
exp.expression.elements.forEach(function(el) {
|
||||||
el = el.evaluate(compressor);
|
var value = el.evaluate(compressor);
|
||||||
if (el.length > 1) {
|
if (value !== el) {
|
||||||
consts.push(el[1]);
|
consts.push(value);
|
||||||
} else {
|
} else {
|
||||||
if (consts.length > 0) {
|
if (consts.length > 0) {
|
||||||
elements.push(make_node(AST_String, self, {
|
elements.push(make_node(AST_String, self, {
|
||||||
|
|
@ -2761,7 +2779,7 @@ merge(Compressor.prototype, {
|
||||||
}));
|
}));
|
||||||
consts.length = 0;
|
consts.length = 0;
|
||||||
}
|
}
|
||||||
elements.push(el[0]);
|
elements.push(el);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (consts.length > 0) {
|
if (consts.length > 0) {
|
||||||
|
|
@ -2802,7 +2820,7 @@ merge(Compressor.prototype, {
|
||||||
node.expression = node.expression.clone();
|
node.expression = node.expression.clone();
|
||||||
node.expression.expression = node.expression.expression.clone();
|
node.expression.expression = node.expression.expression.clone();
|
||||||
node.expression.expression.elements = elements;
|
node.expression.expression.elements = elements;
|
||||||
return best_of(self, node);
|
return best_of(compressor, self, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("drop_error")) {
|
if (compressor.option("drop_error")) {
|
||||||
|
|
@ -2987,8 +3005,7 @@ merge(Compressor.prototype, {
|
||||||
return e.expression;
|
return e.expression;
|
||||||
}
|
}
|
||||||
if (e instanceof AST_Binary) {
|
if (e instanceof AST_Binary) {
|
||||||
var statement = first_in_statement(compressor);
|
self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor)));
|
||||||
self = (statement ? best_of_statement : best_of)(self, e.negate(compressor, statement));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "typeof":
|
case "typeof":
|
||||||
|
|
@ -3001,7 +3018,15 @@ merge(Compressor.prototype, {
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.evaluate(compressor)[0];
|
// avoids infinite recursion of numerals
|
||||||
|
if (self.operator != "-" || !(self.expression instanceof AST_Number)) {
|
||||||
|
var ev = self.evaluate(compressor);
|
||||||
|
if (ev !== self) {
|
||||||
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
return best_of(compressor, ev, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
function has_side_effects_or_prop_access(node, compressor) {
|
function has_side_effects_or_prop_access(node, compressor) {
|
||||||
|
|
@ -3039,16 +3064,6 @@ merge(Compressor.prototype, {
|
||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor){
|
OPT(AST_Binary, function(self, compressor){
|
||||||
var lhs = self.left.evaluate(compressor);
|
|
||||||
var rhs = self.right.evaluate(compressor);
|
|
||||||
if (lhs.length > 1 && lhs[0].is_constant() !== self.left.is_constant()
|
|
||||||
|| rhs.length > 1 && rhs[0].is_constant() !== self.right.is_constant()) {
|
|
||||||
return make_node(AST_Binary, self, {
|
|
||||||
operator: self.operator,
|
|
||||||
left: lhs[0],
|
|
||||||
right: rhs[0]
|
|
||||||
}).optimize(compressor);
|
|
||||||
}
|
|
||||||
function reversible() {
|
function reversible() {
|
||||||
return self.left instanceof AST_Constant
|
return self.left instanceof AST_Constant
|
||||||
|| self.right instanceof AST_Constant
|
|| self.right instanceof AST_Constant
|
||||||
|
|
@ -3133,48 +3148,48 @@ merge(Compressor.prototype, {
|
||||||
case "&&":
|
case "&&":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if ((ll.length > 1 && !ll[1]) || (rr.length > 1 && !rr[1])) {
|
if (!ll || !rr) {
|
||||||
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean && always false [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_node(AST_Seq, self, {
|
||||||
car: self.left,
|
car: self.left,
|
||||||
cdr: make_node(AST_False, self)
|
cdr: make_node(AST_False, self)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (ll.length > 1 && ll[1]) {
|
if (ll !== self.left && ll) {
|
||||||
return rr[0];
|
return self.right.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (rr.length > 1 && rr[1]) {
|
if (rr !== self.right && rr) {
|
||||||
return ll[0];
|
return self.left.optimize(compressor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "||":
|
case "||":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if ((ll.length > 1 && ll[1]) || (rr.length > 1 && rr[1])) {
|
if (ll !== self.left && ll || rr !== self.right && rr) {
|
||||||
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_node(AST_Seq, self, {
|
||||||
car: self.left,
|
car: self.left,
|
||||||
cdr: make_node(AST_True, self)
|
cdr: make_node(AST_True, self)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (ll.length > 1 && !ll[1]) {
|
if (!ll) {
|
||||||
return rr[0];
|
return self.right.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (rr.length > 1 && !rr[1]) {
|
if (!rr) {
|
||||||
return ll[0];
|
return self.left.optimize(compressor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "+":
|
case "+":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if (ll.length > 1 && ll[0] instanceof AST_String && ll[1]) {
|
if (ll && typeof ll == "string") {
|
||||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_node(AST_Seq, self, {
|
||||||
car: self.right,
|
car: self.right,
|
||||||
cdr: make_node(AST_True, self)
|
cdr: make_node(AST_True, self)
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
}
|
}
|
||||||
if (rr.length > 1 && rr[0] instanceof AST_String && rr[1]) {
|
if (rr && typeof rr == "string") {
|
||||||
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
compressor.warn("+ in boolean context always true [{file}:{line},{col}]", self.start);
|
||||||
return make_node(AST_Seq, self, {
|
return make_node(AST_Seq, self, {
|
||||||
car: self.left,
|
car: self.left,
|
||||||
|
|
@ -3186,12 +3201,11 @@ merge(Compressor.prototype, {
|
||||||
if (compressor.option("comparisons") && self.is_boolean()) {
|
if (compressor.option("comparisons") && self.is_boolean()) {
|
||||||
if (!(compressor.parent() instanceof AST_Binary)
|
if (!(compressor.parent() instanceof AST_Binary)
|
||||||
|| compressor.parent() instanceof AST_Assign) {
|
|| compressor.parent() instanceof AST_Assign) {
|
||||||
var statement = first_in_statement(compressor);
|
|
||||||
var negated = make_node(AST_UnaryPrefix, self, {
|
var negated = make_node(AST_UnaryPrefix, self, {
|
||||||
operator: "!",
|
operator: "!",
|
||||||
expression: self.negate(compressor, statement)
|
expression: self.negate(compressor, first_in_statement(compressor))
|
||||||
});
|
});
|
||||||
self = (statement ? best_of_statement : best_of)(self, negated);
|
self = best_of(compressor, self, negated);
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe_comps")) {
|
if (compressor.option("unsafe_comps")) {
|
||||||
switch (self.operator) {
|
switch (self.operator) {
|
||||||
|
|
@ -3343,9 +3357,9 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
if (self.right instanceof AST_Constant
|
if (self.right instanceof AST_Constant
|
||||||
&& !(self.left instanceof AST_Constant)) {
|
&& !(self.left instanceof AST_Constant)) {
|
||||||
self = best_of(reversed, self);
|
self = best_of(compressor, reversed, self);
|
||||||
} else {
|
} else {
|
||||||
self = best_of(self, reversed);
|
self = best_of(compressor, self, reversed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (associative && self.is_number(compressor)) {
|
if (associative && self.is_number(compressor)) {
|
||||||
|
|
@ -3442,7 +3456,12 @@ merge(Compressor.prototype, {
|
||||||
self.right = self.right.right;
|
self.right = self.right.right;
|
||||||
return self.transform(compressor);
|
return self.transform(compressor);
|
||||||
}
|
}
|
||||||
return self.evaluate(compressor)[0];
|
var ev = self.evaluate(compressor);
|
||||||
|
if (ev !== self) {
|
||||||
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
return best_of(compressor, ev, self);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_SymbolRef, function(self, compressor){
|
OPT(AST_SymbolRef, function(self, compressor){
|
||||||
|
|
@ -3457,11 +3476,11 @@ merge(Compressor.prototype, {
|
||||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
return make_node(AST_Undefined, self).transform(compressor);
|
return make_node(AST_Undefined, self).optimize(compressor);
|
||||||
case "NaN":
|
case "NaN":
|
||||||
return make_node(AST_NaN, self).transform(compressor);
|
return make_node(AST_NaN, self).optimize(compressor);
|
||||||
case "Infinity":
|
case "Infinity":
|
||||||
return make_node(AST_Infinity, self).transform(compressor);
|
return make_node(AST_Infinity, self).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
|
if (compressor.option("evaluate") && compressor.option("reduce_vars")) {
|
||||||
|
|
@ -3469,18 +3488,20 @@ merge(Compressor.prototype, {
|
||||||
if (d.fixed) {
|
if (d.fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
var init = d.fixed.evaluate(compressor);
|
var init = d.fixed.evaluate(compressor);
|
||||||
if (init.length > 1) {
|
if (init !== d.fixed) {
|
||||||
var value = init[0].print_to_string().length;
|
init = make_node_from_constant(init, d.fixed).optimize(compressor);
|
||||||
|
init = best_of_expression(init, d.fixed);
|
||||||
|
var value = init.print_to_string().length;
|
||||||
var name = d.name.length;
|
var name = d.name.length;
|
||||||
var freq = d.references.length;
|
var freq = d.references.length;
|
||||||
var overhead = d.global || !freq ? 0 : (name + 2 + value) / freq;
|
var overhead = d.global || !freq ? 0 : (name + 2 + value) / freq;
|
||||||
d.should_replace = value <= name + overhead ? init[0] : false;
|
d.should_replace = value <= name + overhead ? init : false;
|
||||||
} else {
|
} else {
|
||||||
d.should_replace = false;
|
d.should_replace = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (d.should_replace) {
|
if (d.should_replace) {
|
||||||
return d.should_replace;
|
return d.should_replace.clone(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3545,8 +3566,8 @@ merge(Compressor.prototype, {
|
||||||
return AST_Seq.cons(car, self);
|
return AST_Seq.cons(car, self);
|
||||||
}
|
}
|
||||||
var cond = self.condition.evaluate(compressor);
|
var cond = self.condition.evaluate(compressor);
|
||||||
if (cond.length > 1) {
|
if (cond !== self.condition) {
|
||||||
if (cond[1]) {
|
if (cond) {
|
||||||
compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
|
||||||
return maintain_this_binding(compressor.parent(), self, self.consequent);
|
return maintain_this_binding(compressor.parent(), self, self.consequent);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -3554,9 +3575,8 @@ merge(Compressor.prototype, {
|
||||||
return maintain_this_binding(compressor.parent(), self, self.alternative);
|
return maintain_this_binding(compressor.parent(), self, self.alternative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var statement = first_in_statement(compressor);
|
var negated = cond.negate(compressor, first_in_statement(compressor));
|
||||||
var negated = cond[0].negate(compressor, statement);
|
if (best_of(compressor, cond, negated) === negated) {
|
||||||
if ((statement ? best_of_statement : best_of)(cond[0], negated) === negated) {
|
|
||||||
self = make_node(AST_Conditional, self, {
|
self = make_node(AST_Conditional, self, {
|
||||||
condition: negated,
|
condition: negated,
|
||||||
consequent: self.alternative,
|
consequent: self.alternative,
|
||||||
|
|
@ -3736,7 +3756,12 @@ merge(Compressor.prototype, {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.evaluate(compressor)[0];
|
var ev = self.evaluate(compressor);
|
||||||
|
if (ev !== self) {
|
||||||
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
return best_of(compressor, ev, self);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Dot, function(self, compressor){
|
OPT(AST_Dot, function(self, compressor){
|
||||||
|
|
@ -3775,13 +3800,17 @@ merge(Compressor.prototype, {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.evaluate(compressor)[0];
|
var ev = self.evaluate(compressor);
|
||||||
|
if (ev !== self) {
|
||||||
|
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||||
|
return best_of(compressor, ev, self);
|
||||||
|
}
|
||||||
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
function literals_in_boolean_context(self, compressor) {
|
function literals_in_boolean_context(self, compressor) {
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) {
|
||||||
var best = first_in_statement(compressor) ? best_of_statement : best_of;
|
return best_of(compressor, self, make_node(AST_Seq, self, {
|
||||||
return best(self, make_node(AST_Seq, self, {
|
|
||||||
car: self,
|
car: self,
|
||||||
cdr: make_node(AST_True, self)
|
cdr: make_node(AST_True, self)
|
||||||
}).optimize(compressor));
|
}).optimize(compressor));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user