[jlox] Add branching
This commit is contained in:
@@ -43,6 +43,15 @@ public class AstPrinter {
|
||||
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
|
||||
public String visitUnaryExpr(Expr.Unary expr) {
|
||||
var op = expr.operator().lexeme();
|
||||
@@ -91,6 +100,14 @@ public class AstPrinter {
|
||||
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
|
||||
public String visitUnaryExpr(Expr.Unary expr) {
|
||||
return expr.operator().lexeme() + expr.right().accept(this);
|
||||
|
||||
@@ -55,6 +55,16 @@ public class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||
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
|
||||
public Void visitPrintStmt(Stmt.Print stmt) {
|
||||
Object value = evaluate(stmt.expression());
|
||||
@@ -121,6 +131,19 @@ public class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||
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
|
||||
public Object visitUnaryExpr(Expr.Unary expr) {
|
||||
var right = evaluate(expr.right());
|
||||
|
||||
@@ -15,6 +15,7 @@ import static xyz.ctsk.lox.TokenType.*;
|
||||
* | statement ;
|
||||
* varDecl → "var" IDENTIFIER ( "=" expression )? ";" ;
|
||||
* statement → exprStmt
|
||||
* | ifStmt
|
||||
* | printStmt
|
||||
* | block ;
|
||||
* block → "{" declaration* "}" ;
|
||||
@@ -23,7 +24,9 @@ import static xyz.ctsk.lox.TokenType.*;
|
||||
* expression → equality ;
|
||||
* expression → assignment ;
|
||||
* assignment → IDENTIFIER "=" assignment
|
||||
* | equality ;
|
||||
* | logic_or ;
|
||||
* logic_or → logic_and ( "or" logic_and )* ;
|
||||
* logic_and → equality ( "and" equality )* ;
|
||||
* equality → comparison ( ( "!=" | "==" ) comparison )* ;
|
||||
* comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ;
|
||||
* term → factor ( ( "-" | "+" ) factor )* ;
|
||||
@@ -76,10 +79,23 @@ public class Parser {
|
||||
|
||||
|
||||
private Stmt statement() {
|
||||
if (match(IF)) return ifStatement();
|
||||
if (match(PRINT)) return printStatement();
|
||||
if (match(LEFT_BRACE)) return new Stmt.Block(blockStatement());
|
||||
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() {
|
||||
Expr value = expression();
|
||||
consume(SEMICOLON, "Expect ';' after value.");
|
||||
@@ -108,7 +124,7 @@ public class Parser {
|
||||
}
|
||||
|
||||
private Expr assignment() {
|
||||
Expr expr = equality();
|
||||
Expr expr = or();
|
||||
|
||||
if (match(EQUAL)) {
|
||||
Token equals = previous();
|
||||
@@ -126,6 +142,30 @@ public class Parser {
|
||||
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() {
|
||||
Expr expr = comparison();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
@Rule(head = "Binary", body = {"Expr left", "Token operator", "Expr right"}),
|
||||
@Rule(head = "Grouping", body = {"Expr expression"}),
|
||||
@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 = "Variable", body = {"Token name"})
|
||||
}),
|
||||
@@ -12,6 +13,7 @@
|
||||
rules = {
|
||||
@Rule(head = "Block", body = {"List<Stmt> statements"}),
|
||||
@Rule(head = "Expression", body = {"Expr expression"}),
|
||||
@Rule(head = "If", body = {"Expr condition", "Stmt thenBranch", "Stmt elseBranch"}),
|
||||
@Rule(head = "Print", body = {"Expr expression"}),
|
||||
@Rule(head = "Var", body = {"Token name", "Expr initializer"})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user