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;
|
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;
|
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,
|
IDENTIFIER,
|
||||||
// the rest
|
// the rest
|
||||||
WHITESPACE,
|
WHITESPACE,
|
||||||
IF;
|
IF,
|
||||||
|
ELSE;
|
||||||
|
|
||||||
public boolean isBinaryOperator() {
|
public boolean isBinaryOperator() {
|
||||||
return switch (this) {
|
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.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() {
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue