diff options
-rw-r--r-- | lib/compress.js | 87 | ||||
-rw-r--r-- | lib/utils.js | 13 |
2 files changed, 85 insertions, 15 deletions
diff --git a/lib/compress.js b/lib/compress.js index 06b133f9..02b9e243 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -122,17 +122,17 @@ function Compressor(options, false_by_default) { }; function SQUEEZE(nodetype, squeeze) { - nodetype.DEFMETHOD("squeeze", function(compressor){ + nodetype.DEFMETHOD("squeeze", function(compressor, block, index){ compressor.push_node(this); - var new_node = squeeze(this, compressor); + var new_node = squeeze(this, compressor, block, index); compressor.pop_node(); return new_node !== undefined ? new_node : this; }); }; function do_list(array, compressor, splice_blocks) { - return MAP(array, function(node){ - node = node.squeeze(compressor); + return MAP(array, function(node, i){ + node = node.squeeze(compressor, array, i); if (splice_blocks) { if (node instanceof AST_BlockStatement) { return MAP.splice(eliminate_spurious_blocks(node.body)); @@ -222,7 +222,8 @@ function Compressor(options, false_by_default) { } else if (i == last && cur instanceof AST_Exit && cur.value - && a.length == 1 && prev instanceof AST_SimpleStatement) { + && a.length > 0 + && prev instanceof AST_SimpleStatement) { // it only makes sense to do this transformation // if the AST gets to a single statement. var seq = make_node(AST_Seq, prev, { @@ -230,7 +231,9 @@ function Compressor(options, false_by_default) { second: cur.value }); cur.value = seq; - return [ cur ]; + a.pop(); + a.push(cur); + return a; } else { a.push(cur); @@ -459,7 +462,9 @@ function Compressor(options, false_by_default) { return basic_negation(this); }); })(function(node, func){ - node.DEFMETHOD("negate", func); + node.DEFMETHOD("negate", function(compressor){ + return func.call(this, compressor).optimize(compressor); + }); }); // determine if expression has side effects @@ -494,6 +499,15 @@ function Compressor(options, false_by_default) { node.DEFMETHOD("has_side_effects", func); }); + // tell me if a statement aborts + (function(def){ + def(AST_StatementBase, function(){ return null }); + def(AST_Jump, function(){ return this }); + def(AST_BlockStatement, function(){ return this.body[this.body.length - 1].aborts() }); + })(function(node, func){ + node.DEFMETHOD("aborts", func); + }); + /* -----[ node squeezers ]----- */ SQUEEZE(AST_Debugger, function(self, compressor){ @@ -516,9 +530,13 @@ function Compressor(options, false_by_default) { SQUEEZE(AST_BlockStatement, function(self, compressor){ self = self.clone(); self.body = tighten_body(self.body, compressor); - if (self.body.length == 1) - return self.body[0]; - return self; + return self.optimize(compressor); + }); + + AST_BlockStatement.DEFMETHOD("optimize", function(compressor){ + if (this.body.length == 1) + return this.body[0]; + return this; }); SQUEEZE(AST_Block, function(self, compressor){ @@ -705,16 +723,16 @@ function Compressor(options, false_by_default) { return self; }); - SQUEEZE(AST_If, function(self, compressor){ + SQUEEZE(AST_If, function(self, compressor, block, index){ self = self.clone(); self.condition = self.condition.squeeze(compressor); self.body = self.body.squeeze(compressor); if (self.alternative) self.alternative = self.alternative.squeeze(compressor); - return self.optimize(compressor); + return self.optimize(compressor, block, index); }); - AST_If.DEFMETHOD("optimize", function(compressor){ + AST_If.DEFMETHOD("optimize", function(compressor, block, index){ var self = this; if (!compressor.option("conditionals")) return self; // if condition can be statically determined, warn and drop @@ -809,6 +827,49 @@ function Compressor(options, false_by_default) { }).optimize(compressor) }); } + if (self.body instanceof AST_Return + && !self.body.value + && !self.alternative + && index < block.length - 1) { + if (compressor.parent() instanceof AST_Lambda) { + var rest = tighten_body(block.slice(index + 1), compressor); + var cond = negated_is_best ? negated : self.condition.negate(compressor); + while (rest[0] instanceof AST_If && rest[0].body instanceof AST_Return && !rest[0].alternative) { + cond = make_node(AST_Binary, rest[0], { + operator: "&&", + left: cond, + right: rest[0].condition.negate(compressor) + }); + rest.shift(); + } + return MAP.last(make_node(AST_If, self, { + condition: cond, + body: make_node(AST_BlockStatement, block[index + 1], { + body: rest + }).optimize(compressor) + }).optimize(compressor)); + } + } + if (self.body instanceof AST_If + && !self.body.alternative + && !self.alternative) { + self.condition = make_node(AST_Binary, self.condition, { + operator: "&&", + left: self.condition, + right: self.body.condition + }); + self.body = self.body.body; + } + var abort = self.body.aborts(); + if (abort) { + if (self.alternative) { + var alt = self.alternative; + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, alt ] + }).optimize(compressor); + } + } return self; }); diff --git a/lib/utils.js b/lib/utils.js index e9a2f80a..6f8334ee 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -113,6 +113,8 @@ var MAP = (function(){ var ret = [], top = [], i; function doit() { var val = f.call(o, a[i], i); + var is_last = val instanceof Last; + if (is_last) val = val.v; if (val instanceof AtTop) { val = val.v; if (val instanceof Splice) { @@ -128,16 +130,23 @@ var MAP = (function(){ ret.push(val); } } + return is_last; }; - if (a instanceof Array) for (i = 0; i < a.length; ++i) doit(); - else for (i in a) if (HOP(a, i)) doit(); + if (a instanceof Array) { + for (i = 0; i < a.length; ++i) if (doit()) break; + } + else { + for (i in a) if (HOP(a, i)) if (doit()) break; + } return top.concat(ret); }; MAP.at_top = function(val) { return new AtTop(val) }; MAP.splice = function(val) { return new Splice(val) }; + MAP.last = function(val) { return new Last(val) }; var skip = MAP.skip = {}; function AtTop(val) { this.v = val }; function Splice(val) { this.v = val }; + function Last(val) { this.v = val }; return MAP; })(); |