From 98434258d0839cb02de8b723df0cafe40c6cf218 Mon Sep 17 00:00:00 2001 From: kzc Date: Sat, 2 Apr 2016 00:21:13 -0400 Subject: [PATCH] Optimize ternaries with boolean consequent or alternative. Fixes #511 --- lib/compress.js | 60 +++++++++++++++++++++++------- test/compress/conditionals.js | 70 +++++++++++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 20 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 4f37e834..26c11bd9 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -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 diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index db0d8000..f5eeb6f2 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -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, -- 2.34.1