UNPKG

@jkearl/pratt

Version:

Pratt parser builder (along with simple tokenizer)

118 lines 3.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PARENTHESES_PARSELET = { parse(parser) { const expr = parser.parse(); if (!parser.match(")")) { throw new Error("Parse error: expected `)`"); } return expr; }, }; class ParserBuilder { constructor(tokenizer) { this.tokenizer = tokenizer; this.prefixParselets = {}; this.infixParselets = {}; } registerInfix(tokenType, parselet) { this.infixParselets[tokenType] = parselet; return this; } registerPrefix(tokenType, parselet) { this.prefixParselets[tokenType] = parselet; return this; } prefix(tokenType, precedence, builder) { this.prefixParselets[tokenType] = { parse(parser, token) { const right = parser.parse(precedence); return builder(token, right); }, }; return this; } postfix(tokenType, precedence, builder) { this.infixParselets[tokenType] = { parse(parser, left, token) { return builder(left, token); }, precedence, }; return this; } infixLeft(tokenType, precedence, builder) { this.infixParselets[tokenType] = { parse(parser, left, token) { const right = parser.parse(precedence); return builder(left, token, right); }, precedence, }; return this; } infixRight(tokenType, precedence, builder) { this.infixParselets[tokenType] = { parse(parser, left, token) { const right = parser.parse(precedence - 1); return builder(left, token, right); }, precedence, }; return this; } construct() { return (input) => new Parser(this.tokenizer(input), this.prefixParselets, this.infixParselets).parse(); } } exports.ParserBuilder = ParserBuilder; class Parser { constructor(tokens, prefixParselets, infixParselets) { this.tokens = tokens; this.prefixParselets = prefixParselets; this.infixParselets = infixParselets; } match(expected) { const token = this.look(); if (token.id !== expected) { return false; } this.consume(); return true; } parse(precedence = 0) { const token = this.consume(); const prefix = this.prefixParselets[token.id]; if (!prefix) { throw Error(`Parse error at ${token.value}. No matching prefix parselet.`); } let left = prefix.parse(this, token); while (precedence < this.getPrecedence()) { const token = this.consume(); const infix = this.infixParselets[token.id]; left = infix.parse(this, left, token); } return left; } getPrecedence() { const nextToken = this.look(); if (!nextToken) { return 0; } const parser = this.infixParselets[nextToken.id]; if (parser) { return parser.precedence; } return 0; } consume() { if (!this.tokens.length) { throw Error("Cant consume any more tokens."); } return this.tokens.shift(); } look() { return this.tokens[0]; } } //# sourceMappingURL=parse.js.map