/
logical-expression.js
80 lines (69 loc) · 2.28 KB
/
logical-expression.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
"use strict";
const h = require("./helpers");
const PatternMatch = require("./pattern-match");
const evaluate = require("babel-helper-evaluate-path");
module.exports = t => {
const OP_AND = input => input === "&&";
const OP_OR = input => input === "||";
function simplifyPatterns(path) {
// cache of evaluate(path)
const evaluateMemo = new Map();
const TRUTHY = input => {
// !NaN and !undefined are truthy
// separate check here as they are considered impure by babel
if (input.isUnaryExpression() && input.get("argument").isIdentifier()) {
if (
input.node.argument.name === "NaN" ||
input.node.argument.name === "undefined"
) {
return true;
}
}
const evalResult = evaluate(input);
evaluateMemo.set(input, evalResult);
return evalResult.confident && input.isPure() && evalResult.value;
};
const FALSY = input => {
// NaN and undefined are falsy
// separate check here as they are considered impure by babel
if (input.isIdentifier()) {
if (input.node.name === "NaN" || input.node.name === "undefined") {
return true;
}
}
const evalResult = evaluate(input);
evaluateMemo.set(input, evalResult);
return evalResult.confident && input.isPure() && !evalResult.value;
};
const { Expression: EX } = h.typeSymbols(t);
// Convention:
// [left, operator, right, handler(leftNode, rightNode)]
const matcher = new PatternMatch([
[TRUTHY, OP_AND, EX, (l, r) => r],
[FALSY, OP_AND, EX, l => l],
[TRUTHY, OP_OR, EX, l => l],
[FALSY, OP_OR, EX, (l, r) => r]
]);
const left = path.get("left");
const right = path.get("right");
const operator = path.node.operator;
const result = matcher.match(
[left, operator, right],
h.isPatternMatchesPath(t)
);
if (result.match) {
// here we are sure that left.evaluate is always confident becuase
// it satisfied one of TRUTHY/FALSY paths
let value;
if (evaluateMemo.has(left)) {
value = evaluateMemo.get(left).value;
} else {
value = evaluate(left).value;
}
path.replaceWith(result.value(t.valueToNode(value), right.node));
}
}
return {
simplifyPatterns
};
};