From 6e0b8f950d1b49b553f298efcb3198c36e908d0c Mon Sep 17 00:00:00 2001 From: Manuel Friedli Date: Sun, 24 Mar 2024 04:30:43 +0100 Subject: [PATCH] if-ELSE!!!! --- .../gombaila/domain/common/NodeStmt.java | 2 +- .../gombaila/domain/common/NodeStmtIf.java | 3 +-- .../domain/common/NodeStmtIfElse.java | 7 ++++++ .../gombaila/domain/common/TokenType.java | 3 ++- .../domain/generator/StmtVisitor.java | 25 ++++++++++++++++++- .../fritteli/gombaila/domain/lexer/Lexer.java | 1 + .../gombaila/domain/parser/Parser.java | 10 ++++++-- src/main/resources/gombaila/simple.gb | 10 +++++--- 8 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIfElse.java diff --git a/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmt.java b/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmt.java index 6fdc1db..ba16182 100644 --- a/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmt.java +++ b/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmt.java @@ -1,4 +1,4 @@ package ch.fritteli.gombaila.domain.common; -public sealed interface NodeStmt extends Node permits NodeStmtAssign, NodeStmtExit, NodeStmtIf, NodeStmtLet, NodeStmtPrint, NodeStmtScope { +public sealed interface NodeStmt extends Node permits NodeStmtAssign, NodeStmtExit, NodeStmtIf, NodeStmtIfElse, NodeStmtLet, NodeStmtPrint, NodeStmtScope { } diff --git a/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIf.java b/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIf.java index 07af22d..2a39145 100644 --- a/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIf.java +++ b/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIf.java @@ -2,6 +2,5 @@ package ch.fritteli.gombaila.domain.common; import org.jetbrains.annotations.NotNull; -public record NodeStmtIf(@NotNull NodeExpr expr, @NotNull NodeStmtScope scope) implements NodeStmt { - +public record NodeStmtIf(@NotNull NodeExpr expr, @NotNull NodeStmtScope ifScope) implements NodeStmt { } diff --git a/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIfElse.java b/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIfElse.java new file mode 100644 index 0000000..b4906f3 --- /dev/null +++ b/src/main/java/ch/fritteli/gombaila/domain/common/NodeStmtIfElse.java @@ -0,0 +1,7 @@ +package ch.fritteli.gombaila.domain.common; + +import org.jetbrains.annotations.NotNull; + +public record NodeStmtIfElse(@NotNull NodeExpr expr, @NotNull NodeStmtScope ifScope, + @NotNull NodeStmtScope elseScope) implements NodeStmt { +} diff --git a/src/main/java/ch/fritteli/gombaila/domain/common/TokenType.java b/src/main/java/ch/fritteli/gombaila/domain/common/TokenType.java index 9e0a82e..1b68f23 100644 --- a/src/main/java/ch/fritteli/gombaila/domain/common/TokenType.java +++ b/src/main/java/ch/fritteli/gombaila/domain/common/TokenType.java @@ -26,7 +26,8 @@ public enum TokenType { IDENTIFIER, // the rest WHITESPACE, - IF; + IF, + ELSE; public boolean isBinaryOperator() { return switch (this) { diff --git a/src/main/java/ch/fritteli/gombaila/domain/generator/StmtVisitor.java b/src/main/java/ch/fritteli/gombaila/domain/generator/StmtVisitor.java index e79b0ed..3571200 100644 --- a/src/main/java/ch/fritteli/gombaila/domain/generator/StmtVisitor.java +++ b/src/main/java/ch/fritteli/gombaila/domain/generator/StmtVisitor.java @@ -4,6 +4,7 @@ import ch.fritteli.gombaila.domain.common.NodeStmt; import ch.fritteli.gombaila.domain.common.NodeStmtAssign; import ch.fritteli.gombaila.domain.common.NodeStmtExit; import ch.fritteli.gombaila.domain.common.NodeStmtIf; +import ch.fritteli.gombaila.domain.common.NodeStmtIfElse; import ch.fritteli.gombaila.domain.common.NodeStmtLet; import ch.fritteli.gombaila.domain.common.NodeStmtPrint; import ch.fritteli.gombaila.domain.common.NodeStmtScope; @@ -27,6 +28,7 @@ final class StmtVisitor { case final NodeStmtPrint stmtPrint -> visit(stmtPrint); case final NodeStmtScope stmtScope -> visit(stmtScope); case final NodeStmtIf stmtIf -> visit(stmtIf); + case final NodeStmtIfElse stmtIfElse -> visit(stmtIfElse); } } @@ -96,9 +98,30 @@ final class StmtVisitor { "skip to %s if condition is not met".formatted(label), "jz", label ); - this.visit(stmt.scope()); + this.visit(stmt.ifScope()); this.generator.printer.label(label); + } + private void visit(@NotNull final NodeStmtIfElse stmt) { + final String afterIfLabel = this.createNextLabel(); + final String afterElseLabel = this.createNextLabel(); + this.generator.generateExpr(stmt.expr()); + this.generator.pop("rax"); + this.generator.printer.commentedLine("test the condition", + "test", "rax, rax"); + this.generator.printer.commentedLine( + "skip to %s (else) if condition is not met".formatted(afterIfLabel), + "jz", afterIfLabel + ); + this.visit(stmt.ifScope()); + this.generator.printer.commentedLine( + "skip to %s to skip the else".formatted(afterElseLabel), + "jmp", + afterElseLabel + ); + this.generator.printer.label(afterIfLabel); + this.visit(stmt.elseScope()); + this.generator.printer.label(afterElseLabel); } private String createNextLabel() { diff --git a/src/main/java/ch/fritteli/gombaila/domain/lexer/Lexer.java b/src/main/java/ch/fritteli/gombaila/domain/lexer/Lexer.java index 579f088..30eb652 100644 --- a/src/main/java/ch/fritteli/gombaila/domain/lexer/Lexer.java +++ b/src/main/java/ch/fritteli/gombaila/domain/lexer/Lexer.java @@ -80,6 +80,7 @@ public class Lexer { case "let" -> this.appendToken(new Token(TokenType.LET, line, column)); case "print" -> this.appendToken(new Token(TokenType.PRINT, line, column)); case "if" -> this.appendToken(new Token(TokenType.IF, line, column)); + case "else" -> this.appendToken(new Token(TokenType.ELSE, line, column)); case final String value -> this.appendToken(new Token(TokenType.IDENTIFIER, Option.of(value), line, column)); } diff --git a/src/main/java/ch/fritteli/gombaila/domain/parser/Parser.java b/src/main/java/ch/fritteli/gombaila/domain/parser/Parser.java index 6e4f3c8..d459b1b 100644 --- a/src/main/java/ch/fritteli/gombaila/domain/parser/Parser.java +++ b/src/main/java/ch/fritteli/gombaila/domain/parser/Parser.java @@ -15,6 +15,7 @@ import ch.fritteli.gombaila.domain.common.NodeStmt; import ch.fritteli.gombaila.domain.common.NodeStmtAssign; import ch.fritteli.gombaila.domain.common.NodeStmtExit; import ch.fritteli.gombaila.domain.common.NodeStmtIf; +import ch.fritteli.gombaila.domain.common.NodeStmtIfElse; import ch.fritteli.gombaila.domain.common.NodeStmtLet; import ch.fritteli.gombaila.domain.common.NodeStmtPrint; import ch.fritteli.gombaila.domain.common.NodeStmtScope; @@ -65,9 +66,14 @@ public class Parser { this.assertAndConsumeNextTokenType(TokenType.OPEN_PAREN); final NodeExpr expr = this.parseExpr(1); this.assertAndConsumeNextTokenType(TokenType.CLOSE_PAREN); - final NodeStmtScope scope = this.parseScope(); + final NodeStmtScope ifScope = this.parseScope(); + // there /could/ be an else, so let's check that + if (this.checkNextTokenTypeConsuming(TokenType.ELSE)) { + final NodeStmtScope elseScope = this.parseScope(); + return new NodeStmtIfElse(expr, ifScope, elseScope); + } // NB: We do NOT expect a SEMI here, so we return directly. - return new NodeStmtIf(expr, scope); + return new NodeStmtIf(expr, ifScope); } else if (this.checkNextTokenType(TokenType.IDENTIFIER)) { result = this.parseStmtAssign(); } else { diff --git a/src/main/resources/gombaila/simple.gb b/src/main/resources/gombaila/simple.gb index a1dc50b..13a65c2 100644 --- a/src/main/resources/gombaila/simple.gb +++ b/src/main/resources/gombaila/simple.gb @@ -1,5 +1,7 @@ -let x = (10 - 2 * 3) / 2; -if (x-2) { - exit (69); +let x = 1; +if (x) { + x = 99; +} else { + x = 12; } -exit(1); +exit(x);