ts-fusion-parser
Version:
Parser for Neos Fusion Files
156 lines (155 loc) • 6.2 kB
JavaScript
;
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]: `^\\/\\**(?:\\*[^\\/][^*]*)*\\*?\\*\\*\\/`,
};