consys
Version:
consys is a flexible tool to evaluate models using generic and readable constraints.
175 lines (174 loc) • 5.67 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const Interpreter_1 = __importDefault(require("./Interpreter"));
const Lexer_1 = __importDefault(require("./Lexer"));
const Parser_1 = __importDefault(require("./Parser"));
var TextTokenType;
(function (TextTokenType) {
TextTokenType[TextTokenType["MODEL"] = 0] = "MODEL";
TextTokenType[TextTokenType["STATE"] = 1] = "STATE";
TextTokenType[TextTokenType["FUNCTION"] = 2] = "FUNCTION";
TextTokenType[TextTokenType["FUNCTION_EXPR"] = 3] = "FUNCTION_EXPR";
})(TextTokenType || (TextTokenType = {}));
class TextProcessor {
constructor(source, functions = {}) {
this.interpreter = new Interpreter_1.default();
this.source = '';
this.functions = {};
this.textTokens = [];
this.current = 0;
this.start = 0;
this.source = source;
this.functions = functions;
this.scan();
}
process(model, state, functions = {}, rescan = true) {
if (this.source === '') {
return '';
}
if (rescan) {
this.functions = functions;
this.scan();
}
if (this.textTokens.length === 0) {
return this.source;
}
let res = this.source + '';
// iterate backwards so the positions do not change for the other tokens
for (let i = this.textTokens.length - 1; i >= 0; i--) {
const token = this.textTokens[i];
if (!!token.ast) {
let value = this.interpreter.interpret(token.ast, model, state, this.functions);
res =
res.substring(0, token.position) +
value +
res.substring(token.position + token.lexeme.length);
}
}
return res;
}
scan() {
this.current = 0;
this.start = 0;
this.textTokens = [];
while (!this.isAtEnd()) {
this.start = this.current;
this.scanToken();
}
}
scanToken() {
const currentSymbol = this.advance();
switch (currentSymbol) {
case '$':
this.scanVariable(TextTokenType.MODEL);
break;
case '#':
this.scanVariable(TextTokenType.STATE);
break;
default:
if (!!currentSymbol.match(/[a-zA-Z_]/)) {
this.scanFunction();
}
break;
}
}
scanVariable(type) {
if (!!this.peek().match(/[a-zA-Z_]/)) {
while (!this.isAtEnd()) {
while (!!this.peek().match(/[a-zA-Z0-9_]/)) {
this.advance();
}
if (this.peek() === '.' && this.peekNext().match(/[a-zA-Z_]/)) {
this.advance();
}
else {
break;
}
}
}
const lexeme = this.source.substring(this.start, this.current);
this.addToken(lexeme, this.start, type);
}
scanArguments() {
let stackCount = 0;
while (!this.isAtEnd()) {
switch (this.peek()) {
case '(':
stackCount++;
break;
case ')':
stackCount--;
break;
}
if (stackCount === 0) {
return;
}
this.advance();
}
}
scanFunction() {
while (!!this.peek().match(/[a-zA-Z0-9_]/)) {
this.advance();
}
const identifier = this.source.substring(this.start, this.current);
// not a function
if (!this.functions[identifier]) {
return;
}
if (this.peek() === '(') {
this.scanArguments();
if (this.peek() === ')') {
this.advance();
const lexeme = this.source.substring(this.start, this.current);
this.addToken(lexeme, this.start, TextTokenType.FUNCTION);
}
return;
}
this.addToken(identifier, this.start, TextTokenType.FUNCTION_EXPR);
}
addToken(lexeme, position, type) {
this.textTokens.push({
lexeme: lexeme,
position: position,
type: type,
ast: this.generateAST(lexeme, position, type),
});
}
generateAST(text, offset, type) {
const lexer = new Lexer_1.default(text, offset);
const tokens = lexer.scan();
const parser = new Parser_1.default(text, tokens);
switch (type) {
case TextTokenType.MODEL:
return parser.parseModel();
case TextTokenType.STATE:
return parser.parseState();
case TextTokenType.FUNCTION:
return parser.parseFunction();
case TextTokenType.FUNCTION_EXPR:
return parser.parseFunctionExpr();
}
}
isAtEnd() {
return this.current >= this.source.length;
}
advance() {
return this.source.charAt(this.current++);
}
peek() {
if (this.isAtEnd()) {
return '\0';
}
return this.source.charAt(this.current);
}
peekNext() {
if (this.current + 1 >= this.source.length) {
return '\0';
}
return this.source.charAt(this.current + 1);
}
}
exports.default = TextProcessor;