Merge pull request #2293 from andrewimm/master

Allow more certainty when evaluating Logical Expressions
This commit is contained in:
Sebastian McKenzie 2015-09-12 18:59:48 +01:00
commit f18f79cc6d
2 changed files with 182 additions and 2 deletions

View File

@ -141,12 +141,28 @@ export function evaluate(): { confident: boolean; value: any } {
}
if (path.isLogicalExpression()) {
// If we are confident that one side of an && is false, or one side of
// an || is true, we can be confident about the entire expression
let wasConfident = confident;
let left = evaluate(path.get("left"));
let leftConfident = confident;
confident = wasConfident;
let right = evaluate(path.get("right"));
let rightConfident = confident;
let uncertain = leftConfident !== rightConfident;
confident = leftConfident && rightConfident;
switch (node.operator) {
case "||": return left || right;
case "&&": return left && right;
case "||":
if ((left || right) && uncertain) {
confident = true;
}
return left || right;
case "&&":
if ((!left && leftConfident) || (!right && rightConfident)) {
confident = true;
}
return left && right;
}
}

View File

@ -0,0 +1,164 @@
var evaluation = require("../lib/traversal/path/evaluation");
var traverse = require('../lib/traversal');
var parse = require("../lib/helpers/parse");
var assert = require("assert");
suite("evaluation", function () {
test("binary expression", function () {
traverse(parse("5 + 5"), {
enter: function (node) {
if (this.isBinaryExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: 10 });
}
}
});
traverse(parse("'str' === 'str'"), {
enter: function(node) {
if (this.isBinaryExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'four' === 4"), {
enter: function(node) {
if (this.isBinaryExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: false });
}
}
});
});
test("logical expression", function () {
traverse(parse("'abc' === 'abc' && 1 === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'abc' === 'abc' && 1 === 10"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: false });
}
}
});
traverse(parse("'abc' === 'xyz' && 1 === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: false });
}
}
});
traverse(parse("'abc' === 'xyz' && 1 === 10"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: false });
}
}
});
traverse(parse("'abc' === 'abc' || 1 === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'abc' === 'abc' || 1 === 10"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'abc' === 'xyz' || 1 === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'abc' === 'xyz' || 1 === 10"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: false });
}
}
});
});
test("logical expression without certainty", function () {
traverse(parse("'abc' === 'abc' || config.flag === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("obj.a === 'abc' || config.flag === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: false, value: undefined });
}
}
});
traverse(parse("'abc' !== 'abc' && config.flag === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: false });
}
}
});
traverse(parse("obj.a === 'abc' && 1 === 1"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: false, value: undefined });
}
}
});
traverse(parse("'abc' === 'abc' && (1 === 1 || config.flag)"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'abc' === 'xyz' || (1 === 1 && config.flag)"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: false, value: undefined });
}
}
});
traverse(parse("'abc' === 'xyz' || (1 === 1 && 'four' === 'four')"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
traverse(parse("'abc' === 'abc' && (1 === 1 && 'four' === 'four')"), {
enter: function(node) {
if (this.isLogicalExpression()) {
assert.deepEqual(this.evaluate(), { confident: true, value: true });
}
}
});
});
});