[jlox] Add branching

This commit is contained in:
ctsk
2022-09-10 11:08:21 +02:00
parent dd09bb748f
commit 5327b3746a
4 changed files with 84 additions and 2 deletions

View File

@@ -43,6 +43,15 @@ public class AstPrinter {
return expr.value().toString(); return expr.value().toString();
} }
@Override
public String visitLogicalExpr(Expr.Logical expr) {
var left = expr.left().accept(this);
var op = expr.operator().lexeme();
var right = expr.right().accept(this);
return reverse ? wrap(left, right, op) : wrap(op, left, right);
}
@Override @Override
public String visitUnaryExpr(Expr.Unary expr) { public String visitUnaryExpr(Expr.Unary expr) {
var op = expr.operator().lexeme(); var op = expr.operator().lexeme();
@@ -91,6 +100,14 @@ public class AstPrinter {
return Interpreter.stringify(expr.value()); return Interpreter.stringify(expr.value());
} }
@Override
public String visitLogicalExpr(Expr.Logical expr) {
return String.join(" ",
expr.left().accept(this),
expr.operator().lexeme(),
expr.right().accept(this));
}
@Override @Override
public String visitUnaryExpr(Expr.Unary expr) { public String visitUnaryExpr(Expr.Unary expr) {
return expr.operator().lexeme() + expr.right().accept(this); return expr.operator().lexeme() + expr.right().accept(this);

View File

@@ -55,6 +55,16 @@ public class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
return null; return null;
} }
@Override
public Void visitIfStmt(Stmt.If stmt) {
if (isTruthy(stmt.condition())) {
execute(stmt.thenBranch());
} else if (stmt.elseBranch() != null){
execute(stmt.elseBranch());
}
return null;
}
@Override @Override
public Void visitPrintStmt(Stmt.Print stmt) { public Void visitPrintStmt(Stmt.Print stmt) {
Object value = evaluate(stmt.expression()); Object value = evaluate(stmt.expression());
@@ -121,6 +131,19 @@ public class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
return expr.value(); return expr.value();
} }
@Override
public Object visitLogicalExpr(Expr.Logical expr) {
var leftVal = evaluate(expr.left());
if (expr.operator().type() == TokenType.OR) {
if (isTruthy(leftVal)) return leftVal;
} else {
if (!isTruthy(leftVal)) return leftVal;
}
return evaluate(expr.right());
}
@Override @Override
public Object visitUnaryExpr(Expr.Unary expr) { public Object visitUnaryExpr(Expr.Unary expr) {
var right = evaluate(expr.right()); var right = evaluate(expr.right());

View File

@@ -15,6 +15,7 @@ import static xyz.ctsk.lox.TokenType.*;
* | statement ; * | statement ;
* varDecl → "var" IDENTIFIER ( "=" expression )? ";" ; * varDecl → "var" IDENTIFIER ( "=" expression )? ";" ;
* statement → exprStmt * statement → exprStmt
* | ifStmt
* | printStmt * | printStmt
* | block ; * | block ;
* block → "{" declaration* "}" ; * block → "{" declaration* "}" ;
@@ -23,7 +24,9 @@ import static xyz.ctsk.lox.TokenType.*;
* expression → equality ; * expression → equality ;
* expression → assignment ; * expression → assignment ;
* assignment → IDENTIFIER "=" assignment * assignment → IDENTIFIER "=" assignment
* | equality ; * | logic_or ;
* logic_or → logic_and ( "or" logic_and )* ;
* logic_and → equality ( "and" equality )* ;
* equality → comparison ( ( "!=" | "==" ) comparison )* ; * equality → comparison ( ( "!=" | "==" ) comparison )* ;
* comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; * comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
* term → factor ( ( "-" | "+" ) factor )* ; * term → factor ( ( "-" | "+" ) factor )* ;
@@ -76,10 +79,23 @@ public class Parser {
private Stmt statement() { private Stmt statement() {
if (match(IF)) return ifStatement();
if (match(PRINT)) return printStatement(); if (match(PRINT)) return printStatement();
if (match(LEFT_BRACE)) return new Stmt.Block(blockStatement()); if (match(LEFT_BRACE)) return new Stmt.Block(blockStatement());
return expressionStatement(); return expressionStatement();
} }
private Stmt ifStatement() {
consume(LEFT_PAREN, "Expect '(' after 'if'.");
Expr condition = expression();
consume(RIGHT_PAREN, "Expect ')' after condition.");
Stmt thenBranch = statement();
Stmt elseBranch = match(ELSE) ? statement() : null;
return new Stmt.If(condition, thenBranch, elseBranch);
}
private Stmt printStatement() { private Stmt printStatement() {
Expr value = expression(); Expr value = expression();
consume(SEMICOLON, "Expect ';' after value."); consume(SEMICOLON, "Expect ';' after value.");
@@ -108,7 +124,7 @@ public class Parser {
} }
private Expr assignment() { private Expr assignment() {
Expr expr = equality(); Expr expr = or();
if (match(EQUAL)) { if (match(EQUAL)) {
Token equals = previous(); Token equals = previous();
@@ -126,6 +142,30 @@ public class Parser {
return expr; return expr;
} }
private Expr or() {
Expr expr = and();
while (match(OR)) {
Token operator = previous();
Expr right = and();
expr = new Expr.Logical(expr, operator, right);
}
return expr;
}
private Expr and() {
Expr expr = equality();
while (match(AND)) {
Token operator = previous();
Expr right = equality();
expr = new Expr.Logical(expr, operator, right);
}
return expr;
}
private Expr equality() { private Expr equality() {
Expr expr = comparison(); Expr expr = comparison();

View File

@@ -5,6 +5,7 @@
@Rule(head = "Binary", body = {"Expr left", "Token operator", "Expr right"}), @Rule(head = "Binary", body = {"Expr left", "Token operator", "Expr right"}),
@Rule(head = "Grouping", body = {"Expr expression"}), @Rule(head = "Grouping", body = {"Expr expression"}),
@Rule(head = "Literal", body = {"Object value"}), @Rule(head = "Literal", body = {"Object value"}),
@Rule(head = "Logical", body = {"Expr left", "Token operator", "Expr right"}),
@Rule(head = "Unary", body = {"Token operator", "Expr right"}), @Rule(head = "Unary", body = {"Token operator", "Expr right"}),
@Rule(head = "Variable", body = {"Token name"}) @Rule(head = "Variable", body = {"Token name"})
}), }),
@@ -12,6 +13,7 @@
rules = { rules = {
@Rule(head = "Block", body = {"List<Stmt> statements"}), @Rule(head = "Block", body = {"List<Stmt> statements"}),
@Rule(head = "Expression", body = {"Expr expression"}), @Rule(head = "Expression", body = {"Expr expression"}),
@Rule(head = "If", body = {"Expr condition", "Stmt thenBranch", "Stmt elseBranch"}),
@Rule(head = "Print", body = {"Expr expression"}), @Rule(head = "Print", body = {"Expr expression"}),
@Rule(head = "Var", body = {"Token name", "Expr initializer"}) @Rule(head = "Var", body = {"Token name", "Expr initializer"})
}) })