@scinorandex/sparse
Version:
Yet another parser generator
73 lines • 3.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildProductions = exports.tryBuildProductions = exports.grammarLexerGenerator = exports.GrammarTokenType = void 0;
const slex_1 = require("@scinorandex/slex");
var GrammarTokenType;
(function (GrammarTokenType) {
GrammarTokenType[GrammarTokenType["PRODUCTION_NAME"] = 0] = "PRODUCTION_NAME";
GrammarTokenType[GrammarTokenType["TOKEN_NAME"] = 1] = "TOKEN_NAME";
GrammarTokenType[GrammarTokenType["COLON"] = 2] = "COLON";
GrammarTokenType[GrammarTokenType["SEMICOLON"] = 3] = "SEMICOLON";
GrammarTokenType[GrammarTokenType["EOF"] = 4] = "EOF";
})(GrammarTokenType || (exports.GrammarTokenType = GrammarTokenType = {}));
exports.grammarLexerGenerator = new slex_1.Slex({
EOF_TYPE: GrammarTokenType.EOF,
isHigherPrecedence: () => false,
});
exports.grammarLexerGenerator.addRule("lowercase", "a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z");
exports.grammarLexerGenerator.addRule("uppercase", "A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z");
exports.grammarLexerGenerator.addRule("letter", "${lowercase} | ${uppercase}");
exports.grammarLexerGenerator.addRule("digit", "0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9");
exports.grammarLexerGenerator.addRule("alphanumeric", "${letter} | ${digit}");
exports.grammarLexerGenerator.addRule("identifier", "(${letter} | ${digit} | $_)*");
exports.grammarLexerGenerator.addRule("colon", "$:", GrammarTokenType.COLON);
exports.grammarLexerGenerator.addRule("semicolon", "$;", GrammarTokenType.SEMICOLON);
exports.grammarLexerGenerator.addRule("production_name", "$< ${identifier} $>", GrammarTokenType.PRODUCTION_NAME);
exports.grammarLexerGenerator.addRule("token_name", "$[ ${identifier} $]", GrammarTokenType.TOKEN_NAME);
const tryBuildProductions = (lexer) => {
if (typeof lexer === "string")
lexer = exports.grammarLexerGenerator.generate(lexer, () => ({}));
const productions = [];
const expect = (type) => {
const token = lexer.peekNextToken();
if (token.type !== type)
throw new Error(`Expected ${type}, got ${token.type}`);
lexer.getNextToken();
};
const buildProduction = () => {
const productionLHS = lexer.getNextToken();
expect(GrammarTokenType.COLON);
const production = { lhs: productionLHS, rhs: [] };
while (lexer.peekNextToken().type != GrammarTokenType.SEMICOLON) {
const productionRHS = lexer.getNextToken();
if (productionRHS.type == GrammarTokenType.PRODUCTION_NAME)
production.rhs.push({ type: "variable", token: productionRHS });
else if (productionRHS.type == GrammarTokenType.TOKEN_NAME)
production.rhs.push({ type: "terminal", token: productionRHS });
else
return {
success: false,
reason: `Unexpected token type: ${GrammarTokenType[productionRHS.type]}`,
token: productionRHS,
};
}
expect(GrammarTokenType.SEMICOLON);
return { success: true, value: production };
};
while (lexer.hasNextToken()) {
const result = buildProduction();
if (result.success === false)
return result;
productions.push(result.value);
}
return { success: true, value: productions };
};
exports.tryBuildProductions = tryBuildProductions;
const buildProductions = (lexer) => {
const result = (0, exports.tryBuildProductions)(lexer);
if (result.success === false)
throw new Error(`Encountered error "${result.reason}" while parsing grammar at ${result.token.line}:${result.token.column}`);
return result.value;
};
exports.buildProductions = buildProductions;
//# sourceMappingURL=grammarParser.js.map