aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2019-10-27 03:07:07 +0800
committerGitHub <noreply@github.com>2019-10-27 03:07:07 +0800
commit50a578c1f63e61654d71642cbfa35f41da9bd626 (patch)
treedc334902dc1eed057ab9d54a669b41a01126cce2
parent85237b08d46c62a97c9b338c4e62d71cdba76e24 (diff)
downloadtracifyjs-50a578c1f63e61654d71642cbfa35f41da9bd626.tar.gz
tracifyjs-50a578c1f63e61654d71642cbfa35f41da9bd626.zip
compress arithmetic expressions further (#3529)
-rw-r--r--lib/compress.js152
-rw-r--r--test/compress/asm.js2
-rw-r--r--test/compress/numbers.js353
3 files changed, 432 insertions, 75 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 03c1f590..6d8c1f8f 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -2437,9 +2437,10 @@ merge(Compressor.prototype, {
|| this.operator == "=" && this.right.is_number(compressor);
});
def(AST_Binary, function(compressor) {
- return binary[this.operator] || this.operator == "+"
- && this.left.is_number(compressor)
- && this.right.is_number(compressor);
+ if (binary[this.operator]) return true;
+ if (this.operator != "+") return false;
+ return (this.left.is_boolean(compressor) || this.left.is_number(compressor))
+ && (this.right.is_boolean(compressor) || this.right.is_number(compressor));
});
var fn = makePredicate([
"charCodeAt",
@@ -5777,6 +5778,7 @@ merge(Compressor.prototype, {
}
}
if (compressor.option("evaluate")) {
+ var associative = true;
switch (self.operator) {
case "&&":
var ll = fuzzy_eval(self.left);
@@ -5845,9 +5847,6 @@ merge(Compressor.prototype, {
}).optimize(compressor);
}
break;
- }
- var associative = true;
- switch (self.operator) {
case "+":
// "foo" + ("bar" + x) => "foobar" + x
if (self.left instanceof AST_Constant
@@ -5927,13 +5926,38 @@ merge(Compressor.prototype, {
});
break;
}
+ case "-":
+ // a - -b => a + b
+ if (self.right instanceof AST_UnaryPrefix
+ && self.right.operator == "-"
+ && self.left.is_number(compressor)) {
+ self = make_node(AST_Binary, self, {
+ operator: "+",
+ left: self.left,
+ right: self.right.expression
+ });
+ break;
+ }
case "*":
+ case "/":
associative = compressor.option("unsafe_math");
+ // +a - b => a - b
+ // a - +b => a - b
+ if (self.operator != "+") {
+ if (self.left instanceof AST_UnaryPrefix && self.left.operator == "+") {
+ self.left = self.left.expression;
+ }
+ if (self.right instanceof AST_UnaryPrefix && self.right.operator == "+") {
+ self.right = self.right.expression;
+ }
+ }
case "&":
case "|":
case "^":
// a + +b => +b + a
- if (self.left.is_number(compressor)
+ if (self.operator != "-"
+ && self.operator != "/"
+ && self.left.is_number(compressor)
&& self.right.is_number(compressor)
&& reversible()
&& !(self.left instanceof AST_Binary
@@ -5951,77 +5975,56 @@ merge(Compressor.prototype, {
self = best_of(compressor, self, reversed);
}
}
- if (associative && self.is_number(compressor)) {
- // a + (b + c) => (a + b) + c
- if (self.right instanceof AST_Binary
- && self.right.operator == self.operator) {
- self = make_node(AST_Binary, self, {
+ if (!associative || !self.is_number(compressor)) break;
+ // a + (b + c) => (a + b) + c
+ if (self.right instanceof AST_Binary
+ && self.right.operator != "%"
+ && PRECEDENCE[self.right.operator] == PRECEDENCE[self.operator]) {
+ self = make_node(AST_Binary, self, {
+ operator: align(self.operator, self.right.operator),
+ left: make_node(AST_Binary, self.left, {
operator: self.operator,
+ left: self.left,
+ right: self.right.left,
+ start: self.left.start,
+ end: self.right.left.end
+ }),
+ right: self.right.right
+ });
+ }
+ // (2 * n) * 3 => 6 * n
+ // (n + 2) + 3 => n + 5
+ if (self.right instanceof AST_Constant
+ && self.left instanceof AST_Binary
+ && self.left.operator != "%"
+ && PRECEDENCE[self.left.operator] == PRECEDENCE[self.operator]) {
+ if (self.left.left instanceof AST_Constant) {
+ self = make_node(AST_Binary, self, {
+ operator: self.left.operator,
left: make_node(AST_Binary, self.left, {
operator: self.operator,
- left: self.left,
- right: self.right.left,
- start: self.left.start,
- end: self.right.left.end
+ left: self.left.left,
+ right: self.right,
+ start: self.left.left.start,
+ end: self.right.end
}),
- right: self.right.right
+ right: self.left.right
});
- }
- // (n + 2) + 3 => 5 + n
- // (2 * n) * 3 => 6 + n
- if (self.right instanceof AST_Constant
- && self.left instanceof AST_Binary
- && self.left.operator == self.operator) {
- if (self.left.left instanceof AST_Constant) {
- self = make_node(AST_Binary, self, {
- operator: self.operator,
- left: make_node(AST_Binary, self.left, {
- operator: self.operator,
- left: self.left.left,
- right: self.right,
- start: self.left.left.start,
- end: self.right.end
- }),
- right: self.left.right
- });
- } else if (self.left.right instanceof AST_Constant) {
- self = make_node(AST_Binary, self, {
- operator: self.operator,
- left: make_node(AST_Binary, self.left, {
- operator: self.operator,
- left: self.left.right,
- right: self.right,
- start: self.left.right.start,
- end: self.right.end
- }),
- right: self.left.left
- });
- }
- }
- // (a | 1) | (2 | d) => (3 | a) | b
- if (self.left instanceof AST_Binary
- && self.left.operator == self.operator
- && self.left.right instanceof AST_Constant
- && self.right instanceof AST_Binary
- && self.right.operator == self.operator
- && self.right.left instanceof AST_Constant) {
+ } else if (self.left.right instanceof AST_Constant) {
self = make_node(AST_Binary, self, {
- operator: self.operator,
- left: make_node(AST_Binary, self.left, {
- operator: self.operator,
- left: make_node(AST_Binary, self.left.left, {
- operator: self.operator,
- left: self.left.right,
- right: self.right.left,
- start: self.left.right.start,
- end: self.right.left.end
- }),
- right: self.left.left
- }),
- right: self.right.right
+ operator: self.left.operator,
+ left: self.left.left,
+ right: make_node(AST_Binary, self.left, {
+ operator: align(self.left.operator, self.operator),
+ left: self.left.right,
+ right: self.right,
+ start: self.left.right.start,
+ end: self.right.end
+ })
});
}
}
+ break;
}
}
if (compressor.option("unsafe")) {
@@ -6086,6 +6089,17 @@ merge(Compressor.prototype, {
}
return self;
+ function align(ref, op) {
+ switch (ref) {
+ case "-":
+ return op == "+" ? "-" : "+";
+ case "/":
+ return op == "*" ? "/" : "*";
+ default:
+ return op;
+ }
+ }
+
function fuzzy_eval(node) {
if (node.truthy) return true;
if (node.falsy) return false;
diff --git a/test/compress/asm.js b/test/compress/asm.js
index cebe6838..1f00f8f2 100644
--- a/test/compress/asm.js
+++ b/test/compress/asm.js
@@ -96,7 +96,7 @@ asm_mixed: {
return +sum;
}
function geometricMean(start, end) {
- return start |= 0, end |= 0, +exp(+logSum(start, end) / +(end - start | 0));
+ return start |= 0, end |= 0, +exp(logSum(start, end) / (end - start | 0));
}
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
return { geometricMean: geometricMean };
diff --git a/test/compress/numbers.js b/test/compress/numbers.js
index 000b9ab5..3f579781 100644
--- a/test/compress/numbers.js
+++ b/test/compress/numbers.js
@@ -51,17 +51,20 @@ comparisons: {
comparisons: true,
}
input: {
+ var x = "42", y = "0x30";
console.log(
~x === 42,
- x % n === 42
+ x % y === 42
);
}
expect: {
+ var x = "42", y = "0x30";
console.log(
42 == ~x,
- x % n == 42
+ x % y == 42
);
}
+ expect_stdout: "false true"
}
evaluate_1: {
@@ -103,12 +106,94 @@ evaluate_1: {
}
}
+evaluate_1_unsafe_math: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ console.log(
+ x + 1 + 2,
+ x * 1 * 2,
+ +x + 1 + 2,
+ 1 + x + 2 + 3,
+ 1 | x | 2 | 3,
+ 1 + x-- + 2 + 3,
+ 1 + (x*y + 2) + 3,
+ 1 + (2 + x + 3),
+ 1 + (2 + ~x + 3),
+ -y + (2 + ~x + 3),
+ 1 & (2 & x & 3),
+ 1 + (2 + (x |= 0) + 3)
+ );
+ }
+ expect: {
+ console.log(
+ x + 1 + 2,
+ 2 * x,
+ +x + 3,
+ 1 + x + 2 + 3,
+ 3 | x,
+ 6 + x--,
+ x*y + 6,
+ 1 + (2 + x + 3),
+ 6 + ~x,
+ 5 - y + ~x,
+ 0 & x,
+ 6 + (x |= 0)
+ );
+ }
+}
+
evaluate_2: {
options = {
evaluate: true,
+ unsafe_math: false,
+ }
+ input: {
+ var x = "42", y = null;
+ console.log(
+ x + 1 + 2,
+ x * 1 * 2,
+ +x + 1 + 2,
+ 1 + x + 2 + 3,
+ 1 | x | 2 | 3,
+ 1 + x-- + 2 + 3,
+ 1 + (x*y + 2) + 3,
+ 1 + (2 + x + 3),
+ 1 + (2 + ~x + 3),
+ -y + (2 + ~x + 3),
+ 1 & (2 & x & 3),
+ 1 + (2 + (x |= 0) + 3)
+ );
+ }
+ expect: {
+ var x = "42", y = null;
+ console.log(
+ x + 1 + 2,
+ 1 * x * 2,
+ +x + 1 + 2,
+ 1 + x + 2 + 3,
+ 3 | x,
+ 1 + x-- + 2 + 3,
+ x*y + 2 + 1 + 3,
+ 1 + (2 + x + 3),
+ 2 + ~x + 3 + 1,
+ 2 + ~x + 3 - y,
+ 0 & x,
+ 2 + (x |= 0) + 3 + 1
+ );
+ }
+ expect_stdout: "4212 84 45 14223 43 48 6 47 -36 -37 0 47"
+}
+
+evaluate_2_unsafe_math: {
+ options = {
+ evaluate: true,
unsafe_math: true,
}
input: {
+ var x = "42", y = null;
console.log(
x + 1 + 2,
x * 1 * 2,
@@ -118,24 +203,30 @@ evaluate_2: {
1 + x-- + 2 + 3,
1 + (x*y + 2) + 3,
1 + (2 + x + 3),
+ 1 + (2 + ~x + 3),
+ -y + (2 + ~x + 3),
1 & (2 & x & 3),
1 + (2 + (x |= 0) + 3)
);
}
expect: {
+ var x = "42", y = null;
console.log(
x + 1 + 2,
2 * x,
- 3 + +x,
+ +x + 3,
1 + x + 2 + 3,
3 | x,
6 + x--,
- 6 + x*y,
+ x*y + 6,
1 + (2 + x + 3),
+ 6 + ~x,
+ 5 + ~x - y,
0 & x,
6 + (x |= 0)
);
}
+ expect_stdout: "4212 84 45 14223 43 48 6 47 -36 -37 0 47"
}
evaluate_3: {
@@ -148,7 +239,7 @@ evaluate_3: {
console.log(1 + Number(x) + 2);
}
expect: {
- console.log(3 + +x);
+ console.log(+x + 3);
}
}
@@ -182,6 +273,258 @@ evaluate_4: {
}
}
+evaluate_5: {
+ options = {
+ evaluate: true,
+ unsafe_math: false,
+ }
+ input: {
+ var a = true;
+ console.log(
+ +a + 2 + 3,
+ +a + 2 - 3,
+ +a - 2 + 3,
+ +a - 2 - 3,
+ 2 + +a + 3,
+ 2 + +a - 3,
+ 2 - +a + 3,
+ 2 - +a - 3,
+ 2 + 3 + +a,
+ 2 + 3 - +a,
+ 2 - 3 + +a,
+ 2 - 3 - +a
+ );
+ }
+ expect: {
+ var a = true;
+ console.log(
+ +a + 2 + 3,
+ +a + 2 - 3,
+ a - 2 + 3,
+ a - 2 - 3,
+ +a + 2 + 3,
+ +a + 2 - 3,
+ 2 - a + 3,
+ 2 - a - 3,
+ +a + 5,
+ 5 - a,
+ +a - 1,
+ -1 - a
+ );
+ }
+ expect_stdout: "6 0 2 -4 6 0 4 -2 6 4 0 -2"
+}
+
+evaluate_5_unsafe_math: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var a = true;
+ console.log(
+ +a + 2 + 3,
+ +a + 2 - 3,
+ +a - 2 + 3,
+ +a - 2 - 3,
+ 2 + +a + 3,
+ 2 + +a - 3,
+ 2 - +a + 3,
+ 2 - +a - 3,
+ 2 + 3 + +a,
+ 2 + 3 - +a,
+ 2 - 3 + +a,
+ 2 - 3 - +a
+ );
+ }
+ expect: {
+ var a = true;
+ console.log(
+ +a + 5,
+ +a + -1,
+ a - -1,
+ a - 5,
+ +a + 5,
+ +a + -1,
+ 5 - a,
+ -1 - a,
+ +a + 5,
+ 5 - a,
+ +a - 1,
+ -1 - a
+ );
+ }
+ expect_stdout: "6 0 2 -4 6 0 4 -2 6 4 0 -2"
+}
+
+evaluate_6: {
+ options = {
+ evaluate: true,
+ unsafe_math: false,
+ }
+ input: {
+ var a = true;
+ console.log(
+ -a + 2 + 3,
+ -a + 2 - 3,
+ -a - 2 + 3,
+ -a - 2 - 3,
+ 2 + -a + 3,
+ 2 + -a - 3,
+ 2 - -a + 3,
+ 2 - -a - 3,
+ 2 + 3 + -a,
+ 2 + 3 - -a,
+ 2 - 3 + -a,
+ 2 - 3 - -a
+ );
+ }
+ expect: {
+ var a = true;
+ console.log(
+ 2 - a + 3,
+ 2 - a - 3,
+ -a - 2 + 3,
+ -a - 2 - 3,
+ 2 - a + 3,
+ 2 - a - 3,
+ 2 + a + 3,
+ 2 + a - 3,
+ 5 - a,
+ 5 + a,
+ -1 - a,
+ -1 + a
+ );
+ }
+ expect_stdout: "4 -2 0 -6 4 -2 6 0 4 6 -2 0"
+}
+
+evaluate_6_unsafe_math: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var a = true;
+ console.log(
+ -a + 2 + 3,
+ -a + 2 - 3,
+ -a - 2 + 3,
+ -a - 2 - 3,
+ 2 + -a + 3,
+ 2 + -a - 3,
+ 2 - -a + 3,
+ 2 - -a - 3,
+ 2 + 3 + -a,
+ 2 + 3 - -a,
+ 2 - 3 + -a,
+ 2 - 3 - -a
+ );
+ }
+ expect: {
+ var a = true;
+ console.log(
+ 5 - a,
+ -1 - a,
+ -a - -1,
+ -a - 5,
+ 5 - a,
+ -1 - a,
+ 2 + a + 3,
+ -1 + a,
+ 5 - a,
+ 5 + a,
+ -1 - a,
+ -1 + a
+ );
+ }
+ expect_stdout: "4 -2 0 -6 4 -2 6 0 4 6 -2 0"
+}
+
+evaluate_7: {
+ options = {
+ evaluate: true,
+ unsafe_math: false,
+ }
+ input: {
+ var x = "42", y;
+ console.log(
+ +x + 2 + (3 + !y),
+ +x + 2 + (3 - !y),
+ +x + 2 - (3 + !y),
+ +x + 2 - (3 - !y),
+ +x - 2 + (3 + !y),
+ +x - 2 + (3 - !y),
+ +x - 2 - (3 + !y),
+ +x - 2 - (3 - !y)
+ );
+ }
+ expect: {
+ var x = "42", y;
+ console.log(
+ +x + 2 + (3 + !y),
+ +x + 2 + (3 - !y),
+ +x + 2 - (3 + !y),
+ +x + 2 - (3 - !y),
+ x - 2 + (3 + !y),
+ x - 2 + (3 - !y),
+ x - 2 - (3 + !y),
+ x - 2 - (3 - !y)
+ );
+ }
+ expect_stdout: "48 46 40 42 44 42 36 38"
+}
+
+evaluate_7_unsafe_math: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var x = "42", y;
+ console.log(
+ +x + 2 + (3 + !y),
+ +x + 2 + (3 - !y),
+ +x + 2 - (3 + !y),
+ +x + 2 - (3 - !y),
+ +x - 2 + (3 + !y),
+ +x - 2 + (3 - !y),
+ +x - 2 - (3 + !y),
+ +x - 2 - (3 - !y)
+ );
+ }
+ expect: {
+ var x = "42", y;
+ console.log(
+ +x + 5 + !y,
+ +x + 5 - !y,
+ +x + -1 - !y,
+ +x + -1 + !y,
+ x - -1 + !y,
+ x - -1 - !y,
+ x - 5 - !y,
+ x - 5 + !y
+ );
+ }
+ expect_stdout: "48 46 40 42 44 42 36 38"
+}
+
+NaN_redefined: {
+ options = {
+ evaluate: true,
+ unsafe_math: true,
+ }
+ input: {
+ var NaN;
+ console.log(1 / (0 / 0));
+ }
+ expect: {
+ var NaN;
+ console.log(0 / 0);
+ }
+ expect_stdout: "NaN"
+}
+
issue_1710: {
options = {
evaluate: true,