(&mut self, is_async: bool)
| 367 | /* for / async for, with optional tuple/star unpacking. */ |
| 368 | |
| 369 | pub(super) fn for_stmt_inner(&mut self, is_async: bool) { |
| 370 | self.advance(); |
| 371 | |
| 372 | let parens = self.eat_if(TokenType::Lpar); |
| 373 | let mut vars = Vec::new(); |
| 374 | let mut star_pos: Option<usize> = None; |
| 375 | loop { |
| 376 | if self.eat_if(TokenType::Star) { star_pos = Some(vars.len()); } |
| 377 | vars.push(self.advance_text()); |
| 378 | if !self.eat_if(TokenType::Comma) { break; } |
| 379 | if matches!(self.peek(), Some(TokenType::In | TokenType::Rpar)) { break; } |
| 380 | } |
| 381 | if parens { |
| 382 | self.eat(TokenType::Rpar); |
| 383 | } |
| 384 | |
| 385 | self.eat(TokenType::In); |
| 386 | self.expr(); |
| 387 | // Unparenthesized tuple iterable: `for x in 1, 2:` iterates the tuple. |
| 388 | let mut n = 1u16; |
| 389 | while self.eat_if(TokenType::Comma) { |
| 390 | if matches!(self.peek(), Some(TokenType::Colon) | None) { break; } |
| 391 | self.expr(); |
| 392 | n += 1; |
| 393 | } |
| 394 | if n > 1 { self.chunk.emit(OpCode::BuildTuple, n); } |
| 395 | self.chunk.emit(OpCode::GetIter, is_async as u16); |
| 396 | |
| 397 | self.enter_block(); |
| 398 | |
| 399 | let loop_start = self.chunk.instructions.len() as u16; |
| 400 | self.loop_starts.push(loop_start); |
| 401 | self.loop_breaks.push(vec![]); |
| 402 | self.loop_kinds.push(true); |
| 403 | self.loop_cleanup_base.push(self.cleanup_count); |
| 404 | |
| 405 | let fi = self.emit_jump(OpCode::ForIter); |
| 406 | |
| 407 | if vars.len() == 1 && star_pos.is_none() { |
| 408 | self.store_name(vars[0].clone()); |
| 409 | } else { |
| 410 | if let Some(sp) = star_pos { |
| 411 | let before = sp as u16; |
| 412 | let after = (vars.len() - sp - 1) as u16; |
| 413 | self.chunk.emit(OpCode::UnpackEx, (before << 8) | after); |
| 414 | } else { |
| 415 | self.chunk.emit(OpCode::UnpackSequence, vars.len() as u16); |
| 416 | } |
| 417 | for var in &vars { self.store_name(var.clone()); } |
| 418 | } |
| 419 | |
| 420 | self.eat(TokenType::Colon); |
| 421 | self.compile_block(); |
| 422 | |
| 423 | self.chunk.emit(OpCode::Jump, loop_start); |
| 424 | self.patch(fi); |
| 425 | |
| 426 | // Pop loop state before the else so its break/continue target the enclosing loop. |
no test coverage detected