15
15
Literal ,
16
16
Logical ,
17
17
Set ,
18
+ Super ,
18
19
This ,
19
20
Unary ,
20
21
Variable ,
@@ -199,6 +200,21 @@ def visit_set_expr(self, expr: Set):
199
200
obj .set (expr .name , value )
200
201
return value
201
202
203
+ def visit_super_expr (self , expr : Super ):
204
+ distance = self .locals [expr ]
205
+ superclass : YaploxClass = self .environment .get_at (
206
+ distance = distance , name = "super"
207
+ )
208
+ obj = self .environment .get_at (distance = distance - 1 , name = "this" )
209
+ method = superclass .find_method (expr .method .lexeme )
210
+
211
+ # Check that we have a super method
212
+ if method is None :
213
+ raise YaploxRuntimeError (
214
+ expr .method , f"Undefined property '{ expr .method .lexeme } '."
215
+ )
216
+ return method .bind (obj )
217
+
202
218
def visit_this_expr (self , expr : This ):
203
219
return self ._look_up_variable (expr .keyword , expr )
204
220
@@ -259,8 +275,20 @@ def visit_assign_expr(self, expr: "Assign") -> Any:
259
275
260
276
# statement stuff
261
277
def visit_class_stmt (self , stmt : Class ):
278
+ superclass = None
279
+ if stmt .superclass is not None :
280
+ superclass = self ._evaluate (stmt .superclass )
281
+ if not isinstance (superclass , YaploxClass ):
282
+ raise YaploxRuntimeError (
283
+ stmt .superclass .name , "Superclass must be a class."
284
+ )
285
+
262
286
self .environment .define (stmt .name .lexeme , None )
263
287
288
+ if stmt .superclass is not None :
289
+ self .environment = Environment (self .environment )
290
+ self .environment .define ("super" , superclass )
291
+
264
292
methods : Dict [str , YaploxFunction ] = {}
265
293
266
294
for method in stmt .methods :
@@ -269,7 +297,13 @@ def visit_class_stmt(self, stmt: Class):
269
297
)
270
298
methods [method .name .lexeme ] = function
271
299
272
- klass = YaploxClass (stmt .name .lexeme , methods )
300
+ klass = YaploxClass (
301
+ name = stmt .name .lexeme , superclass = superclass , methods = methods
302
+ )
303
+
304
+ if stmt .superclass is not None :
305
+ self .environment = self .environment .enclosing # type: ignore
306
+
273
307
self .environment .assign (stmt .name , klass )
274
308
275
309
def visit_expression_stmt (self , stmt : Expression ) -> None :
0 commit comments