enhance evaluate (#3995)
This commit is contained in:
@@ -1485,7 +1485,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
|
||||
function is_last_node(node, parent) {
|
||||
if (node.TYPE == "Binary") return node.operator == "in" && !is_object(node.right.tail_node());
|
||||
if (node.TYPE == "Binary") return node.operator == "in" && !is_object(node.right);
|
||||
if (node instanceof AST_Call) {
|
||||
var def, fn = node.expression;
|
||||
if (fn instanceof AST_SymbolRef) {
|
||||
@@ -3369,10 +3369,10 @@ merge(Compressor.prototype, {
|
||||
var elements = [];
|
||||
for (var i = 0; i < this.elements.length; i++) {
|
||||
var element = this.elements[i];
|
||||
if (element instanceof AST_Hole) continue;
|
||||
if (element instanceof AST_Hole) return this;
|
||||
var value = element._eval(compressor, ignore_side_effects, cached, depth);
|
||||
if (element === value) return this;
|
||||
elements[i] = value;
|
||||
elements.push(value);
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
@@ -3384,16 +3384,11 @@ merge(Compressor.prototype, {
|
||||
for (var i = 0; i < this.properties.length; i++) {
|
||||
var prop = this.properties[i];
|
||||
var key = prop.key;
|
||||
if (key instanceof AST_Symbol) {
|
||||
key = key.name;
|
||||
} else if (key instanceof AST_Node) {
|
||||
key = key._eval(compressor, ignore_side_effects, cached, depth);
|
||||
if (key === prop.key) return this;
|
||||
if (key instanceof AST_Symbol) key = key.name;
|
||||
if (prop.value instanceof AST_Function) {
|
||||
if (typeof Object.prototype[key] == "function") return this;
|
||||
continue;
|
||||
}
|
||||
if (typeof Object.prototype[key] === "function") {
|
||||
return this;
|
||||
}
|
||||
if (prop.value instanceof AST_Function) continue;
|
||||
val[key] = prop.value._eval(compressor, ignore_side_effects, cached, depth);
|
||||
if (val[key] === prop.value) return this;
|
||||
}
|
||||
@@ -3480,10 +3475,10 @@ merge(Compressor.prototype, {
|
||||
case "&" : result = left & right; break;
|
||||
case "^" : result = left ^ right; break;
|
||||
case "+" : result = left + right; break;
|
||||
case "-" : result = left - right; break;
|
||||
case "*" : result = left * right; break;
|
||||
case "/" : result = left / right; break;
|
||||
case "%" : result = left % right; break;
|
||||
case "-" : result = left - right; break;
|
||||
case "<<" : result = left << right; break;
|
||||
case ">>" : result = left >> right; break;
|
||||
case ">>>": result = left >>> right; break;
|
||||
@@ -3495,7 +3490,13 @@ merge(Compressor.prototype, {
|
||||
case "<=" : result = left <= right; break;
|
||||
case ">" : result = left > right; break;
|
||||
case ">=" : result = left >= right; break;
|
||||
default : return this;
|
||||
case "in":
|
||||
if (right && typeof right == "object" && HOP(right, left)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return this;
|
||||
}
|
||||
if (isNaN(result)) return compressor.find_parent(AST_With) ? this : result;
|
||||
if (compressor.option("unsafe_math")
|
||||
@@ -3849,7 +3850,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_Binary, function(compressor) {
|
||||
return this.left.has_side_effects(compressor)
|
||||
|| this.right.has_side_effects(compressor)
|
||||
|| this.operator == "in" && !is_object(this.right.tail_node());
|
||||
|| this.operator == "in" && !is_object(this.right);
|
||||
});
|
||||
def(AST_Block, function(compressor) {
|
||||
return any(this.body, compressor);
|
||||
@@ -3962,7 +3963,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_Binary, function(compressor) {
|
||||
return this.left.may_throw(compressor)
|
||||
|| this.right.may_throw(compressor)
|
||||
|| this.operator == "in" && !is_object(this.right.tail_node());
|
||||
|| this.operator == "in" && !is_object(this.right);
|
||||
});
|
||||
def(AST_Block, function(compressor) {
|
||||
return any(this.body, compressor);
|
||||
@@ -4057,7 +4058,7 @@ merge(Compressor.prototype, {
|
||||
def(AST_Binary, function() {
|
||||
return this.left.is_constant_expression()
|
||||
&& this.right.is_constant_expression()
|
||||
&& (this.operator != "in" || is_object(this.right.tail_node()));
|
||||
&& (this.operator != "in" || is_object(this.right));
|
||||
});
|
||||
def(AST_Constant, return_true);
|
||||
def(AST_Lambda, function(scope) {
|
||||
@@ -5163,7 +5164,7 @@ merge(Compressor.prototype, {
|
||||
return this;
|
||||
});
|
||||
def(AST_Binary, function(compressor, first_in_statement) {
|
||||
if (this.operator == "in" && !is_object(this.right.tail_node())) {
|
||||
if (this.operator == "in" && !is_object(this.right)) {
|
||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (left === this.left) return this;
|
||||
var node = this.clone();
|
||||
@@ -6921,10 +6922,9 @@ merge(Compressor.prototype, {
|
||||
var indexFns = makePredicate("indexOf lastIndexOf");
|
||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||
function is_object(node) {
|
||||
while (node instanceof AST_SymbolRef) {
|
||||
while ((node = node.tail_node()) instanceof AST_SymbolRef) {
|
||||
node = node.fixed_value();
|
||||
if (!node) return false;
|
||||
node = node.tail_node();
|
||||
}
|
||||
return node instanceof AST_Array
|
||||
|| node instanceof AST_Lambda
|
||||
|
||||
@@ -560,6 +560,8 @@ unsafe_array: {
|
||||
input: {
|
||||
var a = "PASS";
|
||||
Array.prototype[1] = a;
|
||||
console.log([, ].length);
|
||||
console.log("" + [, , ]);
|
||||
console.log([1, , 3][1]);
|
||||
console.log([1, 2, 3, a] + 1);
|
||||
console.log([1, 2, 3, 4] + 1);
|
||||
@@ -574,6 +576,8 @@ unsafe_array: {
|
||||
expect: {
|
||||
var a = "PASS";
|
||||
Array.prototype[1] = a;
|
||||
console.log([, ].length);
|
||||
console.log("" + [, , ]);
|
||||
console.log([1, , 3][1]);
|
||||
console.log([1, 2, 3, a] + 1);
|
||||
console.log("1,2,3,41");
|
||||
@@ -586,6 +590,8 @@ unsafe_array: {
|
||||
console.log([[1, 2], , [3, 4]][1][1] + 1);
|
||||
}
|
||||
expect_stdout: [
|
||||
"1",
|
||||
",PASS",
|
||||
"PASS",
|
||||
"1,2,3,PASS1",
|
||||
"1,2,3,41",
|
||||
@@ -2770,3 +2776,39 @@ issue_3988: {
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
operator_in: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
unsafe: true,
|
||||
}
|
||||
input: {
|
||||
Object.prototype.PASS = 0;
|
||||
console.log(0 in [ 1 ]);
|
||||
console.log(0 in [ , ]);
|
||||
console.log(0 / 0 in { NaN: 2 });
|
||||
console.log("PASS" in { });
|
||||
console.log("FAIL" in { });
|
||||
console.log("toString" in { });
|
||||
console.log("toString" in { toString: 3 });
|
||||
}
|
||||
expect: {
|
||||
Object.prototype.PASS = 0;
|
||||
console.log(true);
|
||||
console.log(0 in [ , ]);
|
||||
console.log(true);
|
||||
console.log("PASS" in { });
|
||||
console.log("FAIL" in { });
|
||||
console.log("toString" in { });
|
||||
console.log(true);
|
||||
}
|
||||
expect_stdout: [
|
||||
"true",
|
||||
"false",
|
||||
"true",
|
||||
"true",
|
||||
"false",
|
||||
"true",
|
||||
"true",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -767,6 +767,10 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) {
|
||||
return createArrayLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey();
|
||||
case p++:
|
||||
return createObjectLiteral(recurmax, stmtDepth, canThrow) + "." + getDotKey();
|
||||
case p++:
|
||||
return createValue() + " in " + createArrayLiteral(recurmax, stmtDepth, canThrow);
|
||||
case p++:
|
||||
return createValue() + " in " + createObjectLiteral(recurmax, stmtDepth, canThrow);
|
||||
case p++:
|
||||
var name = getVarName();
|
||||
var s = name + "[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]";
|
||||
|
||||
Reference in New Issue
Block a user