Compile a chained comparison. ```py a == b == c == d ``` Will compile into (pseudo code): ```py result = a == b if result: result = b == c if result: result = c == d ``` # See Also - [CPython `compiler_compare`](https://github.com/python/cpython/blob/627894459a84be3488a1789919679c997056a03c/Python/compile.c#L4678-L4717)
(
&mut self,
left: &ast::Expr,
ops: &[ast::CmpOp],
comparators: &[ast::Expr],
)
| 6939 | /// # See Also |
| 6940 | /// - [CPython `compiler_compare`](https://github.com/python/cpython/blob/627894459a84be3488a1789919679c997056a03c/Python/compile.c#L4678-L4717) |
| 6941 | fn compile_compare( |
| 6942 | &mut self, |
| 6943 | left: &ast::Expr, |
| 6944 | ops: &[ast::CmpOp], |
| 6945 | comparators: &[ast::Expr], |
| 6946 | ) -> CompileResult<()> { |
| 6947 | // Save the full Compare expression range for COMPARE_OP positions |
| 6948 | let compare_range = self.current_source_range; |
| 6949 | let (last_op, mid_ops) = ops.split_last().unwrap(); |
| 6950 | let (last_comparator, mid_comparators) = comparators.split_last().unwrap(); |
| 6951 | |
| 6952 | // initialize lhs outside of loop |
| 6953 | self.compile_expression(left)?; |
| 6954 | |
| 6955 | if mid_comparators.is_empty() { |
| 6956 | self.compile_expression(last_comparator)?; |
| 6957 | self.set_source_range(compare_range); |
| 6958 | self.compile_addcompare(last_op); |
| 6959 | |
| 6960 | return Ok(()); |
| 6961 | } |
| 6962 | |
| 6963 | let cleanup = self.new_block(); |
| 6964 | |
| 6965 | // for all comparisons except the last (as the last one doesn't need a conditional jump) |
| 6966 | for (op, comparator) in mid_ops.iter().zip(mid_comparators) { |
| 6967 | self.compile_expression(comparator)?; |
| 6968 | |
| 6969 | // store rhs for the next comparison in chain |
| 6970 | self.set_source_range(compare_range); |
| 6971 | emit!(self, Instruction::Swap { i: 2 }); |
| 6972 | emit!(self, Instruction::Copy { i: 2 }); |
| 6973 | |
| 6974 | self.compile_addcompare(op); |
| 6975 | |
| 6976 | // if comparison result is false, we break with this value; if true, try the next one. |
| 6977 | emit!(self, Instruction::Copy { i: 1 }); |
| 6978 | emit!(self, Instruction::PopJumpIfFalse { delta: cleanup }); |
| 6979 | emit!(self, Instruction::PopTop); |
| 6980 | } |
| 6981 | |
| 6982 | self.compile_expression(last_comparator)?; |
| 6983 | self.set_source_range(compare_range); |
| 6984 | self.compile_addcompare(last_op); |
| 6985 | |
| 6986 | let end = self.new_block(); |
| 6987 | emit!(self, PseudoInstruction::Jump { delta: end }); |
| 6988 | |
| 6989 | // early exit left us with stack: `rhs, comparison_result`. We need to clean up rhs. |
| 6990 | self.switch_to_block(cleanup); |
| 6991 | emit!(self, Instruction::Swap { i: 2 }); |
| 6992 | emit!(self, Instruction::PopTop); |
| 6993 | |
| 6994 | self.switch_to_block(end); |
| 6995 | Ok(()) |
| 6996 | } |
| 6997 | |
| 6998 | fn compile_jump_if_compare( |
no test coverage detected