13.1 Superclasses and Subclasses
This commit is contained in:
parent
958ba22a57
commit
db403da4b2
5 changed files with 42 additions and 16 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue