diff --git a/src/lox/ASTPrinter.java b/src/lox/ASTPrinter.java new file mode 100644 index 0000000..9ea4b64 --- /dev/null +++ b/src/lox/ASTPrinter.java @@ -0,0 +1,42 @@ +package lox; + +class ASTPrinter implements Expr.Visitor { + String print(Expr expr) { + return expr.accept(this); + } + + @Override + public String visitBinaryExpr(Expr.Binary expr) { + return parenthesize(expr.operator.lexeme, expr.left, expr.right); + } + + @Override + public String visitGroupingExpr(Expr.Grouping expr) { + return parenthesize("group", expr.expression); + } + + @Override + public String visitLiteralExpr(Expr.Literal expr) { + if (expr.value == null) { + return "nil"; + } + return expr.value.toString(); + } + + @Override + public String visitUnaryExpr(Expr.Unary expr) { + return parenthesize(expr.operator.lexeme, expr.right); + } + + private String parenthesize(String name, Expr... exprs) { + StringBuilder builder = new StringBuilder(); + + builder.append("(").append(name); + for (Expr expr : exprs) { + builder.append(" ").append(expr.accept(this)); + } + builder.append(")"); + + return builder.toString(); + } +} diff --git a/src/lox/Expr.java b/src/lox/Expr.java index 7c91ca4..5337c91 100644 --- a/src/lox/Expr.java +++ b/src/lox/Expr.java @@ -1,6 +1,15 @@ package lox; +import java.util.List; + abstract class Expr { + interface Visitor { + R visitBinaryExpr(Binary expr); + R visitGroupingExpr(Grouping expr); + R visitLiteralExpr(Literal expr); + R visitUnaryExpr(Unary expr); + } + static class Binary extends Expr { Binary(Expr left, Token operator, Expr right) { this.left = left; @@ -8,6 +17,11 @@ abstract class Expr { this.right = right; } + @Override + R accept(Visitor visitor) { + return visitor.visitBinaryExpr(this); + } + final Expr left; final Token operator; final Expr right; @@ -18,6 +32,11 @@ abstract class Expr { this.expression = expression; } + @Override + R accept(Visitor visitor) { + return visitor.visitGroupingExpr(this); + } + final Expr expression; } @@ -26,6 +45,11 @@ abstract class Expr { this.value = value; } + @Override + R accept(Visitor visitor) { + return visitor.visitLiteralExpr(this); + } + final Object value; } @@ -35,7 +59,14 @@ abstract class Expr { this.right = right; } + @Override + R accept(Visitor visitor) { + return visitor.visitUnaryExpr(this); + } + final Token operator; final Expr right; } + + abstract R accept(Visitor visitor); } diff --git a/src/tool/GenerateAST.java b/src/tool/GenerateAST.java index ebfcbc8..b887eb8 100644 --- a/src/tool/GenerateAST.java +++ b/src/tool/GenerateAST.java @@ -34,21 +34,45 @@ public class GenerateAST { writer.println(); writer.println("abstract class " + baseName + " {"); + defineVisitor(writer, baseName, types); + for (String type : types) { String className = type.split(":")[0].trim(); String fields = type.split(":")[1].trim(); defineType(writer, baseName, className, fields); } + writer.println(" abstract R accept(Visitor visitor);"); + writer.println("}"); writer.close(); } + private static void defineVisitor(PrintWriter writer, String baseName, List types) { + writer.println(" interface Visitor {"); + + for (String type : types) { + String typeName = type.split(":")[0].trim(); + writer.println( + " R visit" + + typeName + + baseName + + "(" + + typeName + + " " + + baseName.toLowerCase() + + ");"); + } + + writer.println(" }"); + writer.println(); + } + private static void defineType( PrintWriter writer, String baseName, String className, String fieldList) { writer.println(" static class " + className + " extends " + baseName + " {"); - writer.println(" " + className + "(" + fieldList + ") { "); + writer.println(" " + className + "(" + fieldList + ") {"); String[] fields = fieldList.split(", "); for (String field : fields) { @@ -59,6 +83,12 @@ public class GenerateAST { writer.println(" }"); writer.println(); + writer.println(" @Override"); + writer.println(" R accept(Visitor visitor) {"); + writer.println(" return visitor.visit" + className + baseName + "(this);"); + writer.println(" }"); + writer.println(); + for (String field : fields) { writer.println(" final " + field + ";"); }