dotlr
Version:
An LR(1) parser generator and visualizer created for educational purposes.
166 lines (165 loc) • 4.92 kB
JavaScript
import { Grammar as _Grammar, Parser as _Parser, } from "./pkg/dotlr";
import { Err, Ok } from "ts-results-es";
export class Grammar {
constructor(grammar) {
this.cache = {
symbols: null,
constant_tokens: null,
start_symbol: null,
regex_tokens: null,
productions: null,
stringify: null,
};
this.grammar = grammar;
}
static parse(grammar) {
try {
const res = _Grammar.parse_wasm(grammar);
return Ok(new Grammar(res));
}
catch (e) {
return Err(e);
}
}
getSymbols() {
var _a;
return ((_a = this.cache).symbols ?? (_a.symbols = this.grammar.symbols_wasm()));
}
getConstantTokens() {
var _a;
return ((_a = this.cache).constant_tokens ?? (_a.constant_tokens = this.grammar.constant_tokens_wasm()));
}
getStartSymbol() {
var _a;
return ((_a = this.cache).start_symbol ?? (_a.start_symbol = this.grammar.start_symbol_wasm()));
}
getProductions() {
var _a;
return ((_a = this.cache).productions ?? (_a.productions = this.grammar.rules_wasm()));
}
getRegexTokens() {
var _a;
return ((_a = this.cache).regex_tokens ?? (_a.regex_tokens = this.grammar.regular_expressions_wasm()));
}
stringify() {
var _a;
return ((_a = this.cache).stringify ?? (_a.stringify = this.grammar.to_string_wasm()));
}
clone() {
return new Grammar(this.grammar.clone_wasm());
}
}
export class Parser {
constructor(parser) {
this.cache = {
action_table: null,
goto_table: null,
parsing_tables: null,
automaton: null,
first_table: null,
follow_table: null,
};
this.parser = parser;
}
parse(input) {
try {
return Ok(this.parser.parse_wasm(input));
}
catch (e) {
return Err(e);
}
}
getActionTable() {
var _a;
return ((_a = this.cache).action_table ?? (_a.action_table = this.parser.action_table_wasm()));
}
getGotoTable() {
var _a;
return ((_a = this.cache).goto_table ?? (_a.goto_table = this.parser.goto_table_wasm()));
}
getParseTables() {
var _a;
return ((_a = this.cache).parsing_tables ?? (_a.parsing_tables = this.parser.parsing_tables_wasm()));
}
getAutomaton() {
var _a;
return ((_a = this.cache).automaton ?? (_a.automaton = this.parser.automaton_wasm()));
}
getFirstTable() {
var _a;
return ((_a = this.cache).first_table ?? (_a.first_table = this.parser.first_table_wasm()));
}
getFollowTable() {
var _a;
return ((_a = this.cache).follow_table ?? (_a.follow_table = this.parser.follow_table_wasm()));
}
tokenize(input) {
try {
const tokens = this.parser.tokenize_wasm(input);
return Ok(tokens.map(([token, slice]) => ({
token,
slice,
})));
}
catch (e) {
return Err(e);
}
}
trace(input) {
try {
const [trace, tree] = this.parser.trace_wasm(input);
return Ok({
trace,
tree,
});
}
catch (e) {
return Err(e);
}
}
}
// this function tries to recover the serialized parser into the actual parser
function mapParserError(error, kind) {
const serialized = error.serialize();
if (serialized.type === "Conflict") {
serialized.value.parser =
kind === "lalr1"
? // @ts-expect-error private constructor
new LALR1Parser(error.into_conflict_parser())
: // @ts-expect-error private constructor
new LR1Parser(error.into_conflict_parser());
}
return serialized;
}
export class LR1Parser extends Parser {
constructor(parser) {
super(parser);
}
/**
* Consumes a grammar and returns a parser, the grammar is consumed and the ownership is transferred to the parser
*/
static fromGrammar(grammar) {
try {
return Ok(new LR1Parser(_Parser.new_wasm(grammar.grammar)));
}
catch (e) {
return Err(mapParserError(e, "lr1"));
}
}
}
export class LALR1Parser extends Parser {
constructor(parser) {
super(parser);
}
/**
* Consumes a grammar and returns a parser, the grammar is consumed and the ownership is transferred to the parser
*/
static fromGrammar(grammar) {
try {
return Ok(new LALR1Parser(_Parser.new_wasm(grammar.grammar)));
}
catch (e) {
return Err(mapParserError(e, "lalr1"));
}
}
}