diff options
author | kzc <zaxxon2011@gmail.com> | 2015-11-24 13:27:50 -0500 |
---|---|---|
committer | kzc <zaxxon2011@gmail.com> | 2015-11-24 13:27:50 -0500 |
commit | 774bda13cdf8de39de7f236ed95ae3da4fc7d822 (patch) | |
tree | 9a116ff09dc276a730ce569d18ae8d1179049887 | |
parent | 15b5f70338695c435cab05b7ac2de29cad230360 (diff) | |
download | tracifyjs-774bda13cdf8de39de7f236ed95ae3da4fc7d822.tar.gz tracifyjs-774bda13cdf8de39de7f236ed95ae3da4fc7d822.zip |
#873 Fix `conditionals` optimizations with default compress options
-rw-r--r-- | lib/compress.js | 66 | ||||
-rw-r--r-- | test/compress/conditionals.js | 204 |
2 files changed, 253 insertions, 17 deletions
diff --git a/lib/compress.js b/lib/compress.js index 32833ebf..44e19799 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -726,6 +726,32 @@ merge(Compressor.prototype, { return [ this ]; } }); + AST_Node.DEFMETHOD("is_constant", function(compressor){ + // Accomodate when compress option evaluate=false + // as well as the common constant expressions !0 and !1 + return this instanceof AST_Constant + || (this instanceof AST_UnaryPrefix && this.operator == "!" + && this.expression instanceof AST_Constant) + || this.evaluate(compressor).length > 1; + }); + // Obtain the constant value of an expression already known to be constant. + // Result only valid iff this.is_constant(compressor) is true. + AST_Node.DEFMETHOD("constant_value", function(compressor){ + // Accomodate when option evaluate=false. + if (this instanceof AST_Constant) return this.value; + // Accomodate the common constant expressions !0 and !1 when option evaluate=false. + if (this instanceof AST_UnaryPrefix + && this.operator == "!" + && this.expression instanceof AST_Constant) { + return !this.expression.value; + } + var result = this.evaluate(compressor) + if (result.length > 1) { + return result[1]; + } + // should never be reached + return undefined; + }); def(AST_Statement, function(){ throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); }); @@ -2427,32 +2453,48 @@ merge(Compressor.prototype, { alternative: alternative }); } - // x=y?1:1 --> x=1 - if (consequent instanceof AST_Constant - && alternative instanceof AST_Constant + // y?1:1 --> 1 + if (consequent.is_constant(compressor) + && alternative.is_constant(compressor) && consequent.equivalent_to(alternative)) { + var consequent_value = consequent.constant_value(); if (self.condition.has_side_effects(compressor)) { - return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent.value, self)]); + return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent_value, self)]); } else { - return make_node_from_constant(compressor, consequent.value, self); - + return make_node_from_constant(compressor, consequent_value, self); } } - // x=y?true:false --> x=!!y - if (consequent instanceof AST_True - && alternative instanceof AST_False) { + + // y?true:false --> !!y + if (is_true(consequent) && is_false(alternative)) { self.condition = self.condition.negate(compressor); return make_node(AST_UnaryPrefix, self.condition, { operator: "!", expression: self.condition }); } - // x=y?false:true --> x=!y - if (consequent instanceof AST_False - && alternative instanceof AST_True) { + // y?false:true --> !y + if (is_false(consequent) && is_true(alternative)) { return self.condition.negate(compressor) } return self; + + // AST_True or !0 + function is_true(node) { + return node instanceof AST_True + || (node instanceof AST_UnaryPrefix + && node.operator == "!" + && node.expression instanceof AST_Constant + && !node.expression.value); + } + // AST_False or !1 + function is_false(node) { + return node instanceof AST_False + || (node instanceof AST_UnaryPrefix + && node.operator == "!" + && node.expression instanceof AST_Constant + && !!node.expression.value); + } }); OPT(AST_Boolean, function(self, compressor){ diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index 16ef6d66..65cfea64 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -332,53 +332,247 @@ cond_7_1: { cond_8: { options = { conditionals: true, - evaluate : true + evaluate : true, + booleans : false }; input: { var a; // compress these a = condition ? true : false; - a = !condition ? true : false; - a = condition() ? true : false; + a = condition ? !0 : !1; + a = !condition ? !null : !2; + a = condition() ? !0 : !-3.5; + if (condition) { a = true; } else { a = false; } - a = condition ? false : true; + if (condition) { + a = !0; + } else { + a = !1; + } + a = condition ? false : true; a = !condition ? false : true; - a = condition() ? false : true; + a = condition ? !3 : !0; + a = !condition ? !2 : !0; + a = condition() ? !1 : !0; + if (condition) { a = false; } else { a = true; } + if (condition) { + a = !1; + } else { + a = !0; + } + // don't compress these a = condition ? 1 : false; + a = !condition ? true : 0; + a = condition ? 1 : 0; + } + expect: { + var a; + a = !!condition; + a = !condition; + a = !!condition(); + + a = !!condition; + a = !condition; + a = !!condition(); + + a = !!condition; + a = !!condition; + + a = !condition; + a = !!condition; + a = !condition(); + + a = !condition; + a = !!condition; + a = !condition(); + + a = !condition; + a = !condition; + + a = condition ? 1 : false; + a = condition ? 0 : true; + a = condition ? 1 : 0; + } +} +cond_8b: { + options = { + conditionals: true, + evaluate : true, + booleans : true + }; + input: { + var a; + // compress these + a = condition ? true : false; + a = !condition ? true : false; + a = condition() ? true : false; + + a = condition ? !0 : !1; + a = !condition ? !null : !2; + a = condition() ? !0 : !-3.5; + + if (condition) { + a = true; + } else { + a = false; + } + + if (condition) { + a = !0; + } else { + a = !1; + } + + a = condition ? false : true; + a = !condition ? false : true; + a = condition() ? false : true; + + a = condition ? !3 : !0; + a = !condition ? !2 : !0; + a = condition() ? !1 : !0; + + if (condition) { + a = false; + } else { + a = true; + } + + if (condition) { + a = !1; + } else { + a = !0; + } + + a = condition ? 1 : false; a = !condition ? true : 0; + a = condition ? 1 : 0; + } + expect: { + var a; + a = !!condition; + a = !condition; + a = !!condition(); + a = !!condition; + a = !condition; + a = !!condition(); + + a = !!condition; + a = !!condition; + + a = !condition; + a = !!condition; + a = !condition(); + + a = !condition; + a = !!condition; + a = !condition(); + + a = !condition; + a = !condition; + + a = condition ? 1 : !1; + a = condition ? 0 : !0; a = condition ? 1 : 0; + } +} + +cond_8c: { + options = { + conditionals: true, + evaluate : false, + booleans : false + }; + input: { + var a; + // compress these + a = condition ? true : false; + a = !condition ? true : false; + a = condition() ? true : false; + a = condition ? !0 : !1; + a = !condition ? !null : !2; + a = condition() ? !0 : !-3.5; + + if (condition) { + a = true; + } else { + a = false; + } + + if (condition) { + a = !0; + } else { + a = !1; + } + + a = condition ? false : true; + a = !condition ? false : true; + a = condition() ? false : true; + + a = condition ? !3 : !0; + a = !condition ? !2 : !0; + a = condition() ? !1 : !0; + + if (condition) { + a = false; + } else { + a = true; + } + + if (condition) { + a = !1; + } else { + a = !0; + } + + a = condition ? 1 : false; + a = !condition ? true : 0; + a = condition ? 1 : 0; } expect: { var a; a = !!condition; a = !condition; a = !!condition(); + + a = !!condition; + a = !condition; + a = condition() ? !0 : !-3.5; + + a = !!condition; + a = !!condition; + + a = !condition; a = !!condition; + a = !condition(); + a = !condition; a = !!condition; a = !condition(); + a = !condition; + a = !condition; + a = condition ? 1 : false; a = condition ? 0 : true; a = condition ? 1 : 0; |