enhance typeofs (#3556)
This commit is contained in:
@@ -1042,7 +1042,8 @@ merge(Compressor.prototype, {
|
||||
|
||||
var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Math Number parseFloat parseInt RangeError ReferenceError RegExp Object setInterval setTimeout String SyntaxError TypeError unescape URIError");
|
||||
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
|
||||
return !this.definition().undeclared
|
||||
return this.defined
|
||||
|| !this.definition().undeclared
|
||||
|| compressor.option("unsafe") && global_names[this.name];
|
||||
});
|
||||
|
||||
@@ -4570,6 +4571,49 @@ merge(Compressor.prototype, {
|
||||
return if_break_in_loop(self, compressor);
|
||||
});
|
||||
|
||||
function mark_locally_defined(condition, consequent, alternative, operator) {
|
||||
if (!(condition instanceof AST_Binary)) return;
|
||||
if (!(condition.left instanceof AST_String)) {
|
||||
if (!operator) operator = condition.operator;
|
||||
if (condition.operator != operator) return;
|
||||
switch (operator) {
|
||||
case "&&":
|
||||
case "||":
|
||||
mark_locally_defined(condition.left, consequent, alternative, operator);
|
||||
mark_locally_defined(condition.right, consequent, alternative, operator);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!(condition.right instanceof AST_UnaryPrefix)) return;
|
||||
if (condition.right.operator != "typeof") return;
|
||||
var sym = condition.right.expression;
|
||||
if (!is_undeclared_ref(sym)) return;
|
||||
var body;
|
||||
var undef = condition.left.getValue() == "undefined";
|
||||
switch (condition.operator) {
|
||||
case "==":
|
||||
body = undef ? alternative : consequent;
|
||||
break;
|
||||
case "!=":
|
||||
body = undef ? consequent : alternative;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
if (!body) return;
|
||||
var def = sym.definition();
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Scope) {
|
||||
var parent = tw.parent();
|
||||
if (parent instanceof AST_Call && parent.expression === node) return;
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_SymbolRef && node.definition() === def) node.defined = true;
|
||||
});
|
||||
body.walk(tw);
|
||||
}
|
||||
|
||||
OPT(AST_If, function(self, compressor) {
|
||||
if (is_empty(self.alternative)) self.alternative = null;
|
||||
|
||||
@@ -4711,6 +4755,7 @@ merge(Compressor.prototype, {
|
||||
body: [ self, body ]
|
||||
}).optimize(compressor);
|
||||
}
|
||||
if (compressor.option("typeofs")) mark_locally_defined(self.condition, self.body, self.alternative);
|
||||
return self;
|
||||
});
|
||||
|
||||
@@ -5698,7 +5743,7 @@ merge(Compressor.prototype, {
|
||||
// "undefined" == typeof x => undefined === x
|
||||
else if (compressor.option("typeofs")
|
||||
&& self.left instanceof AST_String
|
||||
&& self.left.value == "undefined"
|
||||
&& self.left.getValue() == "undefined"
|
||||
&& self.right instanceof AST_UnaryPrefix
|
||||
&& self.right.operator == "typeof") {
|
||||
var expr = self.right.expression;
|
||||
@@ -6089,6 +6134,14 @@ merge(Compressor.prototype, {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (compressor.option("typeofs")) switch (self.operator) {
|
||||
case "&&":
|
||||
mark_locally_defined(self.left, self.right, null, "&&");
|
||||
break;
|
||||
case "||":
|
||||
mark_locally_defined(self.left, null, self.right, "||");
|
||||
break;
|
||||
}
|
||||
if (compressor.option("unsafe")) {
|
||||
var indexRight = is_indexFn(self.right);
|
||||
if (in_bool
|
||||
@@ -6651,8 +6704,8 @@ merge(Compressor.prototype, {
|
||||
}).optimize(compressor);
|
||||
}
|
||||
var in_bool = compressor.option("booleans") && compressor.in_boolean_context();
|
||||
if (is_true(self.consequent)) {
|
||||
if (is_false(self.alternative)) {
|
||||
if (is_true(consequent)) {
|
||||
if (is_false(alternative)) {
|
||||
// c ? true : false ---> !!c
|
||||
return booleanize(condition);
|
||||
}
|
||||
@@ -6660,11 +6713,11 @@ merge(Compressor.prototype, {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: booleanize(condition),
|
||||
right: self.alternative
|
||||
right: alternative
|
||||
});
|
||||
}
|
||||
if (is_false(self.consequent)) {
|
||||
if (is_true(self.alternative)) {
|
||||
if (is_false(consequent)) {
|
||||
if (is_true(alternative)) {
|
||||
// c ? false : true ---> !c
|
||||
return booleanize(condition.negate(compressor));
|
||||
}
|
||||
@@ -6672,26 +6725,26 @@ merge(Compressor.prototype, {
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: booleanize(condition.negate(compressor)),
|
||||
right: self.alternative
|
||||
right: alternative
|
||||
});
|
||||
}
|
||||
if (is_true(self.alternative)) {
|
||||
if (is_true(alternative)) {
|
||||
// c ? x : true ---> !c || x
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "||",
|
||||
left: booleanize(condition.negate(compressor)),
|
||||
right: self.consequent
|
||||
right: consequent
|
||||
});
|
||||
}
|
||||
if (is_false(self.alternative)) {
|
||||
if (is_false(alternative)) {
|
||||
// c ? x : false ---> !!c && x
|
||||
return make_node(AST_Binary, self, {
|
||||
operator: "&&",
|
||||
left: booleanize(condition),
|
||||
right: self.consequent
|
||||
right: consequent
|
||||
});
|
||||
}
|
||||
|
||||
if (compressor.option("typeofs")) mark_locally_defined(condition, consequent, alternative);
|
||||
return self;
|
||||
|
||||
function booleanize(node) {
|
||||
|
||||
@@ -295,3 +295,117 @@ issue_2728_6: {
|
||||
}
|
||||
expect_stdout: "function undefined"
|
||||
}
|
||||
|
||||
typeof_defined_1: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
"undefined" == typeof A && A;
|
||||
"undefined" != typeof A && A;
|
||||
"undefined" == typeof A || A;
|
||||
"undefined" != typeof A || A;
|
||||
}
|
||||
expect: {
|
||||
"undefined" == typeof A && A;
|
||||
"undefined" != typeof A || A;
|
||||
}
|
||||
}
|
||||
|
||||
typeof_defined_2: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
"function" == typeof A && A;
|
||||
"function" != typeof A && A;
|
||||
"function" == typeof A || A;
|
||||
"function" != typeof A || A;
|
||||
}
|
||||
expect: {
|
||||
"function" != typeof A && A;
|
||||
"function" == typeof A || A;
|
||||
}
|
||||
}
|
||||
|
||||
typeof_defined_3: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
"undefined" == typeof A && "undefined" == typeof B && (A, B);
|
||||
"undefined" == typeof A && "undefined" != typeof B && (A, B);
|
||||
"undefined" != typeof A && "undefined" == typeof B && (A, B);
|
||||
"undefined" != typeof A && "undefined" != typeof B && (A, B);
|
||||
"undefined" == typeof A && "undefined" == typeof B || (A, B);
|
||||
"undefined" == typeof A && "undefined" != typeof B || (A, B);
|
||||
"undefined" != typeof A && "undefined" == typeof B || (A, B);
|
||||
"undefined" != typeof A && "undefined" != typeof B || (A, B);
|
||||
"undefined" == typeof A || "undefined" == typeof B && (A, B);
|
||||
"undefined" == typeof A || "undefined" != typeof B && (A, B);
|
||||
"undefined" != typeof A || "undefined" == typeof B && (A, B);
|
||||
"undefined" != typeof A || "undefined" != typeof B && (A, B);
|
||||
"undefined" == typeof A || "undefined" == typeof B || (A, B);
|
||||
"undefined" == typeof A || "undefined" != typeof B || (A, B);
|
||||
"undefined" != typeof A || "undefined" == typeof B || (A, B);
|
||||
"undefined" != typeof A || "undefined" != typeof B || (A, B);
|
||||
}
|
||||
expect: {
|
||||
"undefined" == typeof A && "undefined" == typeof B && (A, B);
|
||||
"undefined" == typeof A && "undefined" != typeof B && A;
|
||||
"undefined" != typeof A && "undefined" == typeof B && B;
|
||||
"undefined" == typeof A && "undefined" == typeof B || (A, B);
|
||||
"undefined" == typeof A && "undefined" != typeof B || (A, B);
|
||||
"undefined" != typeof A && "undefined" == typeof B || (A, B);
|
||||
"undefined" != typeof A && "undefined" != typeof B || (A, B);
|
||||
"undefined" == typeof A || "undefined" == typeof B && B;
|
||||
"undefined" != typeof A || "undefined" == typeof B && (A, B);
|
||||
"undefined" != typeof A || "undefined" != typeof B && A;
|
||||
"undefined" == typeof A || "undefined" != typeof B || B;
|
||||
"undefined" != typeof A || "undefined" == typeof B || A;
|
||||
"undefined" != typeof A || "undefined" != typeof B || (A, B);
|
||||
}
|
||||
}
|
||||
|
||||
typeof_defined_4: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
typeofs: true,
|
||||
}
|
||||
input: {
|
||||
"object" == typeof A && "object" == typeof B && (A, B);
|
||||
"object" == typeof A && "object" != typeof B && (A, B);
|
||||
"object" != typeof A && "object" == typeof B && (A, B);
|
||||
"object" != typeof A && "object" != typeof B && (A, B);
|
||||
"object" == typeof A && "object" == typeof B || (A, B);
|
||||
"object" == typeof A && "object" != typeof B || (A, B);
|
||||
"object" != typeof A && "object" == typeof B || (A, B);
|
||||
"object" != typeof A && "object" != typeof B || (A, B);
|
||||
"object" == typeof A || "object" == typeof B && (A, B);
|
||||
"object" == typeof A || "object" != typeof B && (A, B);
|
||||
"object" != typeof A || "object" == typeof B && (A, B);
|
||||
"object" != typeof A || "object" != typeof B && (A, B);
|
||||
"object" == typeof A || "object" == typeof B || (A, B);
|
||||
"object" == typeof A || "object" != typeof B || (A, B);
|
||||
"object" != typeof A || "object" == typeof B || (A, B);
|
||||
"object" != typeof A || "object" != typeof B || (A, B);
|
||||
}
|
||||
expect: {
|
||||
"object" == typeof A && "object" != typeof B && B;
|
||||
"object" != typeof A && "object" == typeof B && A;
|
||||
"object" != typeof A && "object" != typeof B && (A, B);
|
||||
"object" == typeof A && "object" == typeof B || (A, B);
|
||||
"object" == typeof A && "object" != typeof B || (A, B);
|
||||
"object" != typeof A && "object" == typeof B || (A, B);
|
||||
"object" != typeof A && "object" != typeof B || (A, B);
|
||||
"object" == typeof A || "object" == typeof B && A;
|
||||
"object" == typeof A || "object" != typeof B && (A, B);
|
||||
"object" != typeof A || "object" != typeof B && B;
|
||||
"object" == typeof A || "object" == typeof B || (A, B);
|
||||
"object" == typeof A || "object" != typeof B || A;
|
||||
"object" != typeof A || "object" == typeof B || B;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user