Skip to content

Instantly share code, notes, and snippets.

@joelburget
Created September 18, 2023 02:15
Show Gist options
  • Save joelburget/39199fefa7401ad3ff4f2654c5b58393 to your computer and use it in GitHub Desktop.
Save joelburget/39199fefa7401ad3ff4f2654c5b58393 to your computer and use it in GitHub Desktop.
import { expect, test } from "bun:test";
import { createToken, Lexer, CstParser } from "chevrotain";
import type { CstNode, IToken } from "chevrotain";
const Integer = createToken({ name: "Integer", pattern: /0|[1-9]\d*/ });
const allTokens = [Integer];
const lexer = new Lexer(allTokens);
class Parser extends CstParser {
constructor() {
super(allTokens);
this.performSelfAnalysis();
}
public expr = this.RULE("expr", () => {
this.SUBRULE(this.literal_list);
});
private literal_list = this.RULE("literal_list", () => {
this.AT_LEAST_ONE(this.literal);
});
private literal = this.RULE("literal", () => {
this.CONSUME(Integer);
});
}
const parserInstance = new Parser();
const BaseVisitor = parserInstance.getBaseCstVisitorConstructor();
type AstNode = {
type: "literal";
value: string;
};
class Visitor extends BaseVisitor {
constructor() {
super();
this.validateVisitor();
}
expr(ctx: { literal_list: CstNode[] }): AstNode[] {
console.log(ctx);
return this.visit(ctx.literal_list);
}
literal_list(ctx: { literal_list: CstNode[] }): AstNode[] {
return ctx.literal_list.map((literal) => this.visit(literal));
}
literal(ctx: { Integer: IToken[] }): AstNode {
return {
type: "literal",
value: ctx.Integer[0].image,
};
}
}
const visitor = new Visitor();
function parseExpr(inputText: string) {
const lexResult = lexer.tokenize(inputText);
parserInstance.input = lexResult.tokens;
const cst = parserInstance.expr();
if (parserInstance.errors.length > 0) {
throw Error(parserInstance.errors[0].message);
}
return visitor.visit(cst);
}
test("expr", () => {
expect(() => parseExpr("1")).not.toThrow();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment