diff --git a/compiler/parser.ts b/compiler/parser.ts index f8b110f..a3b3ab1 100644 --- a/compiler/parser.ts +++ b/compiler/parser.ts @@ -87,7 +87,7 @@ export class Parser { } private parseExpr(): Expr { - return this.parsePrefix(); + return this.parseBinary(); } private parseBlock(): Expr { @@ -361,6 +361,114 @@ export class Parser { return this.expr({ type: "if", cond, truthy, falsy }, pos); } + private parseBinary(): Expr { + return this.parseOr(); + } + + private parseOr(): Expr { + const pos = this.pos(); + let left = this.parseAnd(); + while (true) { + if (this.test("or")) { + left = this.parBinTail(left, pos, this.parseAnd, "or"); + } else { + break; + } + } + return left; + } + + private parseAnd(): Expr { + const pos = this.pos(); + let left = this.parseEquality(); + while (true) { + if (this.test("and")) { + left = this.parBinTail(left, pos, this.parseEquality, "and"); + } else { + break; + } + } + return left; + } + + private parseEquality(): Expr { + const pos = this.pos(); + const left = this.parseComparison(); + if (this.test("==")) { + return this.parBinTail(left, pos, this.parseComparison, "=="); + } + if (this.test("!=")) { + return this.parBinTail(left, pos, this.parseComparison, "!="); + } + return left; + } + + private parseComparison(): Expr { + const pos = this.pos(); + const left = this.parseAddSub(); + if (this.test("<")) { + return this.parBinTail(left, pos, this.parseAddSub, "<"); + } + if (this.test(">")) { + return this.parBinTail(left, pos, this.parseAddSub, ">"); + } + if (this.test("<=")) { + return this.parBinTail(left, pos, this.parseAddSub, "<="); + } + if (this.test(">=")) { + return this.parBinTail(left, pos, this.parseAddSub, ">="); + } + return left; + } + + private parseAddSub(): Expr { + const pos = this.pos(); + let left = this.parseMulDiv(); + while (true) { + if (this.test("+")) { + left = this.parBinTail(left, pos, this.parseMulDiv, "+"); + continue; + } + if (this.test(".")) { + left = this.parBinTail(left, pos, this.parseMulDiv, "-"); + continue; + } + break; + } + return left; + } + + private parseMulDiv(): Expr { + const pos = this.pos(); + let left = this.parsePrefix(); + while (true) { + if (this.test("*")) { + left = this.parBinTail(left, pos, this.parsePrefix, "*"); + continue; + } + if (this.test("/")) { + left = this.parBinTail(left, pos, this.parsePrefix, "/"); + continue; + } + break; + } + return left; + } + + private parBinTail( + left: Expr, + pos: Pos, + parseRight: (this: Parser) => Expr, + binaryType: BinaryType, + ): Expr { + this.step(); + const right = parseRight.call(this); + return this.expr( + { type: "binary", binaryType, left, right }, + pos, + ); + } + private parsePrefix(): Expr { const pos = this.pos(); if (this.test("not")) { @@ -368,40 +476,9 @@ export class Parser { const subject = this.parsePrefix(); return this.expr({ type: "unary", unaryType: "not", subject }, pos); } - for ( - const binaryType of [ - "+", - "*", - "==", - "-", - "/", - "!=", - "<", - ">", - "<=", - ">=", - "or", - "and", - ] - ) { - const subject = this.parseBinary(binaryType as BinaryType, pos); - if (subject !== null) { - return subject; - } - } return this.parsePostfix(); } - private parseBinary(binaryType: BinaryType, pos: Pos): Expr | null { - if (this.test(binaryType)) { - this.step(); - const left = this.parsePrefix(); - const right = this.parsePrefix(); - return this.expr({ type: "binary", binaryType, left, right }, pos); - } - return null; - } - private parsePostfix(): Expr { let subject = this.parseOperand(); while (true) { diff --git a/examples/add_fn.slg b/examples/add_fn.slg index 8382df5..27afd59 100644 --- a/examples/add_fn.slg +++ b/examples/add_fn.slg @@ -8,7 +8,7 @@ fn add(a: int, b: int) -> int { let d = b; { let a = c; - + a d + a + d } } diff --git a/examples/add_int.slg b/examples/add_int.slg index b45070e..223e322 100644 --- a/examples/add_int.slg +++ b/examples/add_int.slg @@ -1,5 +1,5 @@ fn main() -> int { - + 1 2 + 1 + 2 } diff --git a/examples/add_let.slg b/examples/add_let.slg index 41976cc..ef8f4aa 100644 --- a/examples/add_let.slg +++ b/examples/add_let.slg @@ -2,6 +2,6 @@ fn main() -> int { let a = 5; let b = 3; - + a b + a + b } diff --git a/examples/annos.slg b/examples/annos.slg index 569a9dd..3f1bb76 100644 --- a/examples/annos.slg +++ b/examples/annos.slg @@ -1,5 +1,5 @@ fn print(msg: string) #[builtin(print)] { - + "hello" 0 + "hello" + 0 } fn main() { diff --git a/examples/example_1.slg b/examples/example_1.slg index 3cbda50..d987f72 100644 --- a/examples/example_1.slg +++ b/examples/example_1.slg @@ -1,7 +1,7 @@ fn print(msg: string) #[builtin(print)] {} fn sum(a: int, b: int) -> int { - + a b + a + b } fn main() { @@ -11,9 +11,9 @@ fn main() { let b = "world"; - print(+ + + a " " b "!\n"); // -> "Hello world!" + print(a + " " + b + "!\n"); // -> "Hello world!" - if == a b { + if a == b { print("whaaaat\n"); } else { @@ -23,10 +23,10 @@ fn main() { loop { let i = 0; - if >= i 10 { + if i >= 10 { break; } - i = + i 1; + i = i + 1; } } diff --git a/examples/example_2.slg b/examples/example_2.slg index 19ad008..45134ae 100644 --- a/examples/example_2.slg +++ b/examples/example_2.slg @@ -1,16 +1,16 @@ fn add(a: int, b: int) -> int { - + a b + a + b } fn main() -> int { let result = 0; let i = 0; loop { - if >= i 10 { + if i >= 10 { break; } result = add(result, 5); - i = + i 1; + i = i + 1; } result }