aboutsummaryrefs
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/compress.js84
1 files changed, 53 insertions, 31 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 06ed35f5..dfd2f7f6 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -980,24 +980,12 @@ merge(Compressor.prototype, {
}
// Stop immediately if these node types are encountered
var parent = scanner.parent();
- if (node instanceof AST_Assign && node.operator != "=" && lhs.equivalent_to(node.left)
- || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
- || node instanceof AST_Debugger
- || node instanceof AST_IterationStatement && !(node instanceof AST_For)
- || node instanceof AST_LoopControl
- || node instanceof AST_Try
- || node instanceof AST_With
- || parent instanceof AST_For && node !== parent.init
- || !replace_all
- && (node instanceof AST_SymbolRef && !node.is_declared(compressor))) {
+ if (should_stop(node, parent)) {
abort = true;
return node;
}
// Stop only if candidate is found within conditional branches
- if (!stop_if_hit
- && (parent instanceof AST_Binary && lazy_op[parent.operator] && parent.left !== node
- || parent instanceof AST_Conditional && parent.condition !== node
- || parent instanceof AST_If && parent.condition !== node)) {
+ if (!stop_if_hit && in_conditional(node, parent)) {
stop_if_hit = parent;
}
// Replace variable with assignment when found
@@ -1047,20 +1035,7 @@ merge(Compressor.prototype, {
// These node types have child nodes that execute sequentially,
// but are otherwise not safe to scan into or beyond them.
var sym;
- if (node instanceof AST_Call
- || node instanceof AST_Exit
- && (side_effects || lhs instanceof AST_PropAccess || may_modify(lhs))
- || node instanceof AST_PropAccess
- && (side_effects || node.expression.may_throw_on_access(compressor))
- || node instanceof AST_SymbolRef
- && (symbol_in_lvalues(node) || side_effects && may_modify(node))
- || node instanceof AST_This && symbol_in_lvalues(node)
- || node instanceof AST_VarDef && node.value
- && (node.name.name in lvalues || side_effects && may_modify(node.name))
- || (sym = is_lhs(node.left, node))
- && (sym instanceof AST_PropAccess || sym.name in lvalues)
- || may_throw
- && (in_try ? node.has_side_effects(compressor) : side_effects_external(node))) {
+ if (is_last_node(node, parent) || may_throw(node)) {
stop_after = node;
if (node instanceof AST_Scope) abort = true;
}
@@ -1119,7 +1094,9 @@ merge(Compressor.prototype, {
var lhs_local = is_lhs_local(lhs);
if (!side_effects) side_effects = value_has_side_effects(candidate);
var replace_all = replace_all_symbols();
- var may_throw = candidate.may_throw(compressor);
+ var may_throw = candidate.may_throw(compressor) ? in_try ? function(node) {
+ return node.has_side_effects(compressor);
+ } : side_effects_external : return_false;
var funarg = candidate.name instanceof AST_SymbolFunarg;
var hit = funarg;
var abort = false, replaced = 0, can_replace = !args || !hit;
@@ -1171,6 +1148,51 @@ merge(Compressor.prototype, {
}
}
+ function should_stop(node, parent) {
+ if (node instanceof AST_Assign) return node.operator != "=" && lhs.equivalent_to(node.left);
+ if (node instanceof AST_Call) {
+ return lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression);
+ }
+ if (node instanceof AST_Debugger) return true;
+ if (node instanceof AST_IterationStatement) return !(node instanceof AST_For);
+ if (node instanceof AST_LoopControl) return true;
+ if (node instanceof AST_Try) return true;
+ if (node instanceof AST_With) return true;
+ if (parent instanceof AST_For) return node !== parent.init;
+ if (replace_all) return false;
+ return node instanceof AST_SymbolRef && !node.is_declared(compressor);
+ }
+
+ function in_conditional(node, parent) {
+ if (parent instanceof AST_Binary) return lazy_op[parent.operator] && parent.left !== node;
+ if (parent instanceof AST_Conditional) return parent.condition !== node;
+ return parent instanceof AST_If && parent.condition !== node;
+ }
+
+ function is_last_node(node, parent) {
+ if (node instanceof AST_Call) return true;
+ if (node instanceof AST_Exit) {
+ return side_effects || lhs instanceof AST_PropAccess || may_modify(lhs);
+ }
+ if (node instanceof AST_PropAccess) {
+ return side_effects || node.expression.may_throw_on_access(compressor);
+ }
+ if (node instanceof AST_SymbolRef) {
+ if (symbol_in_lvalues(node, parent)) {
+ return !parent || parent.operator != "=" || parent.left !== node;
+ }
+ return side_effects && may_modify(node);
+ }
+ if (node instanceof AST_This) return symbol_in_lvalues(node, parent);
+ if (node instanceof AST_VarDef) {
+ if (!node.value) return false;
+ return node.name.name in lvalues || side_effects && may_modify(node.name);
+ }
+ var sym = is_lhs(node.left, node);
+ if (sym && sym.name in lvalues) return true;
+ if (sym instanceof AST_PropAccess) return true;
+ }
+
function extract_args() {
var iife, fn = compressor.self();
if (fn instanceof AST_Function
@@ -1482,10 +1504,10 @@ merge(Compressor.prototype, {
return false;
}
- function symbol_in_lvalues(sym) {
+ function symbol_in_lvalues(sym, parent) {
var lvalue = lvalues[sym.name];
if (!lvalue) return;
- if (lvalue !== lhs) return true;
+ if (lvalue !== lhs) return !(parent instanceof AST_Call);
scan_rhs = false;
}