UNPKG

consys

Version:

consys is a flexible tool to evaluate models using generic and readable constraints.

136 lines (135 loc) 4.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const Token_1 = require("./Token"); const Util_1 = require("../Util"); class Interpreter { constructor() { // store the current model, state and registered functions for evaluation this.model = null; this.state = null; this.source = ''; this.functions = null; } interpret(ast, model, state, functions) { var _a; this.model = model; this.state = state; this.source = ast.source; this.functions = functions; return (_a = ast.root) === null || _a === void 0 ? void 0 : _a.accept(this); } visitBinaryExpression(expression) { const left = expression.left.accept(this); const right = expression.right.accept(this); switch (expression.operator.type) { case Token_1.TokenType.PLUS: return left + right; case Token_1.TokenType.MINUS: return left - right; case Token_1.TokenType.STAR: return left * right; case Token_1.TokenType.SLASH: if (right === 0) { this.reportError(`Division by zero`, expression.operator.position); return false; } return left / right; case Token_1.TokenType.PERCENT: if (right === 0) { this.reportError(`Division by zero`, expression.operator.position); return false; } return left % right; case Token_1.TokenType.EXCLAMATION_MARK_EQUAL: return left != right; case Token_1.TokenType.EQUAL_EQUAL: return left == right; case Token_1.TokenType.GREATER: return left > right; case Token_1.TokenType.GREATER_EQUAL: return left >= right; case Token_1.TokenType.LESS: return left < right; default: return left <= right; } } visitConstraintExpression(expression) { const activation = expression.activation.accept(this); if (activation) { return expression.assertion.accept(this); } return true; } visitFunctionExpression(expression) { let name = expression.name.lexeme; if (!this.functions || (!!this.functions && this.functions[name] === undefined)) { this.reportError(`Function '${name}' is not registered`, expression.name.position); return false; } let args; if (expression.args.length === 0) { args = [this.model, this.state]; } else { args = expression.args.map(arg => arg.accept(this)); } return this.functions[name](...args); } visitGroupingExpression(expression) { return expression.expression.accept(this); } visitLiteralExpression(expression) { return expression.value.literal; } visitLogicalExpression(expression) { const left = expression.left.accept(this); if (expression.operator.type === Token_1.TokenType.PIPE_PIPE || expression.operator.type === Token_1.TokenType.OR) { if (!!left) { return left; } } else { if (!left) { return left; } } return expression.right.accept(this); } visitUnaryExpression(expression) { const right = expression.right.accept(this); if (expression.operator.type === Token_1.TokenType.MINUS) { return -right; } return !right; } visitVariableExpression(expression) { let value = this.model; if (expression.prefix.type === Token_1.TokenType.HASH) { value = this.state; } if (expression.name.length === 0) { return JSON.stringify(value); } for (let name of expression.name) { if (value[name.lexeme] === undefined) { const type = expression.prefix.type === Token_1.TokenType.HASH ? 'state' : 'model'; const variable = expression.prefix.type === Token_1.TokenType.HASH ? this.state : this.model; const fullVariableName = expression.name .map(token => token.lexeme) .join('.'); const position = name.position; this.reportError(`Attribute '${fullVariableName}' not found in ${type}: ${JSON.stringify(variable)}`, position); return false; } value = value[name.lexeme]; } return value; } reportError(message, position) { Util_1.Log.reportError('Evaluation', this.source, message, position); } } exports.default = Interpreter;