if-ELSE!!!!

This commit is contained in:
Manuel Friedli 2024-03-24 04:30:43 +01:00
parent 19c9409ccd
commit 6e0b8f950d
Signed by: manuel
GPG key ID: 41D08ABA75634DA1
8 changed files with 50 additions and 11 deletions

View file

@ -1,4 +1,4 @@
package ch.fritteli.gombaila.domain.common; 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 {
} }

View file

@ -2,6 +2,5 @@ package ch.fritteli.gombaila.domain.common;
import org.jetbrains.annotations.NotNull; 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 {
} }

View file

@ -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 {
}

View file

@ -26,7 +26,8 @@ public enum TokenType {
IDENTIFIER, IDENTIFIER,
// the rest // the rest
WHITESPACE, WHITESPACE,
IF; IF,
ELSE;
public boolean isBinaryOperator() { public boolean isBinaryOperator() {
return switch (this) { return switch (this) {

View file

@ -4,6 +4,7 @@ import ch.fritteli.gombaila.domain.common.NodeStmt;
import ch.fritteli.gombaila.domain.common.NodeStmtAssign; import ch.fritteli.gombaila.domain.common.NodeStmtAssign;
import ch.fritteli.gombaila.domain.common.NodeStmtExit; import ch.fritteli.gombaila.domain.common.NodeStmtExit;
import ch.fritteli.gombaila.domain.common.NodeStmtIf; 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.NodeStmtLet;
import ch.fritteli.gombaila.domain.common.NodeStmtPrint; import ch.fritteli.gombaila.domain.common.NodeStmtPrint;
import ch.fritteli.gombaila.domain.common.NodeStmtScope; import ch.fritteli.gombaila.domain.common.NodeStmtScope;
@ -27,6 +28,7 @@ final class StmtVisitor {
case final NodeStmtPrint stmtPrint -> visit(stmtPrint); case final NodeStmtPrint stmtPrint -> visit(stmtPrint);
case final NodeStmtScope stmtScope -> visit(stmtScope); case final NodeStmtScope stmtScope -> visit(stmtScope);
case final NodeStmtIf stmtIf -> visit(stmtIf); 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), "skip to %s if condition is not met".formatted(label),
"jz", label "jz", label
); );
this.visit(stmt.scope()); this.visit(stmt.ifScope());
this.generator.printer.label(label); 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() { private String createNextLabel() {

View file

@ -80,6 +80,7 @@ public class Lexer {
case "let" -> this.appendToken(new Token(TokenType.LET, line, column)); case "let" -> this.appendToken(new Token(TokenType.LET, line, column));
case "print" -> this.appendToken(new Token(TokenType.PRINT, line, column)); case "print" -> this.appendToken(new Token(TokenType.PRINT, line, column));
case "if" -> this.appendToken(new Token(TokenType.IF, 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 -> case final String value ->
this.appendToken(new Token(TokenType.IDENTIFIER, Option.of(value), line, column)); this.appendToken(new Token(TokenType.IDENTIFIER, Option.of(value), line, column));
} }

View file

@ -15,6 +15,7 @@ import ch.fritteli.gombaila.domain.common.NodeStmt;
import ch.fritteli.gombaila.domain.common.NodeStmtAssign; import ch.fritteli.gombaila.domain.common.NodeStmtAssign;
import ch.fritteli.gombaila.domain.common.NodeStmtExit; import ch.fritteli.gombaila.domain.common.NodeStmtExit;
import ch.fritteli.gombaila.domain.common.NodeStmtIf; 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.NodeStmtLet;
import ch.fritteli.gombaila.domain.common.NodeStmtPrint; import ch.fritteli.gombaila.domain.common.NodeStmtPrint;
import ch.fritteli.gombaila.domain.common.NodeStmtScope; import ch.fritteli.gombaila.domain.common.NodeStmtScope;
@ -65,9 +66,14 @@ public class Parser {
this.assertAndConsumeNextTokenType(TokenType.OPEN_PAREN); this.assertAndConsumeNextTokenType(TokenType.OPEN_PAREN);
final NodeExpr expr = this.parseExpr(1); final NodeExpr expr = this.parseExpr(1);
this.assertAndConsumeNextTokenType(TokenType.CLOSE_PAREN); 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. // 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)) { } else if (this.checkNextTokenType(TokenType.IDENTIFIER)) {
result = this.parseStmtAssign(); result = this.parseStmtAssign();
} else { } else {

View file

@ -1,5 +1,7 @@
let x = (10 - 2 * 3) / 2; let x = 1;
if (x-2) { if (x) {
exit (69); x = 99;
} else {
x = 12;
} }
exit(1); exit(x);