@@ -4173,7 +4173,9 @@ impl Compiler {
41734173 if let Some ( ref guard) = m. guard {
41744174 // Compile guard and jump to end if false
41754175 self . compile_expression ( guard) ?;
4176- emit ! ( self , Instruction :: JumpIfFalseOrPop { target: end } ) ;
4176+ emit ! ( self , Instruction :: CopyItem { index: 1_u32 } ) ;
4177+ emit ! ( self , Instruction :: PopJumpIfFalse { target: end } ) ;
4178+ emit ! ( self , Instruction :: PopTop ) ;
41774179 }
41784180 self . compile_statements ( & m. body ) ?;
41794181 }
@@ -4187,92 +4189,97 @@ impl Compiler {
41874189 Ok ( ( ) )
41884190 }
41894191
4190- fn compile_chained_comparison (
4192+ /// [CPython `compiler_addcompare`](https://github.com/python/cpython/blob/627894459a84be3488a1789919679c997056a03c/Python/compile.c#L2880-L2924)
4193+ fn compile_addcompare ( & mut self , op : & CmpOp ) {
4194+ use bytecode:: ComparisonOperator :: * ;
4195+ match op {
4196+ CmpOp :: Eq => emit ! ( self , Instruction :: CompareOperation { op: Equal } ) ,
4197+ CmpOp :: NotEq => emit ! ( self , Instruction :: CompareOperation { op: NotEqual } ) ,
4198+ CmpOp :: Lt => emit ! ( self , Instruction :: CompareOperation { op: Less } ) ,
4199+ CmpOp :: LtE => emit ! ( self , Instruction :: CompareOperation { op: LessOrEqual } ) ,
4200+ CmpOp :: Gt => emit ! ( self , Instruction :: CompareOperation { op: Greater } ) ,
4201+ CmpOp :: GtE => {
4202+ emit ! ( self , Instruction :: CompareOperation { op: GreaterOrEqual } )
4203+ }
4204+ CmpOp :: In => emit ! ( self , Instruction :: ContainsOp ( Invert :: No ) ) ,
4205+ CmpOp :: NotIn => emit ! ( self , Instruction :: ContainsOp ( Invert :: Yes ) ) ,
4206+ CmpOp :: Is => emit ! ( self , Instruction :: IsOp ( Invert :: No ) ) ,
4207+ CmpOp :: IsNot => emit ! ( self , Instruction :: IsOp ( Invert :: Yes ) ) ,
4208+ }
4209+ }
4210+
4211+ /// Compile a chained comparison.
4212+ ///
4213+ /// ```py
4214+ /// a == b == c == d
4215+ /// ```
4216+ ///
4217+ /// Will compile into (pseudo code):
4218+ ///
4219+ /// ```py
4220+ /// result = a == b
4221+ /// if result:
4222+ /// result = b == c
4223+ /// if result:
4224+ /// result = c == d
4225+ /// ```
4226+ ///
4227+ /// # See Also
4228+ /// - [CPython `compiler_compare`](https://github.com/python/cpython/blob/627894459a84be3488a1789919679c997056a03c/Python/compile.c#L4678-L4717)
4229+ fn compile_compare (
41914230 & mut self ,
41924231 left : & Expr ,
41934232 ops : & [ CmpOp ] ,
4194- exprs : & [ Expr ] ,
4233+ comparators : & [ Expr ] ,
41954234 ) -> CompileResult < ( ) > {
4196- assert ! ( !ops. is_empty( ) ) ;
4197- assert_eq ! ( exprs. len( ) , ops. len( ) ) ;
41984235 let ( last_op, mid_ops) = ops. split_last ( ) . unwrap ( ) ;
4199- let ( last_val, mid_exprs) = exprs. split_last ( ) . unwrap ( ) ;
4200-
4201- use bytecode:: ComparisonOperator :: * ;
4202- let compile_cmpop = |c : & mut Self , op : & CmpOp | match op {
4203- CmpOp :: Eq => emit ! ( c, Instruction :: CompareOperation { op: Equal } ) ,
4204- CmpOp :: NotEq => emit ! ( c, Instruction :: CompareOperation { op: NotEqual } ) ,
4205- CmpOp :: Lt => emit ! ( c, Instruction :: CompareOperation { op: Less } ) ,
4206- CmpOp :: LtE => emit ! ( c, Instruction :: CompareOperation { op: LessOrEqual } ) ,
4207- CmpOp :: Gt => emit ! ( c, Instruction :: CompareOperation { op: Greater } ) ,
4208- CmpOp :: GtE => {
4209- emit ! ( c, Instruction :: CompareOperation { op: GreaterOrEqual } )
4210- }
4211- CmpOp :: In => emit ! ( c, Instruction :: ContainsOp ( Invert :: No ) ) ,
4212- CmpOp :: NotIn => emit ! ( c, Instruction :: ContainsOp ( Invert :: Yes ) ) ,
4213- CmpOp :: Is => emit ! ( c, Instruction :: IsOp ( Invert :: No ) ) ,
4214- CmpOp :: IsNot => emit ! ( c, Instruction :: IsOp ( Invert :: Yes ) ) ,
4215- } ;
4216-
4217- // a == b == c == d
4218- // compile into (pseudo code):
4219- // result = a == b
4220- // if result:
4221- // result = b == c
4222- // if result:
4223- // result = c == d
4236+ let ( last_comparator, mid_comparators) = comparators. split_last ( ) . unwrap ( ) ;
42244237
42254238 // initialize lhs outside of loop
42264239 self . compile_expression ( left) ?;
42274240
4228- let end_blocks = if mid_exprs. is_empty ( ) {
4229- None
4230- } else {
4231- let break_block = self . new_block ( ) ;
4232- let after_block = self . new_block ( ) ;
4233- Some ( ( break_block, after_block) )
4234- } ;
4241+ if mid_comparators. is_empty ( ) {
4242+ self . compile_expression ( last_comparator) ?;
4243+ self . compile_addcompare ( last_op) ;
4244+
4245+ return Ok ( ( ) ) ;
4246+ }
4247+
4248+ let cleanup = self . new_block ( ) ;
42354249
42364250 // for all comparisons except the last (as the last one doesn't need a conditional jump)
4237- for ( op, val) in mid_ops. iter ( ) . zip ( mid_exprs) {
4238- self . compile_expression ( val) ?;
4251+ for ( op, comparator) in mid_ops. iter ( ) . zip ( mid_comparators) {
4252+ self . compile_expression ( comparator) ?;
4253+
42394254 // store rhs for the next comparison in chain
42404255 emit ! ( self , Instruction :: Swap { index: 2 } ) ;
4241- emit ! ( self , Instruction :: CopyItem { index: 2_u32 } ) ;
4256+ emit ! ( self , Instruction :: CopyItem { index: 2 } ) ;
42424257
4243- compile_cmpop ( self , op) ;
4258+ self . compile_addcompare ( op) ;
42444259
42454260 // if comparison result is false, we break with this value; if true, try the next one.
4246- if let Some ( ( break_block , _ ) ) = end_blocks {
4247- emit ! (
4248- self ,
4249- Instruction :: JumpIfFalseOrPop {
4250- target : break_block ,
4251- }
4252- ) ;
4253- }
4261+ /*
4262+ emit!(self, Instruction::CopyItem { index: 1 });
4263+ // emit!(self, Instruction::ToBool); // TODO: Uncomment this
4264+ emit!(self, Instruction::PopJumpIfFalse { target: cleanup });
4265+ emit!(self, Instruction::PopTop);
4266+ */
4267+
4268+ emit ! ( self , Instruction :: JumpIfFalseOrPop { target : cleanup } ) ;
42544269 }
42554270
4256- // handle the last comparison
4257- self . compile_expression ( last_val) ?;
4258- compile_cmpop ( self , last_op) ;
4271+ self . compile_expression ( last_comparator) ?;
4272+ self . compile_addcompare ( last_op) ;
42594273
4260- if let Some ( ( break_block, after_block) ) = end_blocks {
4261- emit ! (
4262- self ,
4263- Instruction :: Jump {
4264- target: after_block,
4265- }
4266- ) ;
4267-
4268- // early exit left us with stack: `rhs, comparison_result`. We need to clean up rhs.
4269- self . switch_to_block ( break_block) ;
4270- emit ! ( self , Instruction :: Swap { index: 2 } ) ;
4271- emit ! ( self , Instruction :: PopTop ) ;
4274+ let end = self . new_block ( ) ;
4275+ emit ! ( self , Instruction :: Jump { target: end } ) ;
42724276
4273- self . switch_to_block ( after_block) ;
4274- }
4277+ // early exit left us with stack: `rhs, comparison_result`. We need to clean up rhs.
4278+ self . switch_to_block ( cleanup) ;
4279+ emit ! ( self , Instruction :: Swap { index: 2 } ) ;
4280+ emit ! ( self , Instruction :: PopTop ) ;
42754281
4282+ self . switch_to_block ( end) ;
42764283 Ok ( ( ) )
42774284 }
42784285
@@ -4600,27 +4607,31 @@ impl Compiler {
46004607 let after_block = self . new_block ( ) ;
46014608
46024609 let ( last_value, values) = values. split_last ( ) . unwrap ( ) ;
4610+
46034611 for value in values {
46044612 self . compile_expression ( value) ?;
46054613
4614+ emit ! ( self , Instruction :: CopyItem { index: 1_u32 } ) ;
46064615 match op {
46074616 BoolOp :: And => {
46084617 emit ! (
46094618 self ,
4610- Instruction :: JumpIfFalseOrPop {
4619+ Instruction :: PopJumpIfFalse {
46114620 target: after_block,
46124621 }
46134622 ) ;
46144623 }
46154624 BoolOp :: Or => {
46164625 emit ! (
46174626 self ,
4618- Instruction :: JumpIfTrueOrPop {
4627+ Instruction :: PopJumpIfTrue {
46194628 target: after_block,
46204629 }
46214630 ) ;
46224631 }
46234632 }
4633+
4634+ emit ! ( self , Instruction :: PopTop ) ;
46244635 }
46254636
46264637 // If all values did not qualify, take the value of the last value:
@@ -4697,7 +4708,7 @@ impl Compiler {
46974708 comparators,
46984709 ..
46994710 } ) => {
4700- self . compile_chained_comparison ( left, ops, comparators) ?;
4711+ self . compile_compare ( left, ops, comparators) ?;
47014712 }
47024713 // Expr::Constant(ExprConstant { value, .. }) => {
47034714 // self.emit_load_const(compile_constant(value));
0 commit comments