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 @Override
public Void visitClassStmt(Stmt.Class stmt) { 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); environment.define(stmt.name.lexeme, null);
Map<String, LoxFunction> methods = new HashMap<>(); 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); 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); environment.assign(stmt.name, klass);
return null; return null;
} }

View file

@ -5,9 +5,11 @@ import java.util.Map;
class LoxClass implements LoxCallable { class LoxClass implements LoxCallable {
final String name; final String name;
final LoxClass superclass;
private final Map<String, LoxFunction> methods; 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.name = name;
this.methods = methods; this.methods = methods;
} }

View file

@ -3,8 +3,8 @@ package com.craftinginterpreters.lox;
import static com.craftinginterpreters.lox.TokenType.*; import static com.craftinginterpreters.lox.TokenType.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
class Parser { class Parser {
private static class ParseError extends RuntimeException { private static class ParseError extends RuntimeException {
@ -49,6 +49,13 @@ class Parser {
private Stmt classDeclaration() { private Stmt classDeclaration() {
Token name = consume(IDENTIFIER, "Expect class name."); 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."); consume(LEFT_BRACE, "Expect '{' before class body.");
List<Stmt.Function> methods = new ArrayList<>(); List<Stmt.Function> methods = new ArrayList<>();
@ -58,7 +65,7 @@ class Parser {
consume(RIGHT_BRACE, "Expect '}' after class body."); consume(RIGHT_BRACE, "Expect '}' after class body.");
return new Stmt.Class(name, methods); return new Stmt.Class(name, superclass, methods);
} }
private Stmt statement() { private Stmt statement() {
@ -355,7 +362,8 @@ class Parser {
return new Expr.Literal(previous().literal); 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)) { if (match(IDENTIFIER)) {
return new Expr.Variable(previous()); return new Expr.Variable(previous());

View file

@ -46,6 +46,14 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
declare(stmt.name); declare(stmt.name);
define(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(); beginScope();
scopes.peek().put("this", true); 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", "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")); "This : Token keyword", "Unary : Token operator, Expr right", "Variable : Token name"));
defineAst(outputDir, "Stmt", 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", "Expression : Expr expression", "Function : Token name, List<Token> params, List<Stmt> body",
"If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression", "If : Expr condition, Stmt thenBranch, Stmt elseBranch", "Print : Expr expression",
"Return : Token keyword, Expr value", "Var : Token name, Expr initializer", "Return : Token keyword, Expr value", "Var : Token name, Expr initializer",