(&mut self)
| 443 | /* try / except / else / finally with exception arm chaining. */ |
| 444 | |
| 445 | pub(super) fn try_stmt(&mut self) { |
| 446 | self.advance(); |
| 447 | self.eat(TokenType::Colon); |
| 448 | |
| 449 | // Outer cleanup frame: the finally runs on every exit (normal, return, break, raise). |
| 450 | let fin_setup = self.emit_jump(OpCode::SetupFinally); |
| 451 | self.cleanup_count += 1; |
| 452 | let setup = self.emit_jump(OpCode::SetupExcept); |
| 453 | |
| 454 | self.enter_block(); |
| 455 | self.compile_block(); |
| 456 | |
| 457 | self.chunk.emit(OpCode::PopExcept, 0); |
| 458 | let success_jump = self.emit_jump(OpCode::Jump); |
| 459 | |
| 460 | self.mid_block(); |
| 461 | |
| 462 | self.patch(setup); |
| 463 | |
| 464 | let mut end_jumps: Vec<usize> = Vec::new(); |
| 465 | let mut next_arm_jump: Option<usize> = None; |
| 466 | let mut had_bare = false; |
| 467 | let mut had_except = false; |
| 468 | |
| 469 | while self.eat_if(TokenType::Except) { |
| 470 | had_except = true; |
| 471 | if let Some(j) = next_arm_jump.take() { self.patch(j); } |
| 472 | if had_bare { |
| 473 | self.error("default 'except:' must be last"); |
| 474 | break; |
| 475 | } |
| 476 | |
| 477 | let mut as_name: Option<String> = None; |
| 478 | if matches!(self.peek(), Some(TokenType::Colon)) { |
| 479 | had_bare = true; |
| 480 | self.chunk.emit(OpCode::PopTop, 0); |
| 481 | } else { |
| 482 | self.chunk.emit(OpCode::Dup, 0); |
| 483 | self.expr(); |
| 484 | let isinst_pos = self.last_end as u32; |
| 485 | self.chunk.emit(OpCode::CallIsInstance, 2); |
| 486 | self.chunk.record_call_pos(isinst_pos); |
| 487 | next_arm_jump = Some(self.emit_jump(OpCode::JumpIfFalse)); |
| 488 | |
| 489 | if self.eat_if(TokenType::As) { |
| 490 | let n = self.advance_text(); |
| 491 | self.store_name(n.clone()); |
| 492 | as_name = Some(n); |
| 493 | } else { self.chunk.emit(OpCode::PopTop, 0); } |
| 494 | } |
| 495 | self.eat(TokenType::Colon); |
| 496 | self.compile_block(); |
| 497 | // Python implicitly unbinds the `except ... as e` name after the block. |
| 498 | if let Some(n) = as_name { |
| 499 | let idx = self.push_ssa_name(&n, self.current_version(&n)); |
| 500 | self.chunk.emit(OpCode::Del, idx); |
| 501 | } |
| 502 |
no test coverage detected