add scopes
This commit is contained in:
		@@ -33,6 +33,11 @@ class ASTPrinter implements Expr.Visitor<String> {
 | 
			
		||||
    return expr.name.toString();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public String visitAssignExpr(Expr.Assign expr) {
 | 
			
		||||
    return expr.name.toString();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private String parenthesize(String name, Expr... exprs) {
 | 
			
		||||
    StringBuilder builder = new StringBuilder();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,16 +4,44 @@ import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
class Environment {
 | 
			
		||||
  final Environment enclosing;
 | 
			
		||||
  private final Map<String, Object> values = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
  Environment() {
 | 
			
		||||
    enclosing = null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Environment(Environment enclosing) {
 | 
			
		||||
    this.enclosing = enclosing;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void define(String name, Object 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) {
 | 
			
		||||
    if (values.containsKey(name.lexeme)) {
 | 
			
		||||
      return values.get(name.lexeme);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (enclosing != null) {
 | 
			
		||||
      return enclosing.get(name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    throw new RuntimeError(name, "Undefined variable '" + name.lexeme + "'.");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,10 @@
 | 
			
		||||
package lox;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
abstract class Expr {
 | 
			
		||||
  interface Visitor<R> {
 | 
			
		||||
    R visitAssignExpr(Assign expr);
 | 
			
		||||
    R visitBinaryExpr(Binary expr);
 | 
			
		||||
    R visitGroupingExpr(Grouping expr);
 | 
			
		||||
    R visitLiteralExpr(Literal expr);
 | 
			
		||||
@@ -9,6 +12,21 @@ abstract class 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 {
 | 
			
		||||
    Binary(Expr left, Token operator, Expr right) {
 | 
			
		||||
      this.left = left;
 | 
			
		||||
 
 | 
			
		||||
@@ -89,6 +89,13 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 | 
			
		||||
    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
 | 
			
		||||
  public Void visitExpressionStmt(Stmt.Expression stmt) {
 | 
			
		||||
    evaluate(stmt.expression);
 | 
			
		||||
@@ -112,6 +119,12 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Override
 | 
			
		||||
  public Void visitBlockStmt(Stmt.Block stmt) {
 | 
			
		||||
    executeBlock(stmt.statements, new Environment(environment));
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void checkNumberOperand(Token operator, Object operand) {
 | 
			
		||||
    if (operand instanceof Double) {
 | 
			
		||||
      return;
 | 
			
		||||
@@ -167,4 +180,18 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 | 
			
		||||
  private void execute(Stmt stmt) {
 | 
			
		||||
    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)) {
 | 
			
		||||
      return printStatement();
 | 
			
		||||
    }
 | 
			
		||||
    if (match(LEFT_BRACE)) {
 | 
			
		||||
      return new Stmt.Block(block());
 | 
			
		||||
    }
 | 
			
		||||
    return expressionStatement();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -65,8 +68,35 @@ class Parser {
 | 
			
		||||
    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() {
 | 
			
		||||
    return equality();
 | 
			
		||||
    return assignment();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private Expr equality() {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,28 @@
 | 
			
		||||
package lox;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
abstract class Stmt {
 | 
			
		||||
  interface Visitor<R> {
 | 
			
		||||
    R visitBlockStmt(Block stmt);
 | 
			
		||||
    R visitExpressionStmt(Expression stmt);
 | 
			
		||||
    R visitVarStmt(Var 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 {
 | 
			
		||||
    Expression(Expr expression) {
 | 
			
		||||
      this.expression = expression;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package tool;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.PrintWriter;
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
@@ -17,30 +18,32 @@ public class GenerateAST {
 | 
			
		||||
        outputDir,
 | 
			
		||||
        "Expr",
 | 
			
		||||
        Arrays.asList(
 | 
			
		||||
            "Binary : Expr left, Token operator, Expr right",
 | 
			
		||||
            "Assign   : Token name, Expr value",
 | 
			
		||||
            "Binary   : Expr left, Token operator, Expr right",
 | 
			
		||||
            "Grouping : Expr expression",
 | 
			
		||||
            "Literal : Object value",
 | 
			
		||||
            "Unary : Token operator, Expr right",
 | 
			
		||||
            "Literal  : Object value",
 | 
			
		||||
            "Unary    : Token operator, Expr right",
 | 
			
		||||
            "Variable : Token name"));
 | 
			
		||||
 | 
			
		||||
    defineAST(
 | 
			
		||||
        outputDir,
 | 
			
		||||
        "Stmt",
 | 
			
		||||
        Arrays.asList(
 | 
			
		||||
            "Block      : List<Stmt> statements",
 | 
			
		||||
            "Expression : Expr expression",
 | 
			
		||||
            "Var : Token name, Expr initializer",
 | 
			
		||||
            "Print : Expr expression"));
 | 
			
		||||
            "Var        : Token name, Expr initializer",
 | 
			
		||||
            "Print      : Expr expression"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private static void defineAST(String outputDir, String baseName, List<String> types)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    String path = outputDir + "/" + baseName + ".java";
 | 
			
		||||
    String path = outputDir + File.separator + baseName + ".java";
 | 
			
		||||
    PrintWriter writer = new PrintWriter(path, Charset.defaultCharset());
 | 
			
		||||
 | 
			
		||||
    writer.println("package lox;");
 | 
			
		||||
    writer.println();
 | 
			
		||||
    //    writer.println("import java.util.List;");
 | 
			
		||||
    //    writer.println();
 | 
			
		||||
    writer.println("import java.util.List;");
 | 
			
		||||
    writer.println();
 | 
			
		||||
    writer.println("abstract class " + baseName + " {");
 | 
			
		||||
 | 
			
		||||
    defineVisitor(writer, baseName, types);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user