xast
Version:
AST parsing library
148 lines • 5.57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
const Location_1 = require("./Location");
const TokenKind_1 = require("./TokenKind");
const schema_1 = require("./parsers/schema");
const ANY_KEYWORD = Symbol('@@any');
class Parser {
constructor(lexer, options = {}) {
this.lexer = lexer;
this._options = options;
this._tokenCounter = 0;
this._parsersMap = new Map;
}
parseSchema() {
return this.expectParse(schema_1.schemaParser);
}
add(nodeParser) {
var _a, _b;
if (nodeParser.trigger) {
if (!this._parsersMap.has(nodeParser.trigger.kind)) {
this._parsersMap.set(nodeParser.trigger.kind, new Map);
}
const parsersKindMap = this._parsersMap.get(nodeParser.trigger.kind);
const keyword = (_a = nodeParser.trigger.keyword) !== null && _a !== void 0 ? _a : ANY_KEYWORD;
if (!(parsersKindMap === null || parsersKindMap === void 0 ? void 0 : parsersKindMap.has(keyword))) {
parsersKindMap === null || parsersKindMap === void 0 ? void 0 : parsersKindMap.set(keyword, []);
}
(_b = parsersKindMap === null || parsersKindMap === void 0 ? void 0 : parsersKindMap.get(keyword)) === null || _b === void 0 ? void 0 : _b.push(nodeParser);
}
}
parseToken(token) {
if (this._parsersMap.has(token.kind)) {
const parsersKindMap = this._parsersMap.get(token.kind);
for (const keyword of [token.value, ANY_KEYWORD]) {
const nodeParsers = (parsersKindMap === null || parsersKindMap === void 0 ? void 0 : parsersKindMap.get(keyword)) || [];
for (const nodeParser of nodeParsers) {
const node = nodeParser.parse(this);
if (node) {
return node;
}
}
}
}
}
optionalParse(nodeParser) {
return nodeParser.parse(this);
}
expectParse(nodeParser) {
const node = nodeParser.parse(this);
if (node) {
return node;
}
throw this.lexer.source.syntaxError(this.lexer.token.start, `Expected ${nodeParser.kind}, found ${this.lexer.token.getDescription()}.`);
}
node(startToken, node) {
if (this._options.enableLocation) {
node.loc = new Location_1.Location(startToken, this.lexer.lastToken, this.lexer.source);
}
return node;
}
peek(kind) {
return this.lexer.token.kind === kind;
}
expectToken(kind) {
const token = this.lexer.token;
if (token.kind === kind) {
this.advanceLexer();
return token;
}
throw this.lexer.source.syntaxError(token.start, `Expected ${(0, TokenKind_1.getTokenKindDescription)(kind)}, found ${token.getDescription()}.`);
}
expectOptionalToken(kind) {
const token = this.lexer.token;
if (token.kind === kind) {
this.advanceLexer();
return true;
}
return false;
}
expectKeyword(value) {
const token = this.lexer.token;
if (token.kind === TokenKind_1.TokenKind.NAME && token.value === value) {
this.advanceLexer();
}
else {
throw this.lexer.source.syntaxError(token.start, `Expected "${value}", found ${token.getDescription()}.`);
}
}
expectOptionalKeyword(value) {
const token = this.lexer.token;
if (token.kind === TokenKind_1.TokenKind.NAME && token.value === value) {
this.advanceLexer();
return true;
}
return false;
}
unexpected(atToken) {
const token = atToken !== null && atToken !== void 0 ? atToken : this.lexer.token;
return this.lexer.source.syntaxError(token.start, `Unexpected ${token.getDescription()}.`);
}
any(openKind, nodeParser, closeKind) {
this.expectToken(openKind);
const nodes = [];
while (!this.expectOptionalToken(closeKind)) {
nodes.push(this.expectParse(nodeParser));
}
return nodes;
}
many(openKind, nodeParser, closeKind) {
this.expectToken(openKind);
const nodes = [];
do {
nodes.push(this.expectParse(nodeParser));
} while (!this.expectOptionalToken(closeKind));
return nodes;
}
optionalMany(openKind, nodeParser, closeKind) {
if (this.expectOptionalToken(openKind)) {
const nodes = [];
do {
nodes.push(this.expectParse(nodeParser));
} while (!this.expectOptionalToken(closeKind));
return nodes;
}
return [];
}
delimitedMany(delimiterKind, nodeParser) {
this.expectOptionalToken(delimiterKind);
const nodes = [];
do {
nodes.push(this.expectParse(nodeParser));
} while (this.expectOptionalToken(delimiterKind));
return nodes;
}
advanceLexer() {
const { maxTokens } = this._options;
const token = this.lexer.advance();
if (maxTokens !== undefined && token.kind !== TokenKind_1.TokenKind.EOF) {
++this._tokenCounter;
if (this._tokenCounter > maxTokens) {
throw this.lexer.source.syntaxError(token.start, `Schema contains more than ${maxTokens} tokens.`);
}
}
}
}
exports.Parser = Parser;
//# sourceMappingURL=Parser.js.map