diff --git a/src/com/lox/AstPrinter.java b/src/com/lox/AstPrinter.java index 8b240a1..1774227 100644 --- a/src/com/lox/AstPrinter.java +++ b/src/com/lox/AstPrinter.java @@ -5,6 +5,11 @@ class AstPrinter implements Expr.Visitor { return expr.accept(this); } @Override + public String visitLogicalExpr(Expr.Logical expr){ + //throw exception + return "TODO"; + } + @Override public String visitVariableExpr(Expr.Variable expr){ if(expr.name.literal == null){ return expr.name.lexeme; @@ -73,4 +78,4 @@ class AstPrinter implements Expr.Visitor { System.out.println(new AstPrinter().print(assignExpr)); } -} \ No newline at end of file +} diff --git a/src/com/lox/Expr.java b/src/com/lox/Expr.java index e027379..0c9da99 100644 --- a/src/com/lox/Expr.java +++ b/src/com/lox/Expr.java @@ -8,6 +8,7 @@ abstract class Expr { R visitBinaryExpr(Binary expr); R visitGroupingExpr(Grouping expr); R visitLiteralExpr(Literal expr); + R visitLogicalExpr(Logical expr); R visitUnaryExpr(Unary expr); R visitVariableExpr(Variable expr); } @@ -65,6 +66,22 @@ abstract class Expr { final Object value; } + static class Logical extends Expr { + Logical(Expr left, Token operator, Expr right) { + this.left = left; + this.operator = operator; + this.right = right; + } + + @Override + R accept(Visitor visitor) { + return visitor.visitLogicalExpr(this); + } + + final Expr left; + final Token operator; + final Expr right; + } static class Unary extends Expr { Unary(Token operator, Expr right) { this.operator = operator; diff --git a/src/com/lox/Interpreter.java b/src/com/lox/Interpreter.java index e942527..42f2e04 100644 --- a/src/com/lox/Interpreter.java +++ b/src/com/lox/Interpreter.java @@ -5,10 +5,21 @@ import java.util.List; class Interpreter implements Expr.Visitor,Stmt.Visitor { private Environment environment = new Environment(); @Override - public Object visitLiteralExpr(Expr.Literal expr) { + public Object visitLiteralExpr(Expr.Literal expr){ return expr.value; } @Override + public Object visitLogicalExpr(Expr.Logical expr) { + Object left = evaluate(expr.left); + if(expr.operator.type == TokenType.OR){ + if(isTruthy(left)) return left; + } + else { + if(!isTruthy(left)) return left; + } + return evaluate(expr.right); + } + @Override public Object visitUnaryExpr(Expr.Unary expr) { Object right = evaluate(expr.right); @@ -93,6 +104,16 @@ class Interpreter implements Expr.Visitor,Stmt.Visitor { return null; } @Override + public Void visitIfStmt(Stmt.If stmt){ + if(isTruthy(evaluate(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); System.out.println(stringify(value)); @@ -109,6 +130,13 @@ class Interpreter implements Expr.Visitor,Stmt.Visitor { return null; } @Override + public Void visitWhileStmt(Stmt.While stmt){ + while(isTruthy(evaluate(stmt.condition))){ + execute(stmt.body); + } + return null; + } + @Override public Object visitAssignExpr(Expr.Assign expr) { Object value = evaluate(expr.value); environment.assign(expr.name, value); @@ -174,4 +202,4 @@ class Interpreter implements Expr.Visitor,Stmt.Visitor { return object.toString(); } -} \ No newline at end of file +} diff --git a/src/com/lox/Parser.java b/src/com/lox/Parser.java index 1a5b896..c61699c 100644 --- a/src/com/lox/Parser.java +++ b/src/com/lox/Parser.java @@ -2,6 +2,7 @@ package com.lox; import java.util.List; import java.util.ArrayList; +import java.util.Arrays; import static com.lox.TokenType.*; class Parser { @@ -23,7 +24,6 @@ class Parser { private Stmt declaration() { try { if (match(VAR)) return varDeclaration(); - return statement(); } catch (ParseError error) { synchronize(); @@ -35,10 +35,64 @@ class Parser { } private Stmt statement() { + if (match(FOR)) return forStatement(); + if (match(IF)) return ifStatement(); if (match(PRINT)) return printStatement(); + if (match(WHILE)) return whileStatement(); if (match(LEFT_BRACE)) return new Stmt.Block(block()); return expressionStatement(); } + private Stmt forStatement(){ + consume(LEFT_PAREN, "Expect '(' after 'for'"); + + Stmt initializer; + if (match(SEMICOLON)){ + initializer = null; + } + else if(match(VAR)){ + initializer = varDeclaration(); + } + else { + initializer = expressionStatement(); + } + + Expr condition = null; + if (!check(SEMICOLON)){ + condition = expression(); + } + consume(SEMICOLON, "Expect ';' after loop condition"); + Expr increment = null; + if (!check(RIGHT_PAREN)){ + increment = expression(); + } + consume(RIGHT_PAREN, "Expect ')' after for clauses"); + Stmt body = statement(); + if(increment != null){ + body = new Stmt.Block( + Arrays.asList( + body, + new Stmt.Expression(increment) + ) + ); + } + if(condition == null) condition = new Expr.Literal(true); + body = new Stmt.While(condition, body); + if(initializer != null){ + body = new Stmt.Block(Arrays.asList(initializer,body)); + } + return body; + } + private Stmt ifStatement(){ + consume(LEFT_PAREN,"Expect '(' after 'if'."); + Expr condition = expression(); + consume(RIGHT_PAREN, "Expect ')' after if condition."); + Stmt thenBranch = statement(); + Stmt elseBranch = null; + if (match(ELSE)){ + elseBranch = statement(); + } + return new Stmt.If(condition, thenBranch, elseBranch); + } private Stmt printStatement() { Expr value = expression(); consume(SEMICOLON, "Expect ';' after value."); @@ -55,6 +109,13 @@ class Parser { consume(SEMICOLON, "Expect ';' after variable declaration."); return new Stmt.Var(name, initializer); } + private Stmt whileStatement(){ + consume(LEFT_PAREN, "Expect '(' after 'while'."); + Expr condition = expression(); + consume(RIGHT_PAREN, "Expect ')' after condition"); + Stmt body = statement(); + return new Stmt.While(condition, body); + } private Stmt expressionStatement() { Expr expr = expression(); consume(SEMICOLON, "Expect ';' after expression."); @@ -72,7 +133,7 @@ class Parser { } private Expr assignment() { - Expr expr = equality(); + Expr expr = or(); if (match(EQUAL)) { Token equals = previous(); @@ -88,6 +149,27 @@ class Parser { 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 or(){ + Expr expr = and(); + + while (match(OR)){ + Token operator = previous(); + Expr right = and(); + expr = new Expr.Logical(expr, operator, right); + } + + return expr; + } private Expr equality() { Expr expr = comparison(); @@ -222,4 +304,4 @@ class Parser { } } -} \ No newline at end of file +} diff --git a/src/com/lox/Stmt.java b/src/com/lox/Stmt.java index 13fbb85..2162a03 100644 --- a/src/com/lox/Stmt.java +++ b/src/com/lox/Stmt.java @@ -5,9 +5,11 @@ import java.util.List; abstract class Stmt { interface Visitor { R visitBlockStmt(Block stmt); + R visitIfStmt(If stmt); R visitExpressionStmt(Expression stmt); R visitPrintStmt(Print stmt); R visitVarStmt(Var stmt); + R visitWhileStmt(While stmt); } static class Block extends Stmt { Block(List statements) { @@ -21,6 +23,22 @@ abstract class Stmt { final List statements; } + static class If extends Stmt { + If(Expr condition, Stmt thenBranch, Stmt elseBranch) { + this.condition = condition; + this.thenBranch = thenBranch; + this.elseBranch = elseBranch; + } + + @Override + R accept(Visitor visitor) { + return visitor.visitIfStmt(this); + } + + final Expr condition; + final Stmt thenBranch; + final Stmt elseBranch; + } static class Expression extends Stmt { Expression(Expr expression) { this.expression = expression; @@ -59,6 +77,20 @@ abstract class Stmt { final Token name; final Expr initializer; } + static class While extends Stmt { + While(Expr condition, Stmt body) { + this.condition = condition; + this.body = body; + } + + @Override + R accept(Visitor visitor) { + return visitor.visitWhileStmt(this); + } + + final Expr condition; + final Stmt body; + } abstract R accept(Visitor visitor); } diff --git a/src/com/tool/GenerateAst.java b/src/com/tool/GenerateAst.java index 2366743..85298e4 100644 --- a/src/com/tool/GenerateAst.java +++ b/src/com/tool/GenerateAst.java @@ -17,14 +17,18 @@ public class GenerateAst { "Binary : Expr left, Token operator, Expr right", "Grouping : Expr expression", "Literal : Object value", + "Logical : Expr left, Token operator, Expr right", "Unary : Token operator, Expr right", "Variable : Token name" )); defineAst(outputDir, "Stmt", Arrays.asList( "Block : List statements", + "If : Expr condition, Stmt thenBranch," + + " Stmt elseBranch", "Expression : Expr expression", "Print : Expr expression", - "Var : Token name, Expr initializer" + "Var : Token name, Expr initializer", + "While : Expr condition, Stmt body" )); } private static void defineAst( @@ -103,4 +107,4 @@ public class GenerateAst { writer.println(" }"); } -} \ No newline at end of file +} diff --git a/tests/for_tests.lox b/tests/for_tests.lox new file mode 100644 index 0000000..8e80a15 --- /dev/null +++ b/tests/for_tests.lox @@ -0,0 +1,8 @@ +var a = 0; +var temp; + +for(var b = 1;a < 10000;b = temp + b){ + print a; + temp = a; + a = b; +}