(&mut self, handler: ErrorHandler<'gc>)
| 1273 | } |
| 1274 | |
| 1275 | fn generate_error_handler(&mut self, handler: ErrorHandler<'gc>) -> Result<(), VmError> { |
| 1276 | let error_jump = self.emit_jump(OpCode::JumpIfError(0)); |
| 1277 | let end_jump = self.emit_jump(OpCode::Jump(0)); |
| 1278 | |
| 1279 | self.patch_jump(error_jump); |
| 1280 | if handler.propagate { |
| 1281 | // For ? operator, return error directly |
| 1282 | self.emit(OpCode::Return); |
| 1283 | } else { |
| 1284 | let is_local_scope = self.scope_depth > 0; |
| 1285 | if is_local_scope { |
| 1286 | // since the assign value isn't a local variable |
| 1287 | // Give this: |
| 1288 | // let x = function_call() |err| {} |
| 1289 | // 'x' is a globa variable which don't occupy a local variable slot |
| 1290 | self.emit(OpCode::Dup); |
| 1291 | } |
| 1292 | // Begin scope for error variable |
| 1293 | self.begin_scope(); |
| 1294 | // Store error in handler variable |
| 1295 | let err_local_pos = self.declare_variable(handler.error_var, Mutability::Mutable); |
| 1296 | self.mark_initialized(); |
| 1297 | |
| 1298 | let has_return = matches!( |
| 1299 | handler.handler_body.last(), |
| 1300 | Some(Stmt::Return { .. }) | Some(Stmt::BlockReturn { .. }) |
| 1301 | ); |
| 1302 | // Generate handler body - any return here will return from entire function |
| 1303 | for stmt in handler.handler_body { |
| 1304 | self.generate_stmt(stmt)?; |
| 1305 | } |
| 1306 | |
| 1307 | // Set the last expression of error handle block (aka, stack top value) |
| 1308 | // to the faield function call return value. |
| 1309 | if is_local_scope { |
| 1310 | // We are in local scope, the slot is err_local_pos - 1 |
| 1311 | self.emit(OpCode::SetLocal(err_local_pos as u8 - 1)); |
| 1312 | } else { |
| 1313 | // We are in global scope, don't need to minus 1 |
| 1314 | self.emit(OpCode::SetLocal(err_local_pos as u8)); |
| 1315 | } |
| 1316 | self.end_scope(); |
| 1317 | if is_local_scope { |
| 1318 | // Pop the stack top we duplicated before |
| 1319 | self.emit(OpCode::Pop(1)); |
| 1320 | } |
| 1321 | // If no return in handler, set nil as value and continue |
| 1322 | if !has_return { |
| 1323 | self.emit(OpCode::Nil); |
| 1324 | } |
| 1325 | } |
| 1326 | self.patch_jump(end_jump); |
| 1327 | Ok(()) |
| 1328 | } |
| 1329 | |
| 1330 | fn generate_class( |
| 1331 | &mut self, |
no test coverage detected