function tighten_body(statements, compressor) {
var in_loop, in_try, scope;
find_loop_scope_try();
- var CHANGED, max_iter = 10;
+ var changed, last_changed, max_iter = 10;
do {
- CHANGED = false;
- eliminate_spurious_blocks(statements);
+ last_changed = changed;
+ changed = 0;
+ if (eliminate_spurious_blocks(statements)) changed = 1;
+ if (!changed && last_changed == 1) break;
if (compressor.option("dead_code")) {
- eliminate_dead_code(statements, compressor);
+ if (eliminate_dead_code(statements, compressor)) changed = 2;
+ if (!changed && last_changed == 2) break;
}
if (compressor.option("if_return")) {
- handle_if_return(statements, compressor);
+ if (handle_if_return(statements, compressor)) changed = 3;
+ if (!changed && last_changed == 3) break;
}
if (compressor.sequences_limit > 0) {
- sequencesize(statements, compressor);
- sequencesize_2(statements, compressor);
+ if (sequencesize(statements, compressor)) changed = 4;
+ if (!changed && last_changed == 4) break;
+ if (sequencesize_2(statements, compressor)) changed = 5;
+ if (!changed && last_changed == 5) break;
}
if (compressor.option("join_vars")) {
- join_consecutive_vars(statements);
+ if (join_consecutive_vars(statements)) changed = 6;
+ if (!changed && last_changed == 6) break;
}
if (compressor.option("collapse_vars")) {
- collapse(statements, compressor);
+ if (collapse(statements, compressor)) changed = 7;
}
- } while (CHANGED && max_iter-- > 0);
+ } while (changed && max_iter-- > 0);
return statements;
function find_loop_scope_try() {
// Will not attempt to collapse assignments into or past code blocks
// which are not sequentially executed, e.g. loops and conditionals.
function collapse(statements, compressor) {
- if (scope.pinned()) return statements;
+ if (scope.pinned()) return;
var args;
var assignments = new Dictionary();
var candidates = [];
+ var changed = false;
var declare_only = new Dictionary();
var force_single;
var stat_index = statements.length;
} else {
replaced++;
}
- CHANGED = abort = true;
+ changed = abort = true;
AST_Node.info("Collapsing {node} [{file}:{line},{col}]", {
node: node,
file: node.start.file,
&& !compressor.exposed(def);
value_def.last_ref = false;
value_def.single_use = false;
- CHANGED = true;
+ changed = true;
}
if (replaced && !remove_candidate(candidate)) statements.splice(stat_index, 1);
}
}
+ return changed;
function signal_abort(node) {
if (abort) return node;
}
function eliminate_spurious_blocks(statements) {
- var seen_dirs = [];
+ var changed = false, seen_dirs = [];
for (var i = 0; i < statements.length;) {
var stat = statements[i];
if (stat instanceof AST_BlockStatement) {
if (all(stat.body, safe_to_trim)) {
- CHANGED = true;
+ changed = true;
eliminate_spurious_blocks(stat.body);
[].splice.apply(statements, [i, 1].concat(stat.body));
i += stat.body.length;
}
if (stat instanceof AST_Directive) {
if (member(stat.value, seen_dirs)) {
- CHANGED = true;
+ changed = true;
statements.splice(i, 1);
continue;
}
seen_dirs.push(stat.value);
}
if (stat instanceof AST_EmptyStatement) {
- CHANGED = true;
+ changed = true;
statements.splice(i, 1);
continue;
}
i++;
}
+ return changed;
}
function handle_if_return(statements, compressor) {
+ var changed = false;
var self = compressor.self();
var parent = compressor.parent();
var in_lambda = last_of(function(node) {
if (in_lambda && !next && stat instanceof AST_Return) {
if (!stat.value) {
- CHANGED = true;
+ changed = true;
statements.splice(i, 1);
continue;
}
var tail = stat.value.tail_node();
if (tail instanceof AST_UnaryPrefix && tail.operator == "void") {
- CHANGED = true;
+ changed = true;
var body;
if (tail === stat.value) {
body = tail.expression;
var ab = aborts(stat.body);
if (can_merge_flow(ab)) {
if (ab.label) remove(ab.label.thedef.references, ab);
- CHANGED = true;
+ changed = true;
stat = stat.clone();
stat.condition = stat.condition.negate(compressor);
var body = as_statement_array_with_return(stat.body, ab);
if (ab && !stat.alternative && stat.body instanceof AST_BlockStatement && next instanceof AST_Jump) {
var negated = stat.condition.negate(compressor);
if (negated.print_to_string().length <= stat.condition.print_to_string().length) {
- CHANGED = true;
+ changed = true;
stat = stat.clone();
stat.condition = negated;
statements[j] = stat.body;
var alt = aborts(stat.alternative);
if (can_merge_flow(alt)) {
if (alt.label) remove(alt.label.thedef.references, alt);
- CHANGED = true;
+ changed = true;
stat = stat.clone();
stat.body = make_node(AST_BlockStatement, stat.body, {
body: as_statement_array(stat.body).concat(extract_functions())
// if (foo()) return; return; ---> foo(); return;
if (!value && !stat.alternative
&& (in_lambda && !next || next instanceof AST_Return && !next.value)) {
- CHANGED = true;
+ changed = true;
statements[i] = make_node(AST_SimpleStatement, stat.condition, {
body: stat.condition
});
//---
// if (foo()) return x; return y; ---> return foo() ? x : y;
if (!stat.alternative && next instanceof AST_Return) {
- CHANGED = true;
+ changed = true;
stat = stat.clone();
stat.alternative = next;
statements.splice(i, 1, stat.transform(compressor));
//---
// if (foo()) return x; [ return ; ] ---> return foo() ? x : undefined;
if (!stat.alternative && !next && in_lambda && (in_bool || value && multiple_if_returns)) {
- CHANGED = true;
+ changed = true;
stat = stat.clone();
stat.alternative = make_node(AST_Return, stat, {
value: null
if (compressor.option("sequences") && in_lambda && !stat.alternative
&& (!prev && in_iife || prev instanceof AST_If && prev.body instanceof AST_Return)
&& next_index(j) == statements.length && next instanceof AST_SimpleStatement) {
- CHANGED = true;
+ changed = true;
stat = stat.clone();
stat.alternative = make_node(AST_BlockStatement, next, {
body: [
}
}
}
+ return changed;
function has_multiple_if_returns(statements) {
var n = 0;
if (has_quit) has_quit.forEach(function(stat) {
extract_declarations_from_unreachable_code(compressor, stat, statements);
});
- CHANGED = statements.length != len;
+ return statements.length != len;
}
function sequencesize(statements, compressor) {
}
push_seq();
statements.length = n;
- if (n != len) CHANGED = true;
+ return n != len;
}
function to_simple_statement(block, decls) {
}
function sequencesize_2(statements, compressor) {
- function cons_seq(right) {
- n--;
- CHANGED = true;
- var left = prev.body;
- return make_sequence(left, [ left, right ]);
- }
- var n = 0, prev;
+ var changed = false, n = 0, prev;
for (var i = 0; i < statements.length; i++) {
var stat = statements[i];
if (prev) {
else {
stat.init = prev.body;
n--;
- CHANGED = true;
+ changed = true;
}
}
}
i += len;
n += len + 1;
prev = null;
- CHANGED = true;
+ changed = true;
continue;
}
}
prev = stat instanceof AST_SimpleStatement ? stat : null;
}
statements.length = n;
+ return changed;
+
+ function cons_seq(right) {
+ n--;
+ changed = true;
+ var left = prev.body;
+ return make_sequence(left, [ left, right ]);
+ }
}
function extract_exprs(body) {
}
function join_consecutive_vars(statements) {
- var defs;
+ var changed = false, defs;
for (var i = 0, j = -1; i < statements.length; i++) {
var stat = statements[i];
var prev = statements[j];
if (stat instanceof AST_Definitions) {
if (prev && prev.TYPE == stat.TYPE) {
prev.definitions = prev.definitions.concat(stat.definitions);
- CHANGED = true;
+ changed = true;
} else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
defs.definitions = defs.definitions.concat(stat.definitions);
- CHANGED = true;
+ changed = true;
} else if (stat instanceof AST_Var) {
var exprs = merge_assigns(prev, stat);
if (exprs) {
prev.body = make_sequence(prev, exprs);
j++;
}
- CHANGED = true;
+ changed = true;
} else {
j++;
}
} else if (stat instanceof AST_For) {
var exprs = join_assigns(prev, stat.init);
if (exprs) {
- CHANGED = true;
+ changed = true;
stat.init = exprs.length ? make_sequence(stat.init, exprs) : null;
} else if (prev instanceof AST_Var && (!stat.init || stat.init.TYPE == prev.TYPE)) {
if (stat.init) {
}
defs = stat.init = prev;
statements[j] = merge_defns(stat);
- CHANGED = true;
+ changed = true;
continue;
} else if (defs && stat.init && defs.TYPE == stat.init.TYPE && declarations_only(stat.init)) {
defs.definitions = defs.definitions.concat(stat.init.definitions);
stat.init = null;
- CHANGED = true;
+ changed = true;
} else if (stat.init instanceof AST_Var) {
defs = stat.init;
exprs = merge_assigns(prev, stat.init);
if (exprs) {
- CHANGED = true;
+ changed = true;
if (exprs.length == 0) {
statements[j] = merge_defns(stat);
continue;
name.definition().references.push(ref);
});
defs.definitions = defns;
- CHANGED = true;
+ changed = true;
}
stat.object = join_assigns_expr(stat.object);
} else if (stat instanceof AST_If) {
} else if (stat instanceof AST_SimpleStatement) {
var exprs = join_assigns(prev, stat.body);
if (exprs) {
- CHANGED = true;
+ changed = true;
if (!exprs.length) continue;
stat.body = make_sequence(stat.body, exprs);
}
statements[++j] = defs ? merge_defns(stat) : stat;
}
statements.length = j + 1;
+ return changed;
function join_assigns_expr(value) {
var exprs = join_assigns(prev, value, 1);
if (!exprs) return value;
- CHANGED = true;
+ changed = true;
var tail = value.tail_node();
if (exprs[exprs.length - 1] !== tail) exprs.push(tail.left);
return make_sequence(value, exprs);
if (parent instanceof AST_ForEnumeration && parent.init === node) return node;
if (!declarations_only(node)) return node;
defs.definitions = defs.definitions.concat(node.definitions);
- CHANGED = true;
+ changed = true;
if (parent instanceof AST_For && parent.init === node) return null;
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
}