consys
Version:
consys is a flexible tool to evaluate models using generic and readable constraints.
136 lines (135 loc) • 4.95 kB
JavaScript
"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;