(
&mut self,
ClassDecl {
name,
superclass,
methods,
visibility,
..
}: ClassDecl<'gc>,
)
| 1328 | } |
| 1329 | |
| 1330 | fn generate_class( |
| 1331 | &mut self, |
| 1332 | ClassDecl { |
| 1333 | name, |
| 1334 | superclass, |
| 1335 | methods, |
| 1336 | visibility, |
| 1337 | .. |
| 1338 | }: ClassDecl<'gc>, |
| 1339 | ) -> Result<(), VmError> { |
| 1340 | // Emit class declaration |
| 1341 | let name_constant = self.identifier_constant(name.lexeme); |
| 1342 | self.emit(OpCode::Class(name_constant as u8)); |
| 1343 | self.emit(OpCode::DefineGlobal { |
| 1344 | name_constant: name_constant as u8, |
| 1345 | visibility, |
| 1346 | }); |
| 1347 | |
| 1348 | let has_superclass = superclass.is_some(); |
| 1349 | // Handle inheritance |
| 1350 | if let Some(superclass) = superclass { |
| 1351 | // Begin a new scope for 'super' |
| 1352 | self.begin_scope(); |
| 1353 | |
| 1354 | // First get the superclass |
| 1355 | self.generate_expr(superclass)?; |
| 1356 | |
| 1357 | // Creating a new lexical scope ensures that if we declare two classes in the same scope, |
| 1358 | // each has a different local slot to store its superclass. Since we always name this |
| 1359 | // variable “super”, if we didn’t make a scope for each subclass, the variables would collide. |
| 1360 | let super_token = Token::new(TokenType::Super, "super", name.line); |
| 1361 | self.declare_variable(super_token, Mutability::Immutable); |
| 1362 | self.mark_initialized(); |
| 1363 | |
| 1364 | // Then get the class we just defined |
| 1365 | self.emit(OpCode::GetGlobal(name_constant as u8)); |
| 1366 | |
| 1367 | // Emit inherit instruction |
| 1368 | self.emit(OpCode::Inherit); |
| 1369 | |
| 1370 | // Load class again for method definitions |
| 1371 | self.emit(OpCode::GetGlobal(name_constant as u8)); |
| 1372 | } else { |
| 1373 | // Load class for method definitions |
| 1374 | self.emit(OpCode::GetGlobal(name_constant as u8)); |
| 1375 | } |
| 1376 | |
| 1377 | // Generate methods |
| 1378 | for method in methods { |
| 1379 | if let Stmt::Function(function_decl) = method { |
| 1380 | self.generate_method(function_decl)?; |
| 1381 | } |
| 1382 | } |
| 1383 | |
| 1384 | // Once we’ve reached the end of the methods, we no longer need |
| 1385 | // the class and tell the VM to pop it off the stack. |
| 1386 | self.emit(OpCode::Pop(1)); |
| 1387 |
no test coverage detected