ソースを参照

Constructors and Initializers

runningwater 2 年 前
コミット
db678ab544

+ 2 - 2
src/main/java/com/craftinginterpreters/lox/Interpreter.java

@@ -220,7 +220,7 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 
     Map<String, LoxFunction> methods = new HashMap<>();
     for (Stmt.Function method : stmt.methods) {
-      LoxFunction function = new LoxFunction(method, environment);
+      LoxFunction function = new LoxFunction(method, environment, method.name.lexeme.equals("init"));
       methods.put(method.name.lexeme, function);
     }
 
@@ -238,7 +238,7 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
 
   @Override
   public Void visitFunctionStmt(Stmt.Function stmt) {
-    LoxFunction function = new LoxFunction(stmt, environment);
+    LoxFunction function = new LoxFunction(stmt, environment, false);
     environment.define(stmt.name.lexeme, function);
     return null;
   }

+ 7 - 2
src/main/java/com/craftinginterpreters/lox/LoxCallable.java

@@ -10,7 +10,12 @@ import java.util.List;
  * @desc
  */
 interface LoxCallable {
-    int arity();
+  /**
+   * 参数个数
+   *
+   * @return int val
+   */
+  int arity();
 
-    Object call(Interpreter interpreter, List<Object> arguments);
+  Object call(Interpreter interpreter, List<Object> arguments);
 }

+ 8 - 1
src/main/java/com/craftinginterpreters/lox/LoxClass.java

@@ -26,12 +26,19 @@ public class LoxClass implements LoxCallable {
 
   @Override
   public int arity() {
-    return 0;
+    LoxFunction initializer = findMethod("init");
+    if (initializer == null) return 0;
+    return initializer.arity();
   }
 
   @Override
   public Object call(Interpreter interpreter, List<Object> arguments) {
     LoxInstance instance = new LoxInstance(this);
+    // 查找初始化方法
+    LoxFunction initializer = findMethod("init");
+    if (initializer != null) {
+      initializer.bind(instance).call(interpreter, arguments);
+    }
     return instance;
   }
 

+ 16 - 8
src/main/java/com/craftinginterpreters/lox/LoxFunction.java

@@ -12,10 +12,12 @@ import java.util.List;
 public class LoxFunction implements LoxCallable {
   private final Stmt.Function declaration;
   private final Environment closure;
+  private final boolean isInitializer;
 
-  public LoxFunction(Stmt.Function declaration, Environment closure) {
+  public LoxFunction(Stmt.Function declaration, Environment closure, boolean isInitializer) {
     this.declaration = declaration;
     this.closure = closure;
+    this.isInitializer = isInitializer;
   }
 
   @Override
@@ -32,8 +34,12 @@ public class LoxFunction implements LoxCallable {
     try {
       interpreter.executeBlock(declaration.body, environment);
     } catch (Return returnVal) {
+      if (isInitializer) return closure.getAt(0, "this");
       return returnVal.value;
     }
+
+    if (isInitializer) return closure.getAt(0, "this");
+
     return null;
   }
 
@@ -41,17 +47,19 @@ public class LoxFunction implements LoxCallable {
     Environment environment = new Environment(closure);
     environment.define("this", instance);
 
-    return new LoxFunction(declaration, environment);
+    return new LoxFunction(declaration, environment, isInitializer);
   }
 
   /**
-   * <code>
-   * fun add(a,b) {
-   * print a + b;
-   * }
-   * <p>
+   *
+   *
+   * <pre>{@code
+   *  fun add(a,b) {
+   *      print a + b;
+   *  }
+   *
    * print add; // "<fn add>".
-   * </code>
+   * }</pre>
    *
    * @return
    */

+ 10 - 1
src/main/java/com/craftinginterpreters/lox/Resolver.java

@@ -128,6 +128,9 @@ public class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
 
     for (Stmt.Function method : stmt.methods) {
       FunctionType declaration = FunctionType.METHOD;
+      if (method.name.lexeme.equals("init")) {
+        declaration = FunctionType.INITIALIZER;
+      }
       resolveFunction(method, declaration);
     }
     endScope();
@@ -170,7 +173,12 @@ public class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
     if (currentFunction == FunctionType.NONE) {
       Lox.error(stmt.keyword, "Can't return from top-level code");
     }
-    if (stmt.value != null) resolve(stmt.value);
+    if (stmt.value != null) {
+      if (currentFunction == FunctionType.INITIALIZER) {
+        Lox.error(stmt.keyword, "Can't return a value from an initializer.");
+      }
+      resolve(stmt.value);
+    }
     return null;
   }
 
@@ -255,6 +263,7 @@ public class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
   private enum FunctionType {
     NONE,
     FUNCTION,
+    INITIALIZER,
     METHOD
   }
 

+ 11 - 1
src/test/resources/this.lox

@@ -16,4 +16,14 @@ class Cake {
 
 var cake = Cake();
 cake.flavor = "German chocolate";
-cake.taste(); // Prints "The German chocolate cake is delicious!".
+cake.taste(); // Prints "The German chocolate cake is delicious!".
+
+
+class Foo {
+  init() {
+    print this;
+  }
+}
+
+var foo = Foo();
+print foo.init();