aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom Willemse2021-06-14 23:36:10 -0700
committerGravatar Tom Willemse2021-06-14 23:36:10 -0700
commitdb403da4b2ed543100dc42fd3f0036fd64ed76a9 (patch)
tree1bfba97f0580d8274173642897148eb68566ea2a
parent958ba22a570594ed2ce60d24cd082ce3b8a6b89a (diff)
downloadcrafting-interpreters-db403da4b2ed543100dc42fd3f0036fd64ed76a9.tar.gz
crafting-interpreters-db403da4b2ed543100dc42fd3f0036fd64ed76a9.zip
13.1 Superclasses and Subclasses
-rw-r--r--src/com/craftinginterpreters/lox/Interpreter.java9
-rw-r--r--src/com/craftinginterpreters/lox/LoxClass.java4
-rw-r--r--src/com/craftinginterpreters/lox/Parser.java34
-rw-r--r--src/com/craftinginterpreters/lox/Resolver.java8
-rw-r--r--src/com/craftinginterpreters/tool/GenerateAst.java3
5 files changed, 42 insertions, 16 deletions
diff --git a/src/com/craftinginterpreters/lox/Interpreter.java b/src/com/craftinginterpreters/lox/Interpreter.java
index 7dfd0fb..101c33c 100644
--- a/src/com/craftinginterpreters/lox/Interpreter.java
+++ b/src/com/craftinginterpreters/lox/Interpreter.java
@@ -181,6 +181,13 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
@Override
public Void visitClassStmt(Stmt.Class stmt) {
+ Object superclass = null;
+ if (stmt.superclass != null) {
+ superclass = evaluate(stmt.superclass);
+ if (!(superclass instanceof LoxClass)) {
+ throw new RuntimeError(stmt.superclass.name, "Superclass must be a class.");
+ }
+ }
environment.define(stmt.name.lexeme, null);
Map<String, LoxFunction> methods = new HashMap<>();
@@ -189,7 +196,7 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
methods.put(method.name.lexeme, function);
}
- LoxClass klass = new LoxClass(stmt.name.lexeme, methods);
+ LoxClass klass = new LoxClass(stmt.name.lexeme, (LoxClass)superclass, methods);
environment.assign(stmt.name, klass);
return null;
}
diff --git a/src/com/craftinginterpreters/lox/LoxClass.java b/src/com/craftinginterpreters/lox/LoxClass.java
index 5e0e755..c9261b9 100644
--- a/src/com/craftinginterpreters/lox/LoxClass.java
+++ b/src/com/craftinginterpreters/lox/LoxClass.java
@@ -5,9 +5,11 @@ import java.util.Map;
class LoxClass implements LoxCallable {
final String name;
+ final LoxClass superclass;
private final Map<String, LoxFunction> methods;
- LoxClass(String name, Map<String, LoxFunction> methods) {
+ LoxClass(String name, LoxClass superclass, Map<String, LoxFunction> methods) {
+ this.superclass = superclass;
this.name = name;
this.methods = methods;
}
diff --git a/src/com/craftinginterpreters/lox/Parser.java b/src/com/craftinginterpreters/lox/Parser.java
index a3f4897..3150035 100644
--- a/src/com/craftinginterpreters/lox/Parser.java
+++ b/src/com/craftinginterpreters/lox/Parser.java
@@ -3,8 +3,8 @@ package com.craftinginterpreters.lox;
import static com.craftinginterpreters.lox.TokenType.*;
import java.util.ArrayList;
-import java.util.List;
import java.util.Arrays;
+import java.util.List;
class Parser {
private static class ParseError extends RuntimeException {
@@ -49,6 +49,13 @@ class Parser {
private Stmt classDeclaration() {
Token name = consume(IDENTIFIER, "Expect class name.");
+
+ Expr.Variable superclass = null;
+ if (match(LESS)) {
+ consume(IDENTIFIER, "Expect superclass name.");
+ superclass = new Expr.Variable(previous());
+ }
+
consume(LEFT_BRACE, "Expect '{' before class body.");
List<Stmt.Function> methods = new ArrayList<>();
@@ -58,7 +65,7 @@ class Parser {
consume(RIGHT_BRACE, "Expect '}' after class body.");
- return new Stmt.Class(name, methods);
+ return new Stmt.Class(name, superclass, methods);
}
private Stmt statement() {
@@ -218,7 +225,7 @@ class Parser {
Token name = ((Expr.Variable) expr).name;
return new Expr.Assign(name, value);
} else if (expr instanceof Expr.Get) {
- Expr.Get get = (Expr.Get)expr;
+ Expr.Get get = (Expr.Get) expr;
return new Expr.Set(get.object, get.name, value);
}
@@ -355,7 +362,8 @@ class Parser {
return new Expr.Literal(previous().literal);
}
- if (match(THIS)) return new Expr.This(previous());
+ if (match(THIS))
+ return new Expr.This(previous());
if (match(IDENTIFIER)) {
return new Expr.Variable(previous());
@@ -425,15 +433,15 @@ class Parser {
return;
switch (peek().type) {
- case CLASS:
- case FUN:
- case VAR:
- case FOR:
- case IF:
- case WHILE:
- case PRINT:
- case RETURN:
- return;
+ case CLASS:
+ case FUN:
+ case VAR:
+ case FOR:
+ case IF:
+ case WHILE:
+ case PRINT:
+ case RETURN:
+ return;
}
advance();
diff --git a/src/com/craftinginterpreters/lox/Resolver.java b/src/com/craftinginterpreters/lox/Resolver.java
index cda0f60..dc7332b 100644
--- a/src/com/craftinginterpreters/lox/Resolver.java
+++ b/src/com/craftinginterpreters/lox/Resolver.java
@@ -46,6 +46,14 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
declare(stmt.name);
define(stmt.name);
+ if (stmt.superclass != null && stmt.name.lexeme.equals(stmt.superclass.name.lexeme)) {
+ Lox.error(stmt.superclass.name, "A class can't inherit from itself.");
+ }
+
+ if (stmt.superclass != null) {
+ resolve(stmt.superclass);
+ }
+
beginScope();
scopes.peek().put("this", true);
diff --git a/src/com/craftinginterpreters/tool/GenerateAst.java b/src/com/craftinginterpreters/tool/GenerateAst.java
index 2097e31..a6789b9 100644
--- a/src/com/craftinginterpreters/tool/GenerateAst.java
+++ b/src/com/craftinginterpreters/tool/GenerateAst.java
@@ -21,7 +21,8 @@ public class GenerateAst {
"Logical : Expr left, Token operator, Expr right", "Set : Expr object, Token name, Expr value",
"This : Token keyword", "Unary : Token operator, Expr right", "Variable : Token name"));
defineAst(outputDir, "Stmt",
- Arrays.asList("Block : List<Stmt> statements", "Class : Token name, List<Stmt.Function> methods",
+ Arrays.asList("Block : List<Stmt> statements",
+ "Class : Token name, Expr.Variable superclass, List<Stmt.Function> methods",
"Expression : Expr expression", "Function : Token name, List<Token> params, List<Stmt> body",
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
"Return : Token keyword, Expr value", "Var : Token name, Expr initializer",