(
&mut self,
items: &[ast::WithItem],
body: &[ast::Stmt],
is_async: bool,
)
| 5548 | } |
| 5549 | |
| 5550 | fn compile_with( |
| 5551 | &mut self, |
| 5552 | items: &[ast::WithItem], |
| 5553 | body: &[ast::Stmt], |
| 5554 | is_async: bool, |
| 5555 | ) -> CompileResult<()> { |
| 5556 | self.enter_conditional_block(); |
| 5557 | |
| 5558 | // Python 3.12+ style with statement: |
| 5559 | // |
| 5560 | // BEFORE_WITH # TOS: ctx_mgr -> [__exit__, __enter__ result] |
| 5561 | // L1: STORE_NAME f # exception table: L1 to L2 -> L3 [1] lasti |
| 5562 | // L2: ... body ... |
| 5563 | // LOAD_CONST None # normal exit |
| 5564 | // LOAD_CONST None |
| 5565 | // LOAD_CONST None |
| 5566 | // CALL 2 # __exit__(None, None, None) |
| 5567 | // POP_TOP |
| 5568 | // JUMP after |
| 5569 | // L3: PUSH_EXC_INFO # exception handler |
| 5570 | // WITH_EXCEPT_START # call __exit__(type, value, tb), push result |
| 5571 | // TO_BOOL |
| 5572 | // POP_JUMP_IF_TRUE suppress |
| 5573 | // RERAISE 2 |
| 5574 | // suppress: |
| 5575 | // POP_TOP # pop exit result |
| 5576 | // L5: POP_EXCEPT |
| 5577 | // POP_TOP # pop __exit__ |
| 5578 | // POP_TOP # pop prev_exc (or lasti depending on layout) |
| 5579 | // JUMP after |
| 5580 | // L6: COPY 3 # cleanup handler for reraise |
| 5581 | // POP_EXCEPT |
| 5582 | // RERAISE 1 |
| 5583 | // after: ... |
| 5584 | |
| 5585 | let with_range = self.current_source_range; |
| 5586 | |
| 5587 | let Some((item, items)) = items.split_first() else { |
| 5588 | return Err(self.error(CodegenErrorType::EmptyWithItems)); |
| 5589 | }; |
| 5590 | |
| 5591 | let exc_handler_block = self.new_block(); |
| 5592 | let after_block = self.new_block(); |
| 5593 | |
| 5594 | // Compile context expression and load __enter__/__exit__ methods |
| 5595 | self.compile_expression(&item.context_expr)?; |
| 5596 | self.set_source_range(with_range); |
| 5597 | |
| 5598 | // Stack: [cm] |
| 5599 | emit!(self, Instruction::Copy { i: 1 }); // [cm, cm] |
| 5600 | |
| 5601 | if is_async { |
| 5602 | if self.ctx.func != FunctionContext::AsyncFunction { |
| 5603 | return Err(self.error(CodegenErrorType::InvalidAsyncWith)); |
| 5604 | } |
| 5605 | // Load __aexit__ and __aenter__, then call __aenter__ |
| 5606 | emit!( |
| 5607 | self, |
no test coverage detected