From e65f4575301cdc13737c2b98560eebd671b0b60d Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Sat, 14 Sep 2024 01:15:42 -0500 Subject: [PATCH] fix ident problem --- src/main.ts | 12 +++++++++++ main.ts => src/parser.ts | 45 ++++++++++++++++++++-------------------- test/parser.test.ts | 8 +++++++ 3 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 src/main.ts rename main.ts => src/parser.ts (82%) create mode 100644 test/parser.test.ts diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..4c678c8 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,12 @@ +import { parseProgram } from "./parser"; + + +// Main +async function main() { + const filename = Bun.argv[2]; + const contents = await Bun.file(filename).text() + + const programAst = parseProgram(contents); +} + +main(); \ No newline at end of file diff --git a/main.ts b/src/parser.ts similarity index 82% rename from main.ts rename to src/parser.ts index b883a31..c7451a9 100644 --- a/main.ts +++ b/src/parser.ts @@ -33,13 +33,22 @@ const alt = (...parsers) => (i: string) => { return res; }; -const _: Parser = re(/\s*/) // whitespace +// whitespace +const __: Parser = re(/\s+/) +const _: Parser = re(/\s*/) // Grammar const ident: Parser = re(/(\_[A-Za-z0-9_]+)|([A-Za-z][A-Za-z0-9_]*)/); +const kwd = (s: string) => (i: string) => { + const res = ident(i) + if (res.status === "err") return wrapErr(`expected ${s}`, res) + if (s !== res.value) return err(`expected ${s}`) + return res +} + const ty: Parser = alt( - re(/uint/), re(/int/), re(/ptr/), - re(/str/), ident, + kwd("uint"), kwd("int"), kwd("ptr"), + kwd("str"), ident, ) const exprL: Parser = alt( @@ -54,17 +63,17 @@ const expr2: Parser = alt( const expr1: Parser = alt( map(seq(expr2, _, re(/==/), _, expr2), ([left,,,,right]) => ({expr: "==", left, right})), expr2) -const expr: Parser = expr1 +export const expr: Parser = expr1 -const top: Parser = alt( - map(seq(re(/extern/), _, ident), (([, name]) => ({type: "extern", name}))), - seq(re(/struct/), _, ident, _, re(/:/)), - map(seq(re(/fn/), _, ident, _, re(/:/)), (([,, name]) => ({type: "func", name}))), +export const top: Parser = alt( + map(seq(kwd("extern"), _, ident), (([, name]) => ({type: "extern", name}))), + seq(kwd("struct"), _, ident, _, re(/:/)), + map(seq(kwd("fn"), _, ident, _, re(/:/)), (([,, name]) => ({type: "func", name}))), ) -const stmt: Parser = alt( - map(seq(re(/let/), _, ident, _, re(/=/), _, (i) => expr(i)), +export const stmt: Parser = alt( + map(seq(kwd("let"), _, ident, _, re(/=/), _, (i) => expr(i)), ([,, name,,,, value]) => ({stmt: "let",name, value})), - map(seq(re(/if/), _, (i) => expr(i), _, re(/:/)), ([,, cond]) => ({stmt: "if", cond})), + map(seq(kwd("if"), _, (i) => expr(i), _, re(/:/)), ([,, cond]) => ({stmt: "if", cond})), map((i) => expr(i), (expr) => ({stmt:"expr", expr})), ) @@ -75,7 +84,7 @@ interface Program { functions: object[] } -function parseProgram(input: string): Program { +export function parseProgram(input: string): Program { let currentFunc: string | null = null; let indentStack = [0]; let expectIndent = false; @@ -124,14 +133,4 @@ function parseProgram(input: string): Program { } } -// Codegen - -// Main -async function main() { - const filename = Bun.argv[2]; - const contents = await Bun.file(filename).text() - - const programAst = parseProgram(contents); -} - -main(); \ No newline at end of file +// Codegen \ No newline at end of file diff --git a/test/parser.test.ts b/test/parser.test.ts new file mode 100644 index 0000000..28b6901 --- /dev/null +++ b/test/parser.test.ts @@ -0,0 +1,8 @@ +import {test,expect} from "bun:test" +import { stmt } from "../src/parser" + +test("ifx", () => expect(stmt("ifx")).toMatchObject({status:"ok", value: {expr: {}}, remain: ""})) +test("ifx:", () => expect(stmt("ifx:")).toMatchObject({status:"ok", value: {expr: {}}, remain: ":"})) +test("if x:", () => expect(stmt("if x:")).toMatchObject({status:"ok", value: {stmt: "if"}, remain: ""})) +test("if(x):", () => expect(stmt("if(x):")).toMatchObject({status:"ok", value: {stmt: "if"}, remain: ""})) +test("let let = let", () => expect(stmt("let let = let")).toMatchObject({status:"ok", value: {stmt: "let"}, remain: ""})) \ No newline at end of file