other small optimization:
authorMihai Bazon <mihai@bazon.net>
Sat, 15 Sep 2012 13:06:09 +0000 (16:06 +0300)
committerMihai Bazon <mihai@bazon.net>
Sat, 15 Sep 2012 13:10:35 +0000 (16:10 +0300)
if (foo) continue;
...body...

==>

if (!foo) { ...body ... }

Only when the parent block is the target loop of the `continue` statement.

lib/compress.js

index 9604729..f8f4d17 100644 (file)
@@ -184,10 +184,44 @@ function Compressor(options, false_by_default) {
         } while (CHANGED);
         return statements;
 
+        /// XXX: this function is UGLY and kinda wrong.
+        ///      I think it would be cleaner if it operates backwards.
         function handle_if_return(statements, compressor) {
-            var in_lambda = compressor.self() instanceof AST_Lambda;
+            var self = compressor.self();
+            var in_lambda = self instanceof AST_Lambda;
             var last = statements.length - 1;
             return MAP(statements, function(stat, i){
+                if (stat instanceof AST_If
+                    && stat.body instanceof AST_Continue
+                    && !stat.alternative
+                    && self === stat.body.target()) {
+                    CHANGED = true;
+                    if (i < last) {
+                        var rest = statements.slice(i + 1);
+                        var cond = stat.condition;
+                        while (rest[0] instanceof AST_If
+                               && rest[0].body instanceof AST_Continue
+                               && self === rest[0].body.target()
+                               && !rest[0].alternative) {
+                            cond = make_node(AST_Binary, rest[0], {
+                                operator: "||",
+                                left: cond,
+                                right: rest[0].condition
+                            });
+                            rest.shift();
+                        }
+                        return MAP.last(make_node(AST_If, stat, {
+                            condition: cond.negate(compressor),
+                            body: make_node(AST_BlockStatement, stat, {
+                                body: rest
+                            }).optimize(compressor)
+                        }).optimize(compressor))
+                    } else {
+                        return make_node(AST_SimpleStatement, stat, {
+                            body: stat.condition
+                        }).optimize(compressor);
+                    }
+                }
                 if (stat instanceof AST_If
                     && stat.body instanceof AST_Return
                     && !stat.alternative
@@ -199,6 +233,7 @@ function Compressor(options, false_by_default) {
                             var cond = stat.condition;
                             while (rest[0] instanceof AST_If
                                    && rest[0].body instanceof AST_Return
+                                   && !rest[0].body.value
                                    && !rest[0].alternative) {
                                 cond = make_node(AST_Binary, rest[0], {
                                     operator: "||",
@@ -645,7 +680,10 @@ function Compressor(options, false_by_default) {
     (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() });
+        def(AST_BlockStatement, function(){
+            var n = this.body.length;
+            return n > 0 && this.body[n - 1].aborts();
+        });
     })(function(node, func){
         node.DEFMETHOD("aborts", func);
     });