@bokeh/bokehjs
Version:
Interactive, novel data visualization
114 lines • 4.28 kB
JavaScript
import { isFunction } from "../core/util/types";
import { dict } from "../core/util/object";
import { Parser, COMPOUND, LITERAL, IDENT, MEMBER, INDEX, CALL, UNARY, BINARY, SEQUENCE, ARRAY, FAILURE, } from "./parser";
import { np, is_Numerical } from "./linalg";
function evaluate(ast, refs) {
const np_proxy = dict(np);
function resolve(ast) {
switch (ast.type) {
case LITERAL:
return ast.value;
case IDENT:
if (ast.name.startsWith("$")) {
const i = Number(ast.name.slice(1));
if (isFinite(i) && 0 <= i && i < refs.length) {
return refs[i];
}
else {
throw new Error(`invalid reference: ${ast.name}`);
}
}
switch (ast.name) {
case "np":
return np;
default:
throw new Error(`unknown identifier: ${ast.name}`);
}
case MEMBER:
const obj = resolve(ast.object);
if (obj === np) {
const { name } = ast.member;
const member = np_proxy.get(name);
if (member !== undefined) {
return member;
}
else {
throw new Error(`'np.${name}' doesn't exist`);
}
}
else {
throw new Error("not an accessible expression");
}
case INDEX:
throw new Error("not an indexable expression");
case CALL:
const callee = resolve(ast.callee);
if (isFunction(callee)) {
return callee.apply(undefined, ast.args.map((arg) => resolve(arg)));
}
else {
throw new Error("not a callable expression");
}
case UNARY: {
const op = (() => {
switch (ast.operator) {
case "+": return np.pos;
case "-": return np.neg;
default:
throw new Error(`unsupported operator: ${ast.operator}`);
}
})();
const x = resolve(ast.argument);
if (is_Numerical(x)) {
return op(x);
}
else {
throw new Error("a number or an array was expected");
}
}
case BINARY:
const op = (() => {
switch (ast.operator) {
case "+": return np.add;
case "-": return np.sub;
case "*": return np.mul;
case "/": return np.div;
case "**": return np.pow;
case "<=": return np.le;
case ">=": return np.ge;
case "<": return np.lt;
case ">": return np.gt;
default:
throw new Error(`unsupported operator: ${ast.operator}`);
}
})();
const x = resolve(ast.left);
const y = resolve(ast.right);
if (is_Numerical(x) && is_Numerical(y)) {
return op(x, y);
}
else {
throw new Error("a number or an array was expected");
}
case COMPOUND:
case SEQUENCE:
case ARRAY:
default:
throw new Error("unsupported");
}
}
return resolve(ast);
}
export function f(strings, ...subs) {
const [head, ...tail] = strings;
const input = head + tail.map((s, i) => `($${i})${s}`).join("");
const parser = new Parser(input);
const ast = parser.parse();
if (ast.type != FAILURE) {
return evaluate(ast, subs);
}
else {
throw new Error(ast.message);
}
}
//# sourceMappingURL=expr.js.map