UNPKG

ts-fusion-parser

Version:

Parser for Neos Fusion Files

156 lines (155 loc) 6.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Lexer = void 0; const token_1 = require("./token"); class Lexer { constructor(code) { this.mode = "fusion"; this.code = ''; this.codeLen = 0; this.cursor = 0; this.lookahead = null; code = code.replace("\r", "\n").replace("\r\n", "\n"); this.code = code; this.codeLen = code.length; } getCode() { return this.code; } getCursor() { return this.cursor; } advanceCursor(amount) { this.cursor += amount; this.lookahead = null; } getRemainingCode() { return this.code.substring(this.cursor); } consumeLookahead() { const token = this.lookahead; this.lookahead = null; return token; } getCachedLookaheadOrTryToGenerateLookaheadForTokenAndGetLookahead(tokenType, debug = false) { if (tokenType === undefined) throw new Error("got undefined tokentype"); const logging = debug; if (this.lookahead !== null) return this.lookahead; if (this.cursor === this.codeLen) return this.lookahead = new token_1.Token(token_1.Token.EOF, ''); if (tokenType === token_1.Token.EOF) return null; const regexStringForToken = Lexer.TOKEN_REGEX[tokenType]; if (logging) this.log("regexStringForToken " + tokenType, regexStringForToken); const remainingCode = this.code.substring(this.cursor); if (logging) this.log("remainingCode|" + remainingCode); const regexForToken = new RegExp(regexStringForToken, 'g'); if (logging) this.log("regexForToken", regexForToken); const matches = regexForToken.exec(remainingCode); if (logging) this.log("matches", matches); if (matches === null) { return null; } this.cursor += matches[0].length; this.lookahead = new token_1.Token(tokenType, matches[0]); return this.lookahead; } consumeUntil(tokenType, logging = false) { const regexStringForToken = Lexer.TOKEN_REGEX[tokenType]; if (logging) this.log("regexStringForToken", regexStringForToken); const regexForToken = new RegExp(regexStringForToken, 'g'); if (logging) this.log("regexForToken", regexForToken); let cursor = this.cursor; let found = ''; let next = this.code.substring(cursor); while (!regexForToken.test(next) && cursor < this.code.length) { if (logging) this.log("found:" + found, "next:" + next); found += next[0]; next = next.substring(1); cursor++; } if (logging) this.log("this.cursor", this.cursor); this.cursor += found.length; if (logging) this.log("this.cursor", this.cursor); this.lookahead = null; return found; } debug() { this.log("remainingCode|" + this.code.substring(this.cursor)); // console.trace() // this.log("exiting...") // NodeProcess.exit() } log(...args) { console.log(this.mode, ...args); } } exports.Lexer = Lexer; // Difference to: Neos\Eel\Package.EelExpressionRecognizer // added an atomic group (to prevent catastrophic backtracking) and removed the end anchor // protected static PATTERN_EEL_EXPRESSION = `^\\\${(?<exp>(>{ (>exp) }|[^{}"']+|"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*')*)}`; Lexer.PATTERN_EEL_EXPRESSION = `^\\\${(.*)}(?=\\s*\\n)`; Lexer.TOKEN_REGEX = { [token_1.Token.SLASH_COMMENT]: '^\\/\\/(?!\\/).*', [token_1.Token.HASH_COMMENT]: '^#.*', [token_1.Token.MULTILINE_COMMENT]: `^\\/\\*[^*]*(?:\\*[^/][^*]*)*\\*\\/`, [token_1.Token.NEWLINE]: '^[\\n\\r]+', [token_1.Token.SPACE]: '^[ \\t]+', // VALUE ASSIGNMENT [token_1.Token.TRUE_VALUE]: '^(?=(true|TRUE))\\1', [token_1.Token.FALSE_VALUE]: '^(?=(false|FALSE))\\1', [token_1.Token.NULL_VALUE]: '^(?=(null|NULL))\\1', [token_1.Token.INTEGER]: '^-?[0-9]+', [token_1.Token.FLOAT]: '^-?[0-9]+\\.[0-9]+', // '/^[a-zA-Z0-9\.]++(?=`)/' [token_1.Token.DSL_EXPRESSION_START]: '^[a-zA-Z0-9\.]+(?=`)', // /^`[^`]*+`/ [token_1.Token.DSL_EXPRESSION_CONTENT]: '^`[^`]*`', [token_1.Token.EEL_EXPRESSION]: Lexer.PATTERN_EEL_EXPRESSION, // Object type part [token_1.Token.FUSION_OBJECT_NAME]: '^[0-9a-zA-Z.]+(?::[0-9a-zA-Z.]+)?', // Keywords [token_1.Token.INCLUDE]: '^include\\s*:', // Object path segments [token_1.Token.PROTOTYPE_START]: '^prototype\\(', [token_1.Token.META_PATH_START]: '^@', [token_1.Token.OBJECT_PATH_PART]: '^[a-zA-Z0-9_:-]+', // Operators [token_1.Token.ASSIGNMENT]: '^=', [token_1.Token.COPY]: '^<', [token_1.Token.UNSET]: '^>', // Symbols [token_1.Token.DOT]: '^\\.', [token_1.Token.COLON]: '^:', [token_1.Token.RPAREN]: '^\\)', [token_1.Token.LBRACE]: '^{', [token_1.Token.RBRACE]: '^}', [token_1.Token.LBRACKET]: '^\\[', [token_1.Token.RBRACKET]: '^\\]', // Strings [token_1.Token.STRING_DOUBLE_QUOTED]: `^"[^"\\\\\\\\]*(?:\\\\.[^"\\\\\\\\]*)*"`, [token_1.Token.STRING_SINGLE_QUOTED]: `^'[^'\\\\\\\\]*(?:\\\\.[^'\\\\\\\\]*)*'`, [token_1.Token.FILE_PATTERN]: '^[a-zA-Z0-9.*:/_-]+', [token_1.Token.EEL_EXPRESSION_START]: `^\\\${`, [token_1.Token.STRING_SINGLE_QUOTED_START]: `^'`, [token_1.Token.STRING_DOUBLE_QUOTED_START]: `^"`, [token_1.Token.EEL_EXPRESSION_FUNCTION_PATH]: `^([0-9a-zA-Z])+(?:\\.[0-9a-zA-Z]+)*\\(`, [token_1.Token.EEL_EXPRESSION_OBJECT_PATH]: `^([0-9a-zA-Z])+(?:\\.[0-9a-zA-Z]+)*`, [token_1.Token.EEL_EXPRESSION_OBJECT_PATH_PART]: `^[0-9a-zA-Z]+`, [token_1.Token.EEL_EXPRESSION_CALLBACK]: `^\\(([a-zA-Z]+(?:\\s*,\\s*[a-zA-Z]+)*)\\)\\s*=>`, [token_1.Token.LPAREN]: '^\\(', [token_1.Token.COMMA]: '^,', [token_1.Token.PROPERTY_DOCUMENTATION_DEFINITION]: '^\\/\\/\\/.*', [token_1.Token.PROTOTYPE_DOCUMENTATION_DEFINITION]: `^\\/\\**(?:\\*[^\\/][^*]*)*\\*?\\*\\*\\/`, };