-
Notifications
You must be signed in to change notification settings - Fork 0
/
Boolio.js
84 lines (70 loc) · 1.83 KB
/
Boolio.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
const ESParser = require("./ESParser");
const parser = new ESParser();
function booleanPairCombinations(n) {
if (n === 1) {
return [[true], [false]];
}
const combinationsMinusOne = booleanPairCombinations(n - 1);
return combinationsMinusOne
.map(rows => [true, ...rows])
.concat(combinationsMinusOne.map(rows => [false, ...rows]));
}
module.exports = class Boolio {
constructor(expression) {
this.ast = this.parse(expression);
}
parse(expression) {
return parser.parse(expression);
}
evaluate(values) {
return this.evaluateNode(this.ast, values);
}
evaluateNode(node, values) {
if (node.type === "atom") {
return values[node.name];
}
if (node.type === "and") {
return (
this.evaluateNode(node.left, values) &&
this.evaluateNode(node.right, values)
);
}
if (node.type === "or") {
return (
this.evaluateNode(node.left, values) ||
this.evaluateNode(node.right, values)
);
}
if (node.type === "not") {
return !this.evaluateNode(node.argument, values);
}
throw new Error(`Cannot evaluate type: ${node.type}`);
}
atoms() {
function findAtoms(node) {
if (node.type === "atom") {
return [node.name];
}
if (node.type === "or" || node.type === "and") {
return findAtoms(node.left).concat(findAtoms(node.right));
}
if (node.type === "not") {
return findAtoms(node.argument);
}
}
return new Set(findAtoms(this.ast));
}
truthTable() {
const atoms = Array.from(this.atoms());
return {
atoms,
rows: booleanPairCombinations(atoms.length).map(row => {
const values = {};
atoms.forEach((atom, i) => {
values[atom] = row[i];
});
return [...row, this.evaluate(values)];
})
};
}
};