From 30faaf13edca3a4db6867e8faf0f0b68c6ac11e0 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Mon, 22 Oct 2012 11:49:58 +0300 Subject: [PATCH] more sequence optimizations (lift some sequences above binary/unary expressions so that we can avoid parens) --- lib/ast.js | 12 ++++++++++ lib/compress.js | 49 ++++++++++++++++++++++++++++++++++++++ lib/output.js | 2 +- test/compress/sequences.js | 40 +++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/lib/ast.js b/lib/ast.js index 44cbed12..32ec5380 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -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) { diff --git a/lib/compress.js b/lib/compress.js index 3e5b524d..22fb330e 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -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 diff --git a/lib/output.js b/lib/output.js index 8d2c4d39..4b515ecd 100644 --- a/lib/output.js +++ b/lib/output.js @@ -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 ] diff --git a/test/compress/sequences.js b/test/compress/sequences.js index 513bc84b..d48eced2 100644 --- a/test/compress/sequences.js +++ b/test/compress/sequences.js @@ -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; + } +} -- 2.34.1