summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2020-10-28 22:56:15 -0700
committerGravatar Tom Willemse2020-10-28 22:56:15 -0700
commit2e15e8bab840b6d13d1463709e3125bb2910dbab (patch)
tree41e805a0726990c175be46763b0bb029f7608856
parent5fcfc5a01582c6159593eaaf23ec0109d1230130 (diff)
downloadcrafting-interpreters-2e15e8bab840b6d13d1463709e3125bb2910dbab.tar.gz
crafting-interpreters-2e15e8bab840b6d13d1463709e3125bb2910dbab.zip
Add GenerateAst and AstPrinter
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/com/craftinginterpreters/lox/AstPrinter.java53
-rw-r--r--src/com/craftinginterpreters/tool/GenerateAst.java88
3 files changed, 146 insertions, 2 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f664d96..cbd1efd 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -9,7 +9,10 @@ add_jar(Lox
com/craftinginterpreters/lox/Lox.java
com/craftinginterpreters/lox/TokenType.java
com/craftinginterpreters/lox/Token.java
+ com/craftinginterpreters/lox/Expr.java
+ com/craftinginterpreters/lox/AstPrinter.java
ENTRY_POINT com/craftinginterpreters/lox/Lox)
-get_target_property(_jarFile Lox JAR_FILE)
-get_target_property(_classDir Lox CLASSDIR)
+add_jar(GenerateAst
+ com/craftinginterpreters/tool/GenerateAst.java
+ ENTRY_POINT com/craftinginterpreters/tool/GenerateAst)
diff --git a/src/com/craftinginterpreters/lox/AstPrinter.java b/src/com/craftinginterpreters/lox/AstPrinter.java
new file mode 100644
index 0000000..cb494f0
--- /dev/null
+++ b/src/com/craftinginterpreters/lox/AstPrinter.java
@@ -0,0 +1,53 @@
+package com.craftinginterpreters.lox;
+
+/**
+ * AstPrinter
+ */
+class AstPrinter implements Expr.Visitor<String> {
+ 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(" ");
+ builder.append(expr.accept(this));
+ }
+ builder.append(")");
+
+ return builder.toString();
+ }
+
+ public static void main(String[] args) {
+ Expr expression = new Expr.Binary(
+ new Expr.Unary(new Token(TokenType.MINUS, "-", null, 1), new Expr.Literal(123)),
+ new Token(TokenType.STAR, "*", null, 1), new Expr.Grouping(new Expr.Literal(45.67)));
+
+ System.out.println(new AstPrinter().print(expression));
+ }
+}
diff --git a/src/com/craftinginterpreters/tool/GenerateAst.java b/src/com/craftinginterpreters/tool/GenerateAst.java
new file mode 100644
index 0000000..5e79d2f
--- /dev/null
+++ b/src/com/craftinginterpreters/tool/GenerateAst.java
@@ -0,0 +1,88 @@
+package com.craftinginterpreters.tool;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.List;
+
+public class GenerateAst {
+ public static void main(String[] args) throws IOException {
+ if (args.length != 1) {
+ System.err.println("Usage: generate_ast <output directory>");
+ System.exit(64);
+ }
+
+ String outputDir = args[0];
+
+ defineAst(outputDir, "Expr", Arrays.asList("Binary : Expr left, Token operator, Expr right",
+ "Grouping : Expr expression", "Literal : Object value", "Unary : Token operator, Expr right"));
+ }
+
+ private static void defineAst(String outputDir, String baseName, List<String> types) throws IOException {
+ String path = outputDir + "/" + baseName + ".java";
+ PrintWriter writer = new PrintWriter(path);
+
+ writer.println("package com.craftinginterpreters.lox;");
+ writer.println();
+ writer.println("import java.util.List;");
+ 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);
+ }
+
+ // The base accept() method
+ writer.println();
+ writer.println(" abstract <R> R accept(Visitor<R> visitor);");
+
+ writer.println("}");
+ writer.close();
+ }
+
+ private static void defineVisitor(PrintWriter writer, String baseName, List<String> types) {
+ writer.println(" interface Visitor<R> {");
+
+ for (String type : types) {
+ String typeName = type.split(":")[0].trim();
+ writer.println(" R visit" + typeName + baseName + "(" + typeName + " " + baseName.toLowerCase() + ");");
+ }
+
+ writer.println(" }");
+ }
+
+ private static void defineType(PrintWriter writer, String baseName, String className, String fieldList) {
+ writer.println(" static class " + className + " extends " + baseName + " {");
+
+ // Constructor
+ writer.println(" " + className + "(" + fieldList + ") {");
+
+ // Store parameters in fields.
+ String[] fields = fieldList.split(", ");
+ for (String field : fields) {
+ String name = field.split(" ")[1];
+ writer.println(" this." + name + " = " + name + ";");
+ }
+
+ writer.println(" }");
+
+ // Visitor pattern.
+ writer.println();
+ writer.println(" @Override");
+ writer.println(" <R> R accept(Visitor<R> visitor) {");
+ writer.println(" return visitor.visit" + className + baseName + "(this);");
+ writer.println(" }");
+
+ // Fields
+ writer.println();
+ for (String field : fields) {
+ writer.println(" final " + field + ";");
+ }
+
+ writer.println(" }");
+ }
+}