add scopes
This commit is contained in:
		@@ -33,6 +33,11 @@ class ASTPrinter implements Expr.Visitor<String> {
 | 
				
			|||||||
    return expr.name.toString();
 | 
					    return expr.name.toString();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public String visitAssignExpr(Expr.Assign expr) {
 | 
				
			||||||
 | 
					    return expr.name.toString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private String parenthesize(String name, Expr... exprs) {
 | 
					  private String parenthesize(String name, Expr... exprs) {
 | 
				
			||||||
    StringBuilder builder = new StringBuilder();
 | 
					    StringBuilder builder = new StringBuilder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,16 +4,44 @@ import java.util.HashMap;
 | 
				
			|||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Environment {
 | 
					class Environment {
 | 
				
			||||||
 | 
					  final Environment enclosing;
 | 
				
			||||||
  private final Map<String, Object> values = new HashMap<>();
 | 
					  private final Map<String, Object> values = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Environment() {
 | 
				
			||||||
 | 
					    enclosing = null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Environment(Environment enclosing) {
 | 
				
			||||||
 | 
					    this.enclosing = enclosing;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void define(String name, Object value) {
 | 
					  void define(String name, Object value) {
 | 
				
			||||||
    values.put(name, value);
 | 
					    values.put(name, value);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void assign(Token name, Object value) {
 | 
				
			||||||
 | 
					    if (values.containsKey(name.lexeme)) {
 | 
				
			||||||
 | 
					      values.put(name.lexeme, value);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (enclosing != null) {
 | 
				
			||||||
 | 
					      enclosing.assign(name, value);
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'.");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Object get(Token name) {
 | 
					  Object get(Token name) {
 | 
				
			||||||
    if (values.containsKey(name.lexeme)) {
 | 
					    if (values.containsKey(name.lexeme)) {
 | 
				
			||||||
      return values.get(name.lexeme);
 | 
					      return values.get(name.lexeme);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (enclosing != null) {
 | 
				
			||||||
 | 
					      return enclosing.get(name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'.");
 | 
					    throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'.");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,10 @@
 | 
				
			|||||||
package lox;
 | 
					package lox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class Expr {
 | 
					abstract class Expr {
 | 
				
			||||||
  interface Visitor<R> {
 | 
					  interface Visitor<R> {
 | 
				
			||||||
 | 
					    R visitAssignExpr(Assign expr);
 | 
				
			||||||
    R visitBinaryExpr(Binary expr);
 | 
					    R visitBinaryExpr(Binary expr);
 | 
				
			||||||
    R visitGroupingExpr(Grouping expr);
 | 
					    R visitGroupingExpr(Grouping expr);
 | 
				
			||||||
    R visitLiteralExpr(Literal expr);
 | 
					    R visitLiteralExpr(Literal expr);
 | 
				
			||||||
@@ -9,6 +12,21 @@ abstract class Expr {
 | 
				
			|||||||
    R visitVariableExpr(Variable expr);
 | 
					    R visitVariableExpr(Variable expr);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static class Assign extends Expr {
 | 
				
			||||||
 | 
					    Assign(Token name, Expr value) {
 | 
				
			||||||
 | 
					      this.name = name;
 | 
				
			||||||
 | 
					      this.value = value;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    <R> R accept(Visitor<R> visitor) {
 | 
				
			||||||
 | 
					      return visitor.visitAssignExpr(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final Token name;
 | 
				
			||||||
 | 
					    final Expr value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static class Binary extends Expr {
 | 
					  static class Binary extends Expr {
 | 
				
			||||||
    Binary(Expr left, Token operator, Expr right) {
 | 
					    Binary(Expr left, Token operator, Expr right) {
 | 
				
			||||||
      this.left = left;
 | 
					      this.left = left;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,6 +89,13 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 | 
				
			|||||||
    return environment.get(expr.name);
 | 
					    return environment.get(expr.name);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public Object visitAssignExpr(Expr.Assign expr) {
 | 
				
			||||||
 | 
					    Object value = evaluate(expr.value);
 | 
				
			||||||
 | 
					    environment.assign(expr.name, value);
 | 
				
			||||||
 | 
					    return value;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @Override
 | 
					  @Override
 | 
				
			||||||
  public Void visitExpressionStmt(Stmt.Expression stmt) {
 | 
					  public Void visitExpressionStmt(Stmt.Expression stmt) {
 | 
				
			||||||
    evaluate(stmt.expression);
 | 
					    evaluate(stmt.expression);
 | 
				
			||||||
@@ -112,6 +119,12 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 | 
				
			|||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @Override
 | 
				
			||||||
 | 
					  public Void visitBlockStmt(Stmt.Block stmt) {
 | 
				
			||||||
 | 
					    executeBlock(stmt.statements, new Environment(environment));
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private void checkNumberOperand(Token operator, Object operand) {
 | 
					  private void checkNumberOperand(Token operator, Object operand) {
 | 
				
			||||||
    if (operand instanceof Double) {
 | 
					    if (operand instanceof Double) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
@@ -167,4 +180,18 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 | 
				
			|||||||
  private void execute(Stmt stmt) {
 | 
					  private void execute(Stmt stmt) {
 | 
				
			||||||
    stmt.accept(this);
 | 
					    stmt.accept(this);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void executeBlock(List<Stmt> statements, Environment environment) {
 | 
				
			||||||
 | 
					    Environment previous = this.environment;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      this.environment = environment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      for (Stmt statement : statements) {
 | 
				
			||||||
 | 
					        // could also just redesign this to accept an environment field everywhere
 | 
				
			||||||
 | 
					        execute(statement);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } finally {
 | 
				
			||||||
 | 
					      this.environment = previous;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,9 @@ class Parser {
 | 
				
			|||||||
    if (match(PRINT)) {
 | 
					    if (match(PRINT)) {
 | 
				
			||||||
      return printStatement();
 | 
					      return printStatement();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (match(LEFT_BRACE)) {
 | 
				
			||||||
 | 
					      return new Stmt.Block(block());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return expressionStatement();
 | 
					    return expressionStatement();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,8 +68,35 @@ class Parser {
 | 
				
			|||||||
    return new Stmt.Expression(value);
 | 
					    return new Stmt.Expression(value);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private List<Stmt> block() {
 | 
				
			||||||
 | 
					    List<Stmt> statements = new ArrayList<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (!check(RIGHT_BRACE) && !isAtEnd()) {
 | 
				
			||||||
 | 
					      statements.add(declaration());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    consume(RIGHT_BRACE, "Expect '}' after block.");
 | 
				
			||||||
 | 
					    return statements;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private Expr assignment() {
 | 
				
			||||||
 | 
					    Expr expr = equality();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (match(EQUAL)) {
 | 
				
			||||||
 | 
					      Token equals = previous();
 | 
				
			||||||
 | 
					      Expr value = assignment();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (expr instanceof Expr.Variable) {
 | 
				
			||||||
 | 
					        Token name = ((Expr.Variable)expr).name;
 | 
				
			||||||
 | 
					        return new Expr.Assign(name, value);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // does not throw because parsing _can_ continue
 | 
				
			||||||
 | 
					      error(equals, "Invalid assignment target.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return expr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private Expr expression() {
 | 
					  private Expr expression() {
 | 
				
			||||||
    return equality();
 | 
					    return assignment();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private Expr equality() {
 | 
					  private Expr equality() {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,28 @@
 | 
				
			|||||||
package lox;
 | 
					package lox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class Stmt {
 | 
					abstract class Stmt {
 | 
				
			||||||
  interface Visitor<R> {
 | 
					  interface Visitor<R> {
 | 
				
			||||||
 | 
					    R visitBlockStmt(Block stmt);
 | 
				
			||||||
    R visitExpressionStmt(Expression stmt);
 | 
					    R visitExpressionStmt(Expression stmt);
 | 
				
			||||||
    R visitVarStmt(Var stmt);
 | 
					    R visitVarStmt(Var stmt);
 | 
				
			||||||
    R visitPrintStmt(Print stmt);
 | 
					    R visitPrintStmt(Print stmt);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static class Block extends Stmt {
 | 
				
			||||||
 | 
					    Block(List<Stmt> statements) {
 | 
				
			||||||
 | 
					      this.statements = statements;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    <R> R accept(Visitor<R> visitor) {
 | 
				
			||||||
 | 
					      return visitor.visitBlockStmt(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final List<Stmt> statements;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static class Expression extends Stmt {
 | 
					  static class Expression extends Stmt {
 | 
				
			||||||
    Expression(Expr expression) {
 | 
					    Expression(Expr expression) {
 | 
				
			||||||
      this.expression = expression;
 | 
					      this.expression = expression;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
package tool;
 | 
					package tool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.PrintWriter;
 | 
					import java.io.PrintWriter;
 | 
				
			||||||
import java.nio.charset.Charset;
 | 
					import java.nio.charset.Charset;
 | 
				
			||||||
@@ -17,6 +18,7 @@ public class GenerateAST {
 | 
				
			|||||||
        outputDir,
 | 
					        outputDir,
 | 
				
			||||||
        "Expr",
 | 
					        "Expr",
 | 
				
			||||||
        Arrays.asList(
 | 
					        Arrays.asList(
 | 
				
			||||||
 | 
					            "Assign   : Token name, Expr value",
 | 
				
			||||||
            "Binary   : Expr left, Token operator, Expr right",
 | 
					            "Binary   : Expr left, Token operator, Expr right",
 | 
				
			||||||
            "Grouping : Expr expression",
 | 
					            "Grouping : Expr expression",
 | 
				
			||||||
            "Literal  : Object value",
 | 
					            "Literal  : Object value",
 | 
				
			||||||
@@ -27,6 +29,7 @@ public class GenerateAST {
 | 
				
			|||||||
        outputDir,
 | 
					        outputDir,
 | 
				
			||||||
        "Stmt",
 | 
					        "Stmt",
 | 
				
			||||||
        Arrays.asList(
 | 
					        Arrays.asList(
 | 
				
			||||||
 | 
					            "Block      : List<Stmt> statements",
 | 
				
			||||||
            "Expression : Expr expression",
 | 
					            "Expression : Expr expression",
 | 
				
			||||||
            "Var        : Token name, Expr initializer",
 | 
					            "Var        : Token name, Expr initializer",
 | 
				
			||||||
            "Print      : Expr expression"));
 | 
					            "Print      : Expr expression"));
 | 
				
			||||||
@@ -34,13 +37,13 @@ public class GenerateAST {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  private static void defineAST(String outputDir, String baseName, List<String> types)
 | 
					  private static void defineAST(String outputDir, String baseName, List<String> types)
 | 
				
			||||||
      throws IOException {
 | 
					      throws IOException {
 | 
				
			||||||
    String path = outputDir + "/" + baseName + ".java";
 | 
					    String path = outputDir + File.separator + baseName + ".java";
 | 
				
			||||||
    PrintWriter writer = new PrintWriter(path, Charset.defaultCharset());
 | 
					    PrintWriter writer = new PrintWriter(path, Charset.defaultCharset());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    writer.println("package lox;");
 | 
					    writer.println("package lox;");
 | 
				
			||||||
    writer.println();
 | 
					    writer.println();
 | 
				
			||||||
    //    writer.println("import java.util.List;");
 | 
					    writer.println("import java.util.List;");
 | 
				
			||||||
    //    writer.println();
 | 
					    writer.println();
 | 
				
			||||||
    writer.println("abstract class " + baseName + " {");
 | 
					    writer.println("abstract class " + baseName + " {");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    defineVisitor(writer, baseName, types);
 | 
					    defineVisitor(writer, baseName, types);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user