UNPKG

consys

Version:

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

175 lines (174 loc) 5.67 kB
"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;