Optimize ternaries with boolean consequent or alternative.
authorkzc <zaxxon2011@gmail.com>
Sat, 2 Apr 2016 04:21:13 +0000 (00:21 -0400)
committerRichard van Velzen <rvanvelzen@experty.com>
Sat, 2 Apr 2016 15:22:12 +0000 (17:22 +0200)
Fixes #511

lib/compress.js
test/compress/conditionals.js

index 4f37e83..26c11bd 100644 (file)
@@ -2658,24 +2658,58 @@ merge(Compressor.prototype, {
             }
         }
 
-        // y?true:false --> !!y
-        if (is_true(consequent) && is_false(alternative)) {
-            if (self.condition.is_boolean()) {
-                // boolean_expression ? true : false --> boolean_expression
-                return self.condition;
-            }
-            self.condition = self.condition.negate(compressor);
-            return make_node(AST_UnaryPrefix, self.condition, {
-                operator: "!",
-                expression: self.condition
+        if (is_true(self.consequent)) {
+            if (is_false(self.alternative)) {
+                // c ? true : false ---> !!c
+                return booleanize(self.condition);
+            }
+            // c ? true : x ---> !!c || x
+            return make_node(AST_Binary, self, {
+                operator: "||",
+                left: booleanize(self.condition),
+                right: self.alternative
+            });
+        }
+        if (is_false(self.consequent)) {
+            if (is_true(self.alternative)) {
+                // c ? false : true ---> !c
+                return booleanize(self.condition.negate(compressor));
+            }
+            // c ? false : x ---> !c && x
+            return make_node(AST_Binary, self, {
+                operator: "&&",
+                left: booleanize(self.condition.negate(compressor)),
+                right: self.alternative
+            });
+        }
+        if (is_true(self.alternative)) {
+            // c ? x : true ---> !c || x
+            return make_node(AST_Binary, self, {
+                operator: "||",
+                left: booleanize(self.condition.negate(compressor)),
+                right: self.consequent
             });
         }
-        // y?false:true --> !y
-        if (is_false(consequent) && is_true(alternative)) {
-            return self.condition.negate(compressor)
+        if (is_false(self.alternative)) {
+            // c ? x : false ---> !!c && x
+            return make_node(AST_Binary, self, {
+                operator: "&&",
+                left: booleanize(self.condition),
+                right: self.consequent
+            });
         }
+
         return self;
 
+        function booleanize(node) {
+            if (node.is_boolean()) return node;
+            // !!expression
+            return make_node(AST_UnaryPrefix, node, {
+                operator: "!",
+                expression: node.negate(compressor)
+            });
+        }
+
         // AST_True or !0
         function is_true(node) {
             return node instanceof AST_True
index db0d800..f5eeb6f 100644 (file)
@@ -407,8 +407,8 @@ cond_8: {
         a = !condition;
         a = !condition;
 
-        a = condition ? 1 : false;
-        a = condition ? 0 : true;
+        a = !!condition && 1;
+        a = !condition || 0;
         a = condition ? 1 : 0;
     }
 }
@@ -490,8 +490,8 @@ cond_8b: {
         a = !condition;
         a = !condition;
 
-        a = condition ? 1 : !1;
-        a = condition ? 0 : !0;
+        a = !!condition && 1;
+        a = !condition || 0;
         a = condition ? 1 : 0;
     }
 }
@@ -557,7 +557,7 @@ cond_8c: {
 
         a = !!condition;
         a = !condition;
-        a = condition() ? !0 : !-3.5;
+        a = !!condition() || !-3.5;
 
         a = !!condition;
         a = !!condition;
@@ -573,12 +573,68 @@ cond_8c: {
         a = !condition;
         a = !condition;
 
-        a = condition ? 1 : false;
-        a = condition ? 0 : true;
+        a = !!condition && 1;
+        a = !condition || 0;
         a = condition ? 1 : 0;
     }
 }
 
+ternary_boolean_consequent: {
+    options = {
+        collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
+        comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
+        keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
+    }
+    input: {
+        function f1() { return a == b ? true : x; }
+        function f2() { return a == b ? false : x; }
+        function f3() { return a < b ? !0 : x; }
+        function f4() { return a < b ? !1 : x; }
+        function f5() { return c ? !0 : x; }
+        function f6() { return c ? false : x; }
+        function f7() { return !c ? true : x; }
+        function f8() { return !c ? !1 : x; }
+    }
+    expect: {
+        function f1() { return a == b || x; }
+        function f2() { return a != b && x; }
+        function f3() { return a < b || x; }
+        function f4() { return !(a < b) && x; }
+        function f5() { return !!c || x; }
+        function f6() { return !c && x; }
+        function f7() { return !c || x; }
+        function f8() { return !!c && x; }
+    }
+}
+
+ternary_boolean_alternative: {
+    options = {
+        collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
+        comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
+        keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
+    }
+    input: {
+        function f1() { return a == b ? x : true; }
+        function f2() { return a == b ? x : false; }
+        function f3() { return a < b ? x : !0; }
+        function f4() { return a < b ? x : !1; }
+        function f5() { return c ? x : true; }
+        function f6() { return c ? x : !1; }
+        function f7() { return !c ? x : !0; }
+        function f8() { return !c ? x : false; }
+    }
+    expect: {
+        function f1() { return a != b || x; }
+        function f2() { return a == b && x; }
+        function f3() { return !(a < b) || x; }
+        function f4() { return a < b && x; }
+        function f5() { return !c || x; }
+        function f6() { return !!c && x; }
+        function f7() { return !!c || x; }
+        function f8() { return !c && x; }
+    }
+}
+
 conditional_and: {
     options = {
         conditionals: true,