more sequence optimizations (lift some sequences above binary/unary expressions so...
authorMihai Bazon <mihai@bazon.net>
Mon, 22 Oct 2012 08:49:58 +0000 (11:49 +0300)
committerMihai Bazon <mihai@bazon.net>
Mon, 22 Oct 2012 08:58:06 +0000 (11:58 +0300)
lib/ast.js
lib/compress.js
lib/output.js
test/compress/sequences.js

index 44cbed1..32ec538 100644 (file)
@@ -581,6 +581,18 @@ var AST_Seq = DEFNODE("Seq", "car cdr", {
         }
         return list;
     },
+    to_array: function() {
+        var p = this, a = [];
+        while (p) {
+            a.push(p.car);
+            if (p.cdr && !(p.cdr instanceof AST_Seq)) {
+                a.push(p.cdr);
+                break;
+            }
+            p = p.cdr;
+        }
+        return a;
+    },
     add: function(node) {
         var p = this;
         while (p) {
index 3e5b524..22fb330 100644 (file)
@@ -1380,6 +1380,10 @@ merge(Compressor.prototype, {
     });
 
     OPT(AST_Seq, function(self, compressor){
+        if (!compressor.option("side_effects"))
+            return self;
+        if (!self.car.has_side_effects())
+            return self.cdr;
         if (compressor.option("cascade")) {
             if (self.car instanceof AST_Assign
                 && !self.car.left.has_side_effects()
@@ -1395,7 +1399,26 @@ merge(Compressor.prototype, {
         return self;
     });
 
+    AST_Unary.DEFMETHOD("lift_sequences", function(compressor){
+        if (compressor.option("sequences")) {
+            if (this.expression instanceof AST_Seq) {
+                var seq = this.expression;
+                var x = seq.to_array();
+                this.expression = x.pop();
+                x.push(this);
+                seq = AST_Seq.from_array(x).transform(compressor);
+                return seq;
+            }
+        }
+        return this;
+    });
+
+    OPT(AST_UnaryPostfix, function(self, compressor){
+        return self.lift_sequences(compressor);
+    });
+
     OPT(AST_UnaryPrefix, function(self, compressor){
+        self = self.lift_sequences(compressor);
         var e = self.expression;
         if (compressor.option("booleans") && compressor.in_boolean_context()) {
             switch (self.operator) {
@@ -1418,7 +1441,32 @@ merge(Compressor.prototype, {
         return self.evaluate(compressor)[0];
     });
 
+    AST_Binary.DEFMETHOD("lift_sequences", function(compressor){
+        if (compressor.option("sequences")) {
+            if (this.left instanceof AST_Seq) {
+                var seq = this.left;
+                var x = seq.to_array();
+                this.left = x.pop();
+                x.push(this);
+                seq = AST_Seq.from_array(x).transform(compressor);
+                return seq;
+            }
+            if (this.right instanceof AST_Seq
+                && !(this.operator == "||" || this.operator == "&&")
+                && !this.left.has_side_effects()) {
+                var seq = this.right;
+                var x = seq.to_array();
+                this.right = x.pop();
+                x.push(this);
+                seq = AST_Seq.from_array(x).transform(compressor);
+                return seq;
+            }
+        }
+        return this;
+    });
+
     OPT(AST_Binary, function(self, compressor){
+        self = self.lift_sequences(compressor);
         if (compressor.option("comparisons")) switch (self.operator) {
           case "===":
           case "!==":
@@ -1557,6 +1605,7 @@ merge(Compressor.prototype, {
 
     var ASSIGN_OPS = [ '+', '-', '/', '*', '%', '>>', '<<', '>>>', '|', '^', '&' ];
     OPT(AST_Assign, function(self, compressor){
+        self = self.lift_sequences(compressor);
         if (self.operator == "="
             && self.left instanceof AST_SymbolRef
             && self.right instanceof AST_Binary
index 8d2c4d3..4b515ec 100644 (file)
@@ -414,7 +414,7 @@ function OutputStream(options) {
         var p = output.parent();
         return p instanceof AST_Call             // (foo, bar)() or foo(1, (2, 3), 4)
             || p instanceof AST_Unary            // !(foo, bar, baz)
-            || p instanceof AST_Binary           // 1 + (2, 3) + 4 ==> 7
+            || p instanceof AST_Binary           // 1 + (2, 3) + 4 ==> 8
             || p instanceof AST_VarDef           // var a = (1, 2), b = a + a; ==> b == 4
             || p instanceof AST_Dot              // (1, {foo:2}).foo ==> 2
             || p instanceof AST_Array            // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
index 513bc84..d48eced 100644 (file)
@@ -87,3 +87,43 @@ make_sequences_4: {
         with (x = 5, obj);
     }
 }
+
+lift_sequences_1: {
+    options = { sequences: true };
+    input: {
+        foo = !(x(), y(), bar());
+    }
+    expect: {
+        x(), y(), foo = !bar();
+    }
+}
+
+lift_sequences_2: {
+    options = { sequences: true, evaluate: true };
+    input: {
+        q = 1 + (foo(), bar(), 5) + 7 * (5 / (3 - (a(), (QW=ER), c(), 2))) - (x(), y(), 5);
+    }
+    expect: {
+        foo(), bar(), a(), QW = ER, c(), x(), y(), q = 36
+    }
+}
+
+lift_sequences_3: {
+    options = { sequences: true, conditionals: true };
+    input: {
+        x = (foo(), bar(), baz()) ? 10 : 20;
+    }
+    expect: {
+        foo(), bar(), x = baz() ? 10 : 20;
+    }
+}
+
+lift_sequences_4: {
+    options = { side_effects: true };
+    input: {
+        x = (foo, bar, baz);
+    }
+    expect: {
+        x = baz;
+    }
+}