Emit `yield` / `yield from` / bare `yield`, leaving the produced value on the stack so it works in both statement and expression position. Assumes the `yield` keyword was already consumed. */
(&mut self)
| 641 | |
| 642 | /* Emit `yield` / `yield from` / bare `yield`, leaving the produced value on the stack so it works in both statement and expression position. Assumes the `yield` keyword was already consumed. */ |
| 643 | pub(super) fn emit_yield(&mut self) { |
| 644 | // No value when a line boundary or a closing token follows (`(yield)`, `f(yield)`). |
| 645 | let bare = matches!( |
| 646 | self.peek_same_line(), |
| 647 | None | Some(TokenType::Rpar | TokenType::Rsqb | TokenType::Rbrace |
| 648 | | TokenType::Comma | TokenType::Colon) |
| 649 | ); |
| 650 | if bare { |
| 651 | self.chunk.emit(OpCode::LoadNone, 0); |
| 652 | self.chunk.emit(OpCode::Yield, 0); |
| 653 | } else if self.eat_if(TokenType::From) { |
| 654 | // `yield from`: GetIter+ForIter+Yield loop; LoadYieldFrom pushes the subiterator's return value. |
| 655 | self.expr(); |
| 656 | self.chunk.emit(OpCode::GetIter, 0); |
| 657 | let loop_start = self.chunk.instructions.len() as u16; |
| 658 | let fi = self.emit_jump(OpCode::ForIter); |
| 659 | self.chunk.emit(OpCode::Yield, 0); |
| 660 | self.chunk.emit(OpCode::PopTop, 0); |
| 661 | self.chunk.emit(OpCode::Jump, loop_start); |
| 662 | self.patch(fi); |
| 663 | self.chunk.emit(OpCode::LoadYieldFrom, 0); |
| 664 | } else { |
| 665 | self.expr(); |
| 666 | self.chunk.emit(OpCode::Yield, 0); |
| 667 | } |
| 668 | } |
| 669 | |
| 670 | pub(super) fn assign(&mut self, name: String) { |
| 671 | self.advance(); |