fix corner case in evaluate (#4138)

fixes #4137
This commit is contained in:
Alex Lam S.L
2020-09-21 23:49:32 +01:00
committed by GitHub
parent 8fa470c17c
commit 13cdc167a2
3 changed files with 264 additions and 203 deletions

View File

@@ -3106,7 +3106,12 @@ merge(Compressor.prototype, {
(function(def) { (function(def) {
def(AST_Node, return_false); def(AST_Node, return_false);
def(AST_Assign, function(compressor) { def(AST_Assign, function(compressor) {
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); switch (this.operator) {
case "+=":
if (this.left.is_string(compressor)) return true;
case "=":
return this.right.is_string(compressor);
}
}); });
def(AST_Binary, function(compressor) { def(AST_Binary, function(compressor) {
return this.operator == "+" && return this.operator == "+" &&
@@ -7365,10 +7370,9 @@ merge(Compressor.prototype, {
var indexFns = makePredicate("indexOf lastIndexOf"); var indexFns = makePredicate("indexOf lastIndexOf");
var commutativeOperators = makePredicate("== === != !== * & | ^"); var commutativeOperators = makePredicate("== === != !== * & | ^");
function is_object(node) { function is_object(node) {
while ((node = node.tail_node()) instanceof AST_SymbolRef) { if (node instanceof AST_Assign) return node.operator == "=" && is_object(node.right);
node = node.fixed_value(); if (node instanceof AST_Sequence) return is_object(node.tail_node());
if (!node) return false; if (node instanceof AST_SymbolRef) return is_object(node.fixed_value());
}
return node instanceof AST_Array return node instanceof AST_Array
|| node instanceof AST_Lambda || node instanceof AST_Lambda
|| node instanceof AST_New || node instanceof AST_New
@@ -7760,14 +7764,16 @@ merge(Compressor.prototype, {
associative = compressor.option("unsafe_math"); associative = compressor.option("unsafe_math");
// +a - b => a - b // +a - b => a - b
// a - +b => a - b // a - +b => a - b
if (self.operator != "+") { [ "left", "right" ].forEach(function(operand) {
if (self.left instanceof AST_UnaryPrefix && self.left.operator == "+") { var node = self[operand];
self.left = self.left.expression; if (node instanceof AST_UnaryPrefix && node.operator == "+") {
var exp = node.expression;
if (exp.is_boolean(compressor) || exp.is_number(compressor)
|| self.operator != "+" && exp.is_string(compressor)) {
self[operand] = exp;
}
} }
if (self.right instanceof AST_UnaryPrefix && self.right.operator == "+") { });
self.right = self.right.expression;
}
}
case "&": case "&":
case "|": case "|":
case "^": case "^":

View File

@@ -95,7 +95,7 @@ asm_mixed: {
return +sum; return +sum;
} }
function geometricMean(start, end) { 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); var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
return { geometricMean: geometricMean }; return { geometricMean: geometricMean };

View File

@@ -91,7 +91,7 @@ evaluate_1: {
expect: { expect: {
console.log( console.log(
x + 1 + 2, x + 1 + 2,
2 * x, 2 * +x,
+x + 1 + 2, +x + 1 + 2,
1 + x + 2 + 3, 1 + x + 2 + 3,
3 | x, 3 | x,
@@ -130,7 +130,7 @@ evaluate_1_unsafe_math: {
expect: { expect: {
console.log( console.log(
x + 1 + 2, x + 1 + 2,
2 * x, 2 * +x,
+x + 3, +x + 3,
1 + x + 2 + 3, 1 + x + 2 + 3,
3 | x, 3 | x,
@@ -148,45 +148,52 @@ evaluate_1_unsafe_math: {
evaluate_2: { evaluate_2: {
options = { options = {
evaluate: true, evaluate: true,
reduce_vars: true,
unsafe_math: false, unsafe_math: false,
} }
input: { input: {
var x = "42", y = null; function f(num) {
[ var x = "" + num, y = null;
x + 1 + 2, [
x * 1 * 2, x + 1 + 2,
+x + 1 + 2, x * 1 * 2,
1 + x + 2 + 3, +x + 1 + 2,
1 | x | 2 | 3, 1 + x + 2 + 3,
1 + x-- + 2 + 3, 1 | x | 2 | 3,
1 + (x*y + 2) + 3, 1 + x-- + 2 + 3,
1 + (2 + x + 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 & 3), -y + (2 + ~x + 3),
1 + (2 + (x |= 0) + 3), 1 & (2 & x & 3),
].forEach(function(n) { 1 + (2 + (x |= 0) + 3),
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect: { expect: {
var x = "42", y = null; function f(num) {
[ var x = "" + num, y = null;
x + 1 + 2, [
2 * x, x + "12",
+x + 1 + 2, 2 * x,
1 + x + 2 + 3, +x + 1 + 2,
3 | x, 1 + x + "23",
1 + x-- + 2 + 3, 3 | x,
x*y + 2 + 1 + 3, 1 + x-- + 2 + 3,
1 + (2 + x + 3), x*y + 2 + 1 + 3,
2 + ~x + 3 + 1, 2 + x + 3 + 1,
2 + ~x + 3 - y, 2 + ~x + 3 + 1,
0 & x, 2 + ~x + 3,
2 + (x |= 0) + 3 + 1, 0 & x,
].forEach(function(n) { 2 + (x |= 0) + 3 + 1,
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect_stdout: [ expect_stdout: [
"string 4212", "string 4212",
@@ -207,45 +214,52 @@ evaluate_2: {
evaluate_2_unsafe_math: { evaluate_2_unsafe_math: {
options = { options = {
evaluate: true, evaluate: true,
reduce_vars: true,
unsafe_math: true, unsafe_math: true,
} }
input: { input: {
var x = "42", y = null; function f(num) {
[ var x = "" + num, y = null;
x + 1 + 2, [
x * 1 * 2, x + 1 + 2,
+x + 1 + 2, x * 1 * 2,
1 + x + 2 + 3, +x + 1 + 2,
1 | x | 2 | 3, 1 + x + 2 + 3,
1 + x-- + 2 + 3, 1 | x | 2 | 3,
1 + (x*y + 2) + 3, 1 + x-- + 2 + 3,
1 + (2 + x + 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 & 3), -y + (2 + ~x + 3),
1 + (2 + (x |= 0) + 3), 1 & (2 & x & 3),
].forEach(function(n) { 1 + (2 + (x |= 0) + 3),
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect: { expect: {
var x = "42", y = null; function f(num) {
[ var x = "" + num, y = null;
x + 1 + 2, [
2 * x, x + "12",
+x + 3, 2 * x,
1 + x + 2 + 3, +x + 3,
3 | x, 1 + x + "23",
6 + x--, 3 | x,
x*y + 6, 6 + x--,
1 + (2 + x + 3), x*y + 6,
6 + ~x, 6 + x,
5 + ~x - y, 6 + ~x,
0 & x, 5 + ~x,
6 + (x |= 0), 0 & x,
].forEach(function(n) { 6 + (x |= 0),
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect_stdout: [ expect_stdout: [
"string 4212", "string 4212",
@@ -310,45 +324,52 @@ evaluate_4: {
evaluate_5: { evaluate_5: {
options = { options = {
evaluate: true, evaluate: true,
reduce_vars: true,
unsafe_math: false, unsafe_math: false,
} }
input: { input: {
var a = "1"; function f(num) {
[ var a = "" + num;
+a + 2 + 3, [
+a + 2 - 3, +a + 2 + 3,
+a - 2 + 3, +a + 2 - 3,
+a - 2 - 3, +a - 2 + 3,
2 + +a + 3, +a - 2 - 3,
2 + +a - 3, 2 + +a + 3,
2 - +a + 3, 2 + +a - 3,
2 - +a - 3, 2 - +a + 3,
2 + 3 + +a, 2 - +a - 3,
2 + 3 - +a, 2 + 3 + +a,
2 - 3 + +a, 2 + 3 - +a,
2 - 3 - +a, 2 - 3 + +a,
].forEach(function(n) { 2 - 3 - +a,
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(1);
} }
expect: { expect: {
var a = "1"; function f(num) {
[ var a = "" + num;
+a + 2 + 3, [
+a + 2 - 3, +a + 2 + 3,
a - 2 + 3, +a + 2 - 3,
a - 2 - 3, a - 2 + 3,
+a + 2 + 3, a - 2 - 3,
+a + 2 - 3, +a + 2 + 3,
2 - a + 3, +a + 2 - 3,
2 - a - 3, 2 - a + 3,
+a + 5, 2 - a - 3,
5 - a, +a + 5,
+a - 1, 5 - a,
-1 - a, +a - 1,
].forEach(function(n) { -1 - a,
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(1);
} }
expect_stdout: [ expect_stdout: [
"number 6", "number 6",
@@ -369,45 +390,52 @@ evaluate_5: {
evaluate_5_unsafe_math: { evaluate_5_unsafe_math: {
options = { options = {
evaluate: true, evaluate: true,
reduce_vars: true,
unsafe_math: true, unsafe_math: true,
} }
input: { input: {
var a = "1"; function f(num) {
[ var a = "" + num;
+a + 2 + 3, [
+a + 2 - 3, +a + 2 + 3,
+a - 2 + 3, +a + 2 - 3,
+a - 2 - 3, +a - 2 + 3,
2 + +a + 3, +a - 2 - 3,
2 + +a - 3, 2 + +a + 3,
2 - +a + 3, 2 + +a - 3,
2 - +a - 3, 2 - +a + 3,
2 + 3 + +a, 2 - +a - 3,
2 + 3 - +a, 2 + 3 + +a,
2 - 3 + +a, 2 + 3 - +a,
2 - 3 - +a, 2 - 3 + +a,
].forEach(function(n) { 2 - 3 - +a,
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(1);
} }
expect: { expect: {
var a = "1"; function f(num) {
[ var a = "" + num;
+a + 5, [
+a + -1, +a + 5,
a - -1, +a + -1,
a - 5, a - -1,
+a + 5, a - 5,
+a + -1, +a + 5,
5 - a, +a + -1,
-1 - a, 5 - a,
+a + 5, -1 - a,
5 - a, +a + 5,
+a - 1, 5 - a,
-1 - a, +a - 1,
].forEach(function(n) { -1 - a,
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(1);
} }
expect_stdout: [ expect_stdout: [
"number 6", "number 6",
@@ -546,37 +574,44 @@ evaluate_6_unsafe_math: {
evaluate_7: { evaluate_7: {
options = { options = {
evaluate: true, evaluate: true,
reduce_vars: true,
unsafe_math: false, unsafe_math: false,
} }
input: { input: {
var x = "42", y; function f(num, y) {
[ var x = "" + num;
+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), +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),
].forEach(function(n) { +x - 2 - (3 - !y),
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect: { expect: {
var x = "42", y; function f(num, y) {
[ var x = "" + num;
+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), +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),
].forEach(function(n) { x - 2 - (3 - !y),
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect_stdout: [ expect_stdout: [
"number 48", "number 48",
@@ -593,37 +628,44 @@ evaluate_7: {
evaluate_7_unsafe_math: { evaluate_7_unsafe_math: {
options = { options = {
evaluate: true, evaluate: true,
reduce_vars: true,
unsafe_math: true, unsafe_math: true,
} }
input: { input: {
var x = "42", y; function f(num, y) {
[ var x = "" + num;
+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), +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),
].forEach(function(n) { +x - 2 - (3 - !y),
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect: { expect: {
var x = "42", y; function f(num, y) {
[ var x = "" + num;
+x + 5 + !y, [
+x + 5 - !y, +x + 5 + !y,
+x + -1 - !y, +x + 5 - !y,
+x + -1 + !y, +x + -1 - !y,
x - -1 + !y, +x + -1 + !y,
x - -1 - !y, x - -1 + !y,
x - 5 - !y, x - -1 - !y,
x - 5 + !y, x - 5 - !y,
].forEach(function(n) { x - 5 + !y,
console.log(typeof n, n); ].forEach(function(n) {
}); console.log(typeof n, n);
});
}
f(42);
} }
expect_stdout: [ expect_stdout: [
"number 48", "number 48",
@@ -1267,3 +1309,16 @@ issue_3695: {
} }
expect_stdout: "NaN" expect_stdout: "NaN"
} }
issue_4137: {
options = {
evaluate: true,
}
input: {
console.log(+(A = []) * (A[0] = 1));
}
expect: {
console.log(+(A = []) * (A[0] = 1));
}
expect_stdout: "0"
}