Skip to content

Commit 7951f35

Browse files
committed
feat: implement super and finish the jlox yeo!!!!
1 parent 3cbe4df commit 7951f35

4 files changed

Lines changed: 50 additions & 2 deletions

File tree

src/main/kotlin/com/aymanetech/Expr.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ sealed class Expr : ExprVisitable {
4040
override fun <T> accept(visitor: Visitor<T>) = visitor.visit(this)
4141
}
4242

43+
data class Super(val keyword: Token, val method: Token): Expr() {
44+
override fun <T> accept(visitor: Visitor<T>) = visitor.visit(this)
45+
}
46+
4347
data class This(val keyword: Token) : Expr() {
4448
override fun <T> accept(visitor: Visitor<T>) = visitor.visit(this)
4549
}
@@ -69,5 +73,6 @@ sealed class Expr : ExprVisitable {
6973
fun visit(expr: Get): T
7074
fun visit(expr: Set): T
7175
fun visit(expr: This): T
76+
fun visit(expr: Super): T
7277
}
7378
}

src/main/kotlin/com/aymanetech/Interpreter.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,16 @@ class Interpreter : Expr.Visitor<Any?>, Stmt.Visitor<Unit> {
145145
return value
146146
}
147147

148+
override fun visit(expr: Super): Any? {
149+
val distance = locals[expr]
150+
val superClass = environment.getAt(distance!!, "super") as LoxClass
151+
val obj = environment.getAt(distance - 1, "this") as LoxInstance
152+
val method = superClass.findMethod(expr.method.lexeme)
153+
?: throw RuntimeError(expr.method, "Undefined property '${expr.method.lexeme}'")
154+
155+
return method.bind(obj)
156+
}
157+
148158
override fun visit(expr: This): Any? = lookUpVariable(expr.keyword, expr)
149159

150160
override fun visit(stmt: Expression) {
@@ -198,6 +208,12 @@ class Interpreter : Expr.Visitor<Any?>, Stmt.Visitor<Unit> {
198208
}
199209

200210
environment.define(stmt.name.lexeme to null)
211+
212+
if (stmt.superClass != null) {
213+
environment = Environment(environment)
214+
environment.define("super" to superClass)
215+
}
216+
201217
val methods: Map<String, LoxFunction> = stmt.methods.associate {
202218
val method = it.name.lexeme
203219
method to LoxFunction(it, environment, method == "init")
@@ -208,6 +224,8 @@ class Interpreter : Expr.Visitor<Any?>, Stmt.Visitor<Unit> {
208224
method to LoxFunction(it, environment, false)
209225
}
210226
val klass = LoxClass(stmt.name.lexeme, superClass as LoxClass?, methods, staticMethods)
227+
if (stmt.superClass != null) environment = environment.enclosing!!
228+
211229
environment.assign(stmt.name to klass)
212230
}
213231

src/main/kotlin/com/aymanetech/Parser.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ class Parser(private val tokens: List<Token>) {
293293
match(TRUE) -> Literal(true)
294294
match(NIL) -> Literal(null)
295295
match(NUMBER, STRING) -> Literal(previous().literal)
296+
match(SUPER) -> superKeyword()
296297
match(THIS) -> This(previous())
297298
match(IDENTIFIER) -> Variable(previous())
298299
match(FN) -> anonymousFunction()
@@ -305,6 +306,13 @@ class Parser(private val tokens: List<Token>) {
305306
else -> throw error(peek(), "Expect expression.")
306307
}
307308

309+
private fun superKeyword(): Expr {
310+
val keyword = previous()
311+
consume(DOT, "Expect '.' after keyword")
312+
val name = consume(IDENTIFIER, "Expect superclass method name")
313+
return Super(keyword, name)
314+
}
315+
308316
private fun match(vararg types: TokenType): Boolean {
309317
for (type in types) {
310318
if (check(type)) {

src/main/kotlin/com/aymanetech/Resolver.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ class Resolver(private val interpreter: Interpreter) : Expr.Visitor<Unit>, Stmt.
5555
resolve(expr.obj)
5656
}
5757

58+
override fun visit(expr: Super) {
59+
if(currentClass == ClassType.NONE)
60+
error(expr.keyword, "Can't use 'super' outside of a class.")
61+
else if (currentClass != ClassType.SUBCLASS)
62+
error(expr.keyword, "Can't use 'super' in a class without a superclass.")
63+
64+
resolveLocal(expr, expr.keyword)
65+
}
66+
5867
override fun visit(expr: This) {
5968
if (currentClass == ClassType.NONE) {
6069
error(expr.keyword, "Can't use 'this' outside of a method")
@@ -132,8 +141,15 @@ class Resolver(private val interpreter: Interpreter) : Expr.Visitor<Unit>, Stmt.
132141
if(stmt.superClass != null && stmt.name.lexeme.equals(stmt.superClass.name.lexeme))
133142
error(stmt.superClass.name, "A class can't inherit from itself")
134143

135-
if (stmt.superClass != null)
144+
if (stmt.superClass != null){
145+
currentClass = ClassType.SUBCLASS
136146
resolve(stmt.superClass)
147+
}
148+
149+
if(stmt.superClass != null){
150+
beginScope()
151+
scopes.peek()["super"] = true
152+
}
137153

138154
beginScope()
139155
scopes.peek()["this"] = true
@@ -142,6 +158,7 @@ class Resolver(private val interpreter: Interpreter) : Expr.Visitor<Unit>, Stmt.
142158
resolveFunction(it, declaration)
143159
}
144160
endScope()
161+
if(stmt.superClass != null) endScope()
145162
currentClass = enclosingClass
146163
}
147164

@@ -210,7 +227,7 @@ class Resolver(private val interpreter: Interpreter) : Expr.Visitor<Unit>, Stmt.
210227
}
211228

212229
enum class ClassType {
213-
NONE, CLASS
230+
NONE, CLASS, SUBCLASS
214231
}
215232
}
216233

0 commit comments

Comments
 (0)