13.3 Calling Superclass Methods
This commit is contained in:
parent
1dd608294a
commit
62bd0f83dc
5 changed files with 61 additions and 4 deletions
|
@ -4,7 +4,7 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
class Environment {
|
class Environment {
|
||||||
private final Environment enclosing;
|
final Environment enclosing;
|
||||||
private final Map<String, Object> values = new HashMap<>();
|
private final Map<String, Object> values = new HashMap<>();
|
||||||
|
|
||||||
Environment() {
|
Environment() {
|
||||||
|
|
|
@ -62,6 +62,22 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitSuperExpr(Expr.Super expr) {
|
||||||
|
int distance = locals.get(expr);
|
||||||
|
LoxClass superclass = (LoxClass) environment.getAt(distance, "super");
|
||||||
|
|
||||||
|
LoxInstance object = (LoxInstance) environment.getAt(distance - 1, "this");
|
||||||
|
|
||||||
|
LoxFunction method = superclass.findMethod(expr.method.lexeme);
|
||||||
|
|
||||||
|
if (method == null) {
|
||||||
|
throw new RuntimeError(expr.method, "Undefined property '" + expr.method.lexeme + "'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return method.bind(object);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitThisExpr(Expr.This expr) {
|
public Object visitThisExpr(Expr.This expr) {
|
||||||
return lookUpVariable(expr.keyword, expr);
|
return lookUpVariable(expr.keyword, expr);
|
||||||
|
@ -190,13 +206,23 @@ class Interpreter implements Expr.Visitor<Object>, Stmt.Visitor<Void> {
|
||||||
}
|
}
|
||||||
environment.define(stmt.name.lexeme, null);
|
environment.define(stmt.name.lexeme, null);
|
||||||
|
|
||||||
|
if (stmt.superclass != null) {
|
||||||
|
environment = new Environment(environment);
|
||||||
|
environment.define("super", superclass);
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, LoxFunction> methods = new HashMap<>();
|
Map<String, LoxFunction> methods = new HashMap<>();
|
||||||
for (Stmt.Function method : stmt.methods) {
|
for (Stmt.Function method : stmt.methods) {
|
||||||
LoxFunction function = new LoxFunction(method, environment, method.name.lexeme.equals("init"));
|
LoxFunction function = new LoxFunction(method, environment, method.name.lexeme.equals("init"));
|
||||||
methods.put(method.name.lexeme, function);
|
methods.put(method.name.lexeme, function);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoxClass klass = new LoxClass(stmt.name.lexeme, (LoxClass)superclass, methods);
|
LoxClass klass = new LoxClass(stmt.name.lexeme, (LoxClass) superclass, methods);
|
||||||
|
|
||||||
|
if (superclass != null) {
|
||||||
|
environment = environment.enclosing;
|
||||||
|
}
|
||||||
|
|
||||||
environment.assign(stmt.name, klass);
|
environment.assign(stmt.name, klass);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -362,6 +362,13 @@ class Parser {
|
||||||
return new Expr.Literal(previous().literal);
|
return new Expr.Literal(previous().literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (match(SUPER)) {
|
||||||
|
Token keyword = previous();
|
||||||
|
consume(DOT, "Expect '.' after 'super'.");
|
||||||
|
Token method = consume(IDENTIFIER, "Expect superclass method name.");
|
||||||
|
return new Expr.Super(keyword, method);
|
||||||
|
}
|
||||||
|
|
||||||
if (match(THIS))
|
if (match(THIS))
|
||||||
return new Expr.This(previous());
|
return new Expr.This(previous());
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum ClassType {
|
private enum ClassType {
|
||||||
NONE, CLASS
|
NONE, CLASS, SUBCLASS
|
||||||
}
|
}
|
||||||
|
|
||||||
private ClassType currentClass = ClassType.NONE;
|
private ClassType currentClass = ClassType.NONE;
|
||||||
|
@ -51,9 +51,16 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt.superclass != null) {
|
if (stmt.superclass != null) {
|
||||||
|
currentClass = ClassType.SUBCLASS;
|
||||||
|
|
||||||
resolve(stmt.superclass);
|
resolve(stmt.superclass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stmt.superclass != null) {
|
||||||
|
beginScope();
|
||||||
|
scopes.peek().put("super", true);
|
||||||
|
}
|
||||||
|
|
||||||
beginScope();
|
beginScope();
|
||||||
scopes.peek().put("this", true);
|
scopes.peek().put("this", true);
|
||||||
|
|
||||||
|
@ -67,6 +74,10 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
|
|
||||||
endScope();
|
endScope();
|
||||||
|
|
||||||
|
if (stmt.superclass != null) {
|
||||||
|
endScope();
|
||||||
|
}
|
||||||
|
|
||||||
currentClass = enclosingClass;
|
currentClass = enclosingClass;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -183,6 +194,18 @@ class Resolver implements Expr.Visitor<Void>, Stmt.Visitor<Void> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitSuperExpr(Expr.Super expr) {
|
||||||
|
if (currentClass == ClassType.NONE) {
|
||||||
|
Lox.error(expr.keyword, "Can't use 'super' outside of a class.");
|
||||||
|
} else if (currentClass != ClassType.SUBCLASS) {
|
||||||
|
Lox.error(expr.keyword, "Can't use 'super' in a class with no superclass.");
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveLocal(expr, expr.keyword);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void visitThisExpr(Expr.This expr) {
|
public Void visitThisExpr(Expr.This expr) {
|
||||||
if (currentClass == ClassType.NONE) {
|
if (currentClass == ClassType.NONE) {
|
||||||
|
|
|
@ -19,7 +19,8 @@ public class GenerateAst {
|
||||||
"Call : Expr callee, Token paren, List<Expr> arguments", "Get : Expr object, Token name",
|
"Call : Expr callee, Token paren, List<Expr> arguments", "Get : Expr object, Token name",
|
||||||
"Grouping : Expr expression", "Literal : Object value",
|
"Grouping : Expr expression", "Literal : Object value",
|
||||||
"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"));
|
"Super : Token keyword, Token method", "This : Token keyword",
|
||||||
|
"Unary : Token operator, Expr right", "Variable : Token name"));
|
||||||
defineAst(outputDir, "Stmt",
|
defineAst(outputDir, "Stmt",
|
||||||
Arrays.asList("Block : List<Stmt> statements",
|
Arrays.asList("Block : List<Stmt> statements",
|
||||||
"Class : Token name, Expr.Variable superclass, List<Stmt.Function> methods",
|
"Class : Token name, Expr.Variable superclass, List<Stmt.Function> methods",
|
||||||
|
|
Loading…
Reference in a new issue