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
|
@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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
@ -218,7 +225,7 @@ class Parser {
|
||||||
Token name = ((Expr.Variable) expr).name;
|
Token name = ((Expr.Variable) expr).name;
|
||||||
return new Expr.Assign(name, value);
|
return new Expr.Assign(name, value);
|
||||||
} else if (expr instanceof Expr.Get) {
|
} 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);
|
return new Expr.Set(get.object, get.name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
@ -425,15 +433,15 @@ class Parser {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (peek().type) {
|
switch (peek().type) {
|
||||||
case CLASS:
|
case CLASS:
|
||||||
case FUN:
|
case FUN:
|
||||||
case VAR:
|
case VAR:
|
||||||
case FOR:
|
case FOR:
|
||||||
case IF:
|
case IF:
|
||||||
case WHILE:
|
case WHILE:
|
||||||
case PRINT:
|
case PRINT:
|
||||||
case RETURN:
|
case RETURN:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
advance();
|
advance();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in a new issue