if-ELSE!!!!
This commit is contained in:
parent
19c9409ccd
commit
6e0b8f950d
8 changed files with 50 additions and 11 deletions
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -26,7 +26,8 @@ public enum TokenType {
|
|||
IDENTIFIER,
|
||||
// the rest
|
||||
WHITESPACE,
|
||||
IF;
|
||||
IF,
|
||||
ELSE;
|
||||
|
||||
public boolean isBinaryOperator() {
|
||||
return switch (this) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue