(
&mut self,
p: &ast::PatternMatchOr,
pc: &mut PatternContext,
)
| 6536 | } |
| 6537 | |
| 6538 | fn compile_pattern_or( |
| 6539 | &mut self, |
| 6540 | p: &ast::PatternMatchOr, |
| 6541 | pc: &mut PatternContext, |
| 6542 | ) -> CompileResult<()> { |
| 6543 | // Ensure the pattern is a MatchOr. |
| 6544 | let end = self.new_block(); // Create a new jump target label. |
| 6545 | let size = p.patterns.len(); |
| 6546 | if size <= 1 { |
| 6547 | return Err(self.error(CodegenErrorType::SyntaxError( |
| 6548 | "MatchOr requires at least 2 patterns".to_owned(), |
| 6549 | ))); |
| 6550 | } |
| 6551 | |
| 6552 | // Save the current pattern context. |
| 6553 | let old_pc = pc.clone(); |
| 6554 | // Simulate Py_INCREF on pc.stores by cloning it. |
| 6555 | pc.stores = pc.stores.clone(); |
| 6556 | let mut control: Option<Vec<String>> = None; // Will hold the capture list of the first alternative. |
| 6557 | |
| 6558 | // Process each alternative. |
| 6559 | for (i, alt) in p.patterns.iter().enumerate() { |
| 6560 | // Create a fresh empty store for this alternative. |
| 6561 | pc.stores = Vec::new(); |
| 6562 | // An irrefutable subpattern must be last (if allowed). |
| 6563 | pc.allow_irrefutable = (i == size - 1) && old_pc.allow_irrefutable; |
| 6564 | // Reset failure targets and the on_top counter. |
| 6565 | pc.fail_pop.clear(); |
| 6566 | pc.on_top = 0; |
| 6567 | // Emit a COPY(1) instruction before compiling the alternative. |
| 6568 | emit!(self, Instruction::Copy { i: 1 }); |
| 6569 | self.compile_pattern(alt, pc)?; |
| 6570 | |
| 6571 | let n_stores = pc.stores.len(); |
| 6572 | if i == 0 { |
| 6573 | // Save the captured names from the first alternative. |
| 6574 | control = Some(pc.stores.clone()); |
| 6575 | } else { |
| 6576 | let control_vec = control.as_ref().unwrap(); |
| 6577 | if n_stores != control_vec.len() { |
| 6578 | return Err(self.error(CodegenErrorType::ConflictingNameBindPattern)); |
| 6579 | } else if n_stores > 0 { |
| 6580 | // Check that the names occur in the same order. |
| 6581 | for i_control in (0..n_stores).rev() { |
| 6582 | let name = &control_vec[i_control]; |
| 6583 | // Find the index of `name` in the current stores. |
| 6584 | let i_stores = |
| 6585 | pc.stores.iter().position(|n| n == name).ok_or_else(|| { |
| 6586 | self.error(CodegenErrorType::ConflictingNameBindPattern) |
| 6587 | })?; |
| 6588 | if i_control != i_stores { |
| 6589 | // The orders differ; we must reorder. |
| 6590 | assert!(i_stores < i_control, "expected i_stores < i_control"); |
| 6591 | let rotations = i_stores + 1; |
| 6592 | // Rotate pc.stores: take a slice of the first `rotations` items... |
| 6593 | let rotated = pc.stores[0..rotations].to_vec(); |
| 6594 | // Remove those elements. |
| 6595 | for _ in 0..rotations { |
no test coverage detected