optimise binary operands with evaluate() (#1427)
- remove call to evaluate() in is_constant() and let nested optimize() does its job instead - reject RegExp in is_constant() and remove special case logic under collapse_vars - operands to conditionals optimisation are now always evaluate()-ed - throw error in constant_value() instead of returning undefined to catch possible bugs, similar to make_node_from_constant() - optimise binary boolean operators under `evaluate` instead of `conditionals`
This commit is contained in:
committed by
Richard van Velzen
parent
0d7d4918eb
commit
0610c020b1
119
lib/compress.js
119
lib/compress.js
@@ -347,7 +347,7 @@ merge(Compressor.prototype, {
|
|||||||
if (ref.scope.uses_eval || ref.scope.uses_with) break;
|
if (ref.scope.uses_eval || ref.scope.uses_with) break;
|
||||||
|
|
||||||
// Constant single use vars can be replaced in any scope.
|
// Constant single use vars can be replaced in any scope.
|
||||||
if (!(var_decl.value instanceof AST_RegExp) && var_decl.value.is_constant(compressor)) {
|
if (var_decl.value.is_constant()) {
|
||||||
var ctt = new TreeTransformer(function(node) {
|
var ctt = new TreeTransformer(function(node) {
|
||||||
if (node === ref)
|
if (node === ref)
|
||||||
return replace_var(node, ctt.parent(), true);
|
return replace_var(node, ctt.parent(), true);
|
||||||
@@ -1013,31 +1013,46 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return [ best_of(node, this), val ];
|
return [ best_of(node, this), val ];
|
||||||
});
|
});
|
||||||
AST_Node.DEFMETHOD("is_constant", function(compressor){
|
var unaryPrefix = makePredicate("! ~ - +");
|
||||||
|
AST_Node.DEFMETHOD("is_constant", function(){
|
||||||
// Accomodate when compress option evaluate=false
|
// Accomodate when compress option evaluate=false
|
||||||
// as well as the common constant expressions !0 and !1
|
// as well as the common constant expressions !0 and -1
|
||||||
return this instanceof AST_Constant
|
if (this instanceof AST_Constant) {
|
||||||
|| (this instanceof AST_UnaryPrefix && this.operator == "!"
|
return !(this instanceof AST_RegExp);
|
||||||
&& this.expression instanceof AST_Constant)
|
} else {
|
||||||
|| this.evaluate(compressor).length > 1;
|
return this instanceof AST_UnaryPrefix
|
||||||
|
&& this.expression instanceof AST_Constant
|
||||||
|
&& unaryPrefix(this.operator);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// Obtain the constant value of an expression already known to be constant.
|
// Obtain the constant value of an expression already known to be constant.
|
||||||
// Result only valid iff this.is_constant(compressor) is true.
|
// Result only valid iff this.is_constant() is true.
|
||||||
AST_Node.DEFMETHOD("constant_value", function(compressor){
|
AST_Node.DEFMETHOD("constant_value", function(compressor){
|
||||||
// Accomodate when option evaluate=false.
|
// Accomodate when option evaluate=false.
|
||||||
if (this instanceof AST_Constant) return this.value;
|
if (this instanceof AST_Constant && !(this instanceof AST_RegExp)) {
|
||||||
// Accomodate the common constant expressions !0 and !1 when option evaluate=false.
|
return this.value;
|
||||||
if (this instanceof AST_UnaryPrefix
|
|
||||||
&& this.operator == "!"
|
|
||||||
&& this.expression instanceof AST_Constant) {
|
|
||||||
return !this.expression.value;
|
|
||||||
}
|
}
|
||||||
var result = this.evaluate(compressor)
|
// Accomodate the common constant expressions !0 and -1 when option evaluate=false.
|
||||||
|
if (this instanceof AST_UnaryPrefix
|
||||||
|
&& this.expression instanceof AST_Constant) switch (this.operator) {
|
||||||
|
case "!":
|
||||||
|
return !this.expression.value;
|
||||||
|
case "~":
|
||||||
|
return ~this.expression.value;
|
||||||
|
case "-":
|
||||||
|
return -this.expression.value;
|
||||||
|
case "+":
|
||||||
|
return +this.expression.value;
|
||||||
|
default:
|
||||||
|
throw new Error(string_template("Cannot evaluate unary expression {value}", {
|
||||||
|
value: this.print_to_string()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
var result = this.evaluate(compressor);
|
||||||
if (result.length > 1) {
|
if (result.length > 1) {
|
||||||
return result[1];
|
return result[1];
|
||||||
}
|
}
|
||||||
// should never be reached
|
throw new Error(string_template("Cannot evaluate constant [{file}:{line},{col}]", this.start));
|
||||||
return undefined;
|
|
||||||
});
|
});
|
||||||
def(AST_Statement, function(){
|
def(AST_Statement, function(){
|
||||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||||
@@ -2419,6 +2434,16 @@ merge(Compressor.prototype, {
|
|||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor){
|
OPT(AST_Binary, function(self, compressor){
|
||||||
|
var lhs = self.left.evaluate(compressor);
|
||||||
|
var rhs = self.right.evaluate(compressor);
|
||||||
|
if (lhs.length > 1 && lhs[0].is_constant() !== self.left.is_constant()
|
||||||
|
|| rhs.length > 1 && rhs[0].is_constant() !== self.right.is_constant()) {
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: self.operator,
|
||||||
|
left: lhs[0],
|
||||||
|
right: rhs[0]
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
function reverse(op, force) {
|
function reverse(op, force) {
|
||||||
if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
|
if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
|
||||||
if (op) self.operator = op;
|
if (op) self.operator = op;
|
||||||
@@ -2491,32 +2516,6 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("conditionals")) {
|
|
||||||
if (self.operator == "&&") {
|
|
||||||
var ll = self.left.evaluate(compressor);
|
|
||||||
if (ll.length > 1) {
|
|
||||||
if (ll[1]) {
|
|
||||||
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
|
||||||
return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
|
||||||
} else {
|
|
||||||
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
|
||||||
return maintain_this_binding(compressor.parent(), self, ll[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (self.operator == "||") {
|
|
||||||
var ll = self.left.evaluate(compressor);
|
|
||||||
if (ll.length > 1) {
|
|
||||||
if (ll[1]) {
|
|
||||||
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
|
||||||
return maintain_this_binding(compressor.parent(), self, ll[0]);
|
|
||||||
} else {
|
|
||||||
compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
|
|
||||||
return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
|
||||||
case "&&":
|
case "&&":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
@@ -2590,6 +2589,30 @@ merge(Compressor.prototype, {
|
|||||||
return self.left;
|
return self.left;
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate")) {
|
if (compressor.option("evaluate")) {
|
||||||
|
switch (self.operator) {
|
||||||
|
case "&&":
|
||||||
|
if (self.left.is_constant()) {
|
||||||
|
if (self.left.constant_value(compressor)) {
|
||||||
|
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
||||||
|
return maintain_this_binding(compressor.parent(), self, self.right);
|
||||||
|
} else {
|
||||||
|
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
||||||
|
return maintain_this_binding(compressor.parent(), self, self.left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "||":
|
||||||
|
if (self.left.is_constant()) {
|
||||||
|
if (self.left.constant_value(compressor)) {
|
||||||
|
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
||||||
|
return maintain_this_binding(compressor.parent(), self, self.left);
|
||||||
|
} else {
|
||||||
|
compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
|
||||||
|
return maintain_this_binding(compressor.parent(), self, self.right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (self.operator == "+") {
|
if (self.operator == "+") {
|
||||||
if (self.left instanceof AST_Constant
|
if (self.left instanceof AST_Constant
|
||||||
&& self.right instanceof AST_Binary
|
&& self.right instanceof AST_Binary
|
||||||
@@ -2816,14 +2839,14 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// y?1:1 --> 1
|
// y?1:1 --> 1
|
||||||
if (consequent.is_constant(compressor)
|
if (consequent.is_constant()
|
||||||
&& alternative.is_constant(compressor)
|
&& alternative.is_constant()
|
||||||
&& consequent.equivalent_to(alternative)) {
|
&& consequent.equivalent_to(alternative)) {
|
||||||
var consequent_value = consequent.constant_value(compressor);
|
var consequent_value = consequent.evaluate(compressor)[0];
|
||||||
if (self.condition.has_side_effects(compressor)) {
|
if (self.condition.has_side_effects(compressor)) {
|
||||||
return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent_value, self)]);
|
return AST_Seq.from_array([self.condition, consequent_value]);
|
||||||
} else {
|
} else {
|
||||||
return make_node_from_constant(compressor, consequent_value, self);
|
return consequent_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -635,166 +635,6 @@ ternary_boolean_alternative: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conditional_and: {
|
|
||||||
options = {
|
|
||||||
conditionals: true,
|
|
||||||
evaluate : true
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
var a;
|
|
||||||
// compress these
|
|
||||||
|
|
||||||
a = true && condition;
|
|
||||||
a = 1 && console.log("a");
|
|
||||||
a = 2 * 3 && 2 * condition;
|
|
||||||
a = 5 == 5 && condition + 3;
|
|
||||||
a = "string" && 4 - condition;
|
|
||||||
a = 5 + "" && condition / 5;
|
|
||||||
a = -4.5 && 6 << condition;
|
|
||||||
a = 6 && 7;
|
|
||||||
|
|
||||||
a = false && condition;
|
|
||||||
a = NaN && console.log("b");
|
|
||||||
a = 0 && console.log("c");
|
|
||||||
a = undefined && 2 * condition;
|
|
||||||
a = null && condition + 3;
|
|
||||||
a = 2 * 3 - 6 && 4 - condition;
|
|
||||||
a = 10 == 7 && condition / 5;
|
|
||||||
a = !"string" && 6 % condition;
|
|
||||||
a = 0 && 7;
|
|
||||||
|
|
||||||
// don't compress these
|
|
||||||
|
|
||||||
a = condition && true;
|
|
||||||
a = console.log("a") && 2;
|
|
||||||
a = 4 - condition && "string";
|
|
||||||
a = 6 << condition && -4.5;
|
|
||||||
|
|
||||||
a = condition && false;
|
|
||||||
a = console.log("b") && NaN;
|
|
||||||
a = console.log("c") && 0;
|
|
||||||
a = 2 * condition && undefined;
|
|
||||||
a = condition + 3 && null;
|
|
||||||
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a;
|
|
||||||
|
|
||||||
a = condition;
|
|
||||||
a = console.log("a");
|
|
||||||
a = 2 * condition;
|
|
||||||
a = condition + 3;
|
|
||||||
a = 4 - condition;
|
|
||||||
a = condition / 5;
|
|
||||||
a = 6 << condition;
|
|
||||||
a = 7;
|
|
||||||
|
|
||||||
a = false;
|
|
||||||
a = NaN;
|
|
||||||
a = 0;
|
|
||||||
a = void 0;
|
|
||||||
a = null;
|
|
||||||
a = 0;
|
|
||||||
a = false;
|
|
||||||
a = false;
|
|
||||||
a = 0;
|
|
||||||
|
|
||||||
a = condition && true;
|
|
||||||
a = console.log("a") && 2;
|
|
||||||
a = 4 - condition && "string";
|
|
||||||
a = 6 << condition && -4.5;
|
|
||||||
|
|
||||||
a = condition && false;
|
|
||||||
a = console.log("b") && NaN;
|
|
||||||
a = console.log("c") && 0;
|
|
||||||
a = 2 * condition && void 0;
|
|
||||||
a = condition + 3 && null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
conditional_or: {
|
|
||||||
options = {
|
|
||||||
conditionals: true,
|
|
||||||
evaluate : true
|
|
||||||
};
|
|
||||||
input: {
|
|
||||||
var a;
|
|
||||||
// compress these
|
|
||||||
|
|
||||||
a = true || condition;
|
|
||||||
a = 1 || console.log("a");
|
|
||||||
a = 2 * 3 || 2 * condition;
|
|
||||||
a = 5 == 5 || condition + 3;
|
|
||||||
a = "string" || 4 - condition;
|
|
||||||
a = 5 + "" || condition / 5;
|
|
||||||
a = -4.5 || 6 << condition;
|
|
||||||
a = 6 || 7;
|
|
||||||
|
|
||||||
a = false || condition;
|
|
||||||
a = 0 || console.log("b");
|
|
||||||
a = NaN || console.log("c");
|
|
||||||
a = undefined || 2 * condition;
|
|
||||||
a = null || condition + 3;
|
|
||||||
a = 2 * 3 - 6 || 4 - condition;
|
|
||||||
a = 10 == 7 || condition / 5;
|
|
||||||
a = !"string" || 6 % condition;
|
|
||||||
a = null || 7;
|
|
||||||
|
|
||||||
a = console.log(undefined && condition || null);
|
|
||||||
a = console.log(undefined || condition && null);
|
|
||||||
|
|
||||||
// don't compress these
|
|
||||||
|
|
||||||
a = condition || true;
|
|
||||||
a = console.log("a") || 2;
|
|
||||||
a = 4 - condition || "string";
|
|
||||||
a = 6 << condition || -4.5;
|
|
||||||
|
|
||||||
a = condition || false;
|
|
||||||
a = console.log("b") || NaN;
|
|
||||||
a = console.log("c") || 0;
|
|
||||||
a = 2 * condition || undefined;
|
|
||||||
a = condition + 3 || null;
|
|
||||||
|
|
||||||
}
|
|
||||||
expect: {
|
|
||||||
var a;
|
|
||||||
|
|
||||||
a = true;
|
|
||||||
a = 1;
|
|
||||||
a = 6;
|
|
||||||
a = true;
|
|
||||||
a = "string";
|
|
||||||
a = "5";
|
|
||||||
a = -4.5;
|
|
||||||
a = 6;
|
|
||||||
|
|
||||||
a = condition;
|
|
||||||
a = console.log("b");
|
|
||||||
a = console.log("c");
|
|
||||||
a = 2 * condition;
|
|
||||||
a = condition + 3;
|
|
||||||
a = 4 - condition;
|
|
||||||
a = condition / 5;
|
|
||||||
a = 6 % condition;
|
|
||||||
a = 7;
|
|
||||||
|
|
||||||
a = console.log(null);
|
|
||||||
a = console.log(condition && null);
|
|
||||||
|
|
||||||
a = condition || true;
|
|
||||||
a = console.log("a") || 2;
|
|
||||||
a = 4 - condition || "string";
|
|
||||||
a = 6 << condition || -4.5;
|
|
||||||
|
|
||||||
a = condition || false;
|
|
||||||
a = console.log("b") || NaN;
|
|
||||||
a = console.log("c") || 0;
|
|
||||||
a = 2 * condition || void 0;
|
|
||||||
a = condition + 3 || null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trivial_boolean_ternary_expressions : {
|
trivial_boolean_ternary_expressions : {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -906,3 +746,26 @@ issue_1154: {
|
|||||||
function g6() { return g(), "number"; }
|
function g6() { return g(), "number"; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
no_evaluate: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : false
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(b) {
|
||||||
|
a = b ? !0 : !0;
|
||||||
|
a = b ? ~1 : ~1;
|
||||||
|
a = b ? -2 : -2;
|
||||||
|
a = b ? +3 : +3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(b) {
|
||||||
|
a = !0;
|
||||||
|
a = ~1;
|
||||||
|
a = -2;
|
||||||
|
a = +3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,187 @@
|
|||||||
|
and: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
|
||||||
|
a = true && condition;
|
||||||
|
a = 1 && console.log("a");
|
||||||
|
a = 2 * 3 && 2 * condition;
|
||||||
|
a = 5 == 5 && condition + 3;
|
||||||
|
a = "string" && 4 - condition;
|
||||||
|
a = 5 + "" && condition / 5;
|
||||||
|
a = -4.5 && 6 << condition;
|
||||||
|
a = 6 && 7;
|
||||||
|
|
||||||
|
a = false && condition;
|
||||||
|
a = NaN && console.log("b");
|
||||||
|
a = 0 && console.log("c");
|
||||||
|
a = undefined && 2 * condition;
|
||||||
|
a = null && condition + 3;
|
||||||
|
a = 2 * 3 - 6 && 4 - condition;
|
||||||
|
a = 10 == 7 && condition / 5;
|
||||||
|
a = !"string" && 6 % condition;
|
||||||
|
a = 0 && 7;
|
||||||
|
|
||||||
|
// don't compress these
|
||||||
|
|
||||||
|
a = condition && true;
|
||||||
|
a = console.log("a") && 2;
|
||||||
|
a = 4 - condition && "string";
|
||||||
|
a = 6 << condition && -4.5;
|
||||||
|
|
||||||
|
a = condition && false;
|
||||||
|
a = console.log("b") && NaN;
|
||||||
|
a = console.log("c") && 0;
|
||||||
|
a = 2 * condition && undefined;
|
||||||
|
a = condition + 3 && null;
|
||||||
|
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
|
||||||
|
a = condition;
|
||||||
|
a = console.log("a");
|
||||||
|
a = 2 * condition;
|
||||||
|
a = condition + 3;
|
||||||
|
a = 4 - condition;
|
||||||
|
a = condition / 5;
|
||||||
|
a = 6 << condition;
|
||||||
|
a = 7;
|
||||||
|
|
||||||
|
a = false;
|
||||||
|
a = NaN;
|
||||||
|
a = 0;
|
||||||
|
a = void 0;
|
||||||
|
a = null;
|
||||||
|
a = 0;
|
||||||
|
a = false;
|
||||||
|
a = false;
|
||||||
|
a = 0;
|
||||||
|
|
||||||
|
a = condition && true;
|
||||||
|
a = console.log("a") && 2;
|
||||||
|
a = 4 - condition && "string";
|
||||||
|
a = 6 << condition && -4.5;
|
||||||
|
|
||||||
|
a = condition && false;
|
||||||
|
a = console.log("b") && NaN;
|
||||||
|
a = console.log("c") && 0;
|
||||||
|
a = 2 * condition && void 0;
|
||||||
|
a = condition + 3 && null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
or: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
|
||||||
|
a = true || condition;
|
||||||
|
a = 1 || console.log("a");
|
||||||
|
a = 2 * 3 || 2 * condition;
|
||||||
|
a = 5 == 5 || condition + 3;
|
||||||
|
a = "string" || 4 - condition;
|
||||||
|
a = 5 + "" || condition / 5;
|
||||||
|
a = -4.5 || 6 << condition;
|
||||||
|
a = 6 || 7;
|
||||||
|
|
||||||
|
a = false || condition;
|
||||||
|
a = 0 || console.log("b");
|
||||||
|
a = NaN || console.log("c");
|
||||||
|
a = undefined || 2 * condition;
|
||||||
|
a = null || condition + 3;
|
||||||
|
a = 2 * 3 - 6 || 4 - condition;
|
||||||
|
a = 10 == 7 || condition / 5;
|
||||||
|
a = !"string" || 6 % condition;
|
||||||
|
a = null || 7;
|
||||||
|
|
||||||
|
a = console.log(undefined && condition || null);
|
||||||
|
a = console.log(undefined || condition && null);
|
||||||
|
|
||||||
|
// don't compress these
|
||||||
|
|
||||||
|
a = condition || true;
|
||||||
|
a = console.log("a") || 2;
|
||||||
|
a = 4 - condition || "string";
|
||||||
|
a = 6 << condition || -4.5;
|
||||||
|
|
||||||
|
a = condition || false;
|
||||||
|
a = console.log("b") || NaN;
|
||||||
|
a = console.log("c") || 0;
|
||||||
|
a = 2 * condition || undefined;
|
||||||
|
a = condition + 3 || null;
|
||||||
|
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
|
||||||
|
a = true;
|
||||||
|
a = 1;
|
||||||
|
a = 6;
|
||||||
|
a = true;
|
||||||
|
a = "string";
|
||||||
|
a = "5";
|
||||||
|
a = -4.5;
|
||||||
|
a = 6;
|
||||||
|
|
||||||
|
a = condition;
|
||||||
|
a = console.log("b");
|
||||||
|
a = console.log("c");
|
||||||
|
a = 2 * condition;
|
||||||
|
a = condition + 3;
|
||||||
|
a = 4 - condition;
|
||||||
|
a = condition / 5;
|
||||||
|
a = 6 % condition;
|
||||||
|
a = 7;
|
||||||
|
|
||||||
|
a = console.log(null);
|
||||||
|
a = console.log(condition && null);
|
||||||
|
|
||||||
|
a = condition || true;
|
||||||
|
a = console.log("a") || 2;
|
||||||
|
a = 4 - condition || "string";
|
||||||
|
a = 6 << condition || -4.5;
|
||||||
|
|
||||||
|
a = condition || false;
|
||||||
|
a = console.log("b") || NaN;
|
||||||
|
a = console.log("c") || 0;
|
||||||
|
a = 2 * condition || void 0;
|
||||||
|
a = condition + 3 || null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unary_prefix: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a = !0 && b;
|
||||||
|
a = !0 || b;
|
||||||
|
a = ~1 && b;
|
||||||
|
a = ~1 || b;
|
||||||
|
a = -2 && b;
|
||||||
|
a = -2 || b;
|
||||||
|
a = +3 && b;
|
||||||
|
a = +3 || b;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = b;
|
||||||
|
a = !0;
|
||||||
|
a = b;
|
||||||
|
a = -2;
|
||||||
|
a = b;
|
||||||
|
a = -2;
|
||||||
|
a = b;
|
||||||
|
a = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
negative_zero: {
|
negative_zero: {
|
||||||
options = { evaluate: true }
|
options = { evaluate: true }
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
@@ -136,30 +136,30 @@ modified: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function f2() {
|
function f2() {
|
||||||
var a = 1, b = 2, c = 3;
|
var b = 2, c = 3;
|
||||||
b = c;
|
b = c;
|
||||||
console.log(a + b);
|
console.log(1 + b);
|
||||||
console.log(b + c);
|
console.log(b + 3);
|
||||||
console.log(4);
|
console.log(4);
|
||||||
console.log(a + b + c);
|
console.log(1 + b + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
function f3() {
|
function f3() {
|
||||||
var a = 1, b = 2, c = 3;
|
var b = 2, c = 3;
|
||||||
b *= c;
|
b *= c;
|
||||||
console.log(a + b);
|
console.log(1 + b);
|
||||||
console.log(b + c);
|
console.log(b + 3);
|
||||||
console.log(4);
|
console.log(4);
|
||||||
console.log(a + b + c);
|
console.log(1 + b + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
function f4() {
|
function f4() {
|
||||||
var a = 1, b = 2, c = 3;
|
var b = 2, c = 3;
|
||||||
b = c;
|
b = c;
|
||||||
console.log(a + b);
|
console.log(1 + b);
|
||||||
console.log(b + c);
|
console.log(b + c);
|
||||||
console.log(a + c);
|
console.log(1 + c);
|
||||||
console.log(a + b + c);
|
console.log(1 + b + c);
|
||||||
}
|
}
|
||||||
|
|
||||||
function f5(a) {
|
function f5(a) {
|
||||||
|
|||||||
Reference in New Issue
Block a user