13.1 Superclasses and Subclasses

This commit is contained in:
Tom Willemse 2021-06-14 23:36:10 -07:00
parent 958ba22a57
commit db403da4b2
5 changed files with 42 additions and 16 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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);

View file

@ -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",