UNPKG

@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
"use strict"; 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;