@valraiso-esf/expression-parser
Version:
An expression evaluator written in typescript with the goal to support SQL like WHERE clauses.
133 lines (132 loc) • 5.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.evaluateObject = exports.evaluate = void 0;
var parser_1 = require("./parser");
function evaluateExpressions(expressions, context) {
return expressions.map(function (exp) { return evaluateExpression(exp, context); });
}
function evaluateFunctionCall(name, args) {
switch (name) {
case 'length':
if (args.length !== 1) {
throw new Error('Length function takes exactly one argument.');
}
return args[0].length;
default:
throw new Error("Function " + name + " not implemented");
}
}
function evaluateBinaryExpression(expression, context) {
switch (expression.operator) {
case '+':
return evaluateExpression(expression.left, context) + evaluateExpression(expression.right, context);
case '-':
return evaluateExpression(expression.left, context) - evaluateExpression(expression.right, context);
case '*':
return evaluateExpression(expression.left, context) * evaluateExpression(expression.right, context);
case '/':
return evaluateExpression(expression.left, context) / evaluateExpression(expression.right, context);
case '=':
return evaluateExpression(expression.left, context) === evaluateExpression(expression.right, context);
case '<>':
return evaluateExpression(expression.left, context) !== evaluateExpression(expression.right, context);
case '>':
return evaluateExpression(expression.left, context) > evaluateExpression(expression.right, context);
case '>=':
return evaluateExpression(expression.left, context) >= evaluateExpression(expression.right, context);
case '<':
return evaluateExpression(expression.left, context) < evaluateExpression(expression.right, context);
case '<=':
return evaluateExpression(expression.left, context) <= evaluateExpression(expression.right, context);
case 'and':
return evaluateExpression(expression.left, context) && evaluateExpression(expression.right, context);
case 'or':
return evaluateExpression(expression.left, context) || evaluateExpression(expression.right, context);
default:
throw new Error("Operator " + expression.operator + " not implemented");
}
}
function evaluateCaseExpression(expression, context) {
for (var index = 0; index < expression.conditions.length; index++) {
var cond = expression.conditions[index];
if (evaluateExpression(cond.when, context)) {
return evaluateExpression(cond.then, context);
}
}
if (expression.last) {
return evaluateExpression(expression.last, context);
}
return false;
}
var invalidLeftSide = 'Invalid left side of IN expression';
function evaluateInExpression(expression, context) {
var left = expression.left, right = expression.right;
var leftValue = evaluateExpression(left, context);
var rightValues = evaluateExpression(right, context);
if (left.type === 'GroupExpression' && right.type === 'IdentifierExpression') {
if (!Array.isArray(leftValue)) {
throw new Error(invalidLeftSide);
}
if (rightValues == null) {
throw new Error(right.name + " is not defined");
}
if (!Array.isArray(rightValues)) {
throw new Error('Right side of IN expression must be an array');
}
return leftValue.every(function (v) { return rightValues.indexOf(v) !== -1; });
}
else if (left.type === 'IdentifierExpression' && right.type === 'GroupExpression') {
if (leftValue == null) {
throw new Error(left.name + " is not defined");
}
else {
if (Array.isArray(leftValue)) {
return leftValue.every(function (v) { return rightValues.includes(v); });
}
else if (typeof leftValue === 'object' && leftValue !== null) {
throw new Error(invalidLeftSide);
}
else {
return rightValues.includes(leftValue);
}
}
}
else {
throw new Error('Invalid left or right side of IN expression');
}
}
function evaluateGroupExpression(expression, context) {
var values = expression.values.map(function (v) { return evaluateExpression(v, context); });
return values;
}
function evaluateExpression(expression, context) {
switch (expression.type) {
case 'IdentifierExpression':
return context(expression.name);
case 'ValueExpression':
return expression.value;
case 'FunctionCallExpression':
return evaluateFunctionCall(expression.name, evaluateExpressions(expression.args, context));
case 'BinaryExpression':
return evaluateBinaryExpression(expression, context);
case 'CaseExpression':
return evaluateCaseExpression(expression, context);
case 'InExpression':
return evaluateInExpression(expression, context);
case 'GroupExpression':
return evaluateGroupExpression(expression, context);
case 'NotExpression':
return !evaluateExpression(expression.expression, context);
default:
throw new Error("Invalid AST node" + expression);
}
}
function evaluate(expression, context) {
var ast = parser_1.parse(expression);
return evaluateExpression(ast, context);
}
exports.evaluate = evaluate;
function evaluateObject(expression, value) {
return evaluate(expression, function (name) { return value[name]; });
}
exports.evaluateObject = evaluateObject;