70 lines
1.8 KiB
JavaScript
70 lines
1.8 KiB
JavaScript
export default function ({ types: t }) {
|
|
return {
|
|
visitor: {
|
|
AssignmentExpression() {
|
|
var left = this.get("left");
|
|
if (!left.isIdentifier()) return;
|
|
|
|
var binding = this.scope.getBinding(left.node.name);
|
|
if (!binding || binding.hasDeoptValue) return;
|
|
|
|
var evaluated = this.get("right").evaluate();
|
|
if (evaluated.confident) {
|
|
binding.setValue(evaluated.value);
|
|
} else {
|
|
binding.deoptValue();
|
|
}
|
|
},
|
|
|
|
IfStatement(path) {
|
|
var evaluated = path.get("test").evaluate();
|
|
if (!evaluated.confident) {
|
|
// todo: deopt binding values for constant violations inside
|
|
return path.skip();
|
|
}
|
|
|
|
if (evaluated.value) {
|
|
path.skipKey("alternate");
|
|
} else {
|
|
path.skipKey("consequent");
|
|
}
|
|
},
|
|
|
|
Scopable: {
|
|
enter(path) {
|
|
var funcScope = path.scope.getFunctionParent();
|
|
|
|
for (var name in path.scope.bindings) {
|
|
var binding = path.scope.bindings[name];
|
|
var deopt = false;
|
|
|
|
for (let path of (binding.constantViolations: Array)) {
|
|
var funcViolationScope = path.scope.getFunctionParent();
|
|
if (funcViolationScope !== funcScope) {
|
|
deopt = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (deopt) binding.deoptValue();
|
|
}
|
|
},
|
|
|
|
exit(path) {
|
|
for (var name in path.scope.bindings) {
|
|
var binding = path.scope.bindings[name];
|
|
binding.clearValue();
|
|
}
|
|
}
|
|
},
|
|
|
|
Expression: {
|
|
exit(path) {
|
|
var res = path.evaluate();
|
|
if (res.confident) return t.valueToNode(res.value);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|