/// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/> internal override void Emit(CodeGenerator/*!*/ codeGenerator) { Statistics.AST.AddNode("SwitchStmt"); ILEmitter il = codeGenerator.IL; // Note: // SwitchStmt is now implemented in the most general (and unefficient) way. The whole switch // is understood as a series of if-elseif-else statements. Label exit_label = il.DefineLabel(); bool fall_through = false; Label fall_through_label = il.DefineLabel(); Label last_default_label = il.DefineLabel(); DefaultItem last_default = GetLastDefaultItem(); LocalBuilder branch_to_lastdefault = null; if (last_default != null) { branch_to_lastdefault = il.DeclareLocal(Types.Bool[0]); il.LdcI4(0); il.Stloc(branch_to_lastdefault); } codeGenerator.BranchingStack.BeginLoop(exit_label, exit_label, codeGenerator.ExceptionBlockNestingLevel); // marks a sequence point containing the discriminator evaluation: codeGenerator.MarkSequencePoint( switchValue.Position.FirstLine, switchValue.Position.FirstColumn, switchValue.Position.LastLine, switchValue.Position.LastColumn + 1); // Evaluate condition value and store the result into local variable codeGenerator.EmitBoxing(switchValue.Emit(codeGenerator)); LocalBuilder condition_value = il.DeclareLocal(Types.Object[0]); il.Stloc(condition_value); foreach (SwitchItem item in switchItems) { item.MarkSequencePoint(codeGenerator); // switch item is either CaseItem ("case xxx:") or DefaultItem ("default") item: CaseItem case_item = item as CaseItem; if (case_item != null) { Label false_label = il.DefineLabel(); // PhpComparer.Default.CompareEq(<switch expr. value>,<case value>); /*changed to static method*/ //il.Emit(OpCodes.Ldsfld, Fields.PhpComparer_Default); codeGenerator.EmitCompareEq( cg => { cg.IL.Ldloc(condition_value); return PhpTypeCode.Object; }, cg => case_item.EmitCaseValue(cg)); // IF (!STACK) GOTO false_label; il.Emit(OpCodes.Brfalse, false_label); if (fall_through == true) { il.MarkLabel(fall_through_label, true); fall_through = false; } case_item.EmitStatements(codeGenerator); if (fall_through == false) { fall_through_label = il.DefineLabel(); fall_through = true; } il.Emit(OpCodes.Br, fall_through_label); il.MarkLabel(false_label, true); } else { DefaultItem default_item = (DefaultItem)item; // Only the last default branch defined in source code is used. // So skip default while testing "case" items at runtime. Label false_label = il.DefineLabel(); il.Emit(OpCodes.Br, false_label); if (default_item == last_default) { il.MarkLabel(last_default_label, false); } if (fall_through == true) { il.MarkLabel(fall_through_label, true); fall_through = false; } default_item.EmitStatements(codeGenerator); if (fall_through == false) { fall_through_label = il.DefineLabel(); fall_through = true; } il.Emit(OpCodes.Br, fall_through_label); il.MarkLabel(false_label, true); } } // If no case branch matched, branch to last default case if any is defined if (last_default != null) { // marks a sequence point containing the condition evaluation or skip of the default case: codeGenerator.MarkSequencePoint( last_default.Position.FirstLine, last_default.Position.FirstColumn, last_default.Position.LastLine, last_default.Position.LastColumn + 1); Debug.Assert(branch_to_lastdefault != null); Label temp = il.DefineLabel(); // IF (!branch_to_lastdefault) THEN il.Ldloc(branch_to_lastdefault); il.LdcI4(0); il.Emit(OpCodes.Bne_Un, temp); if (true) { // branch_to_lastdefault = TRUE; il.LdcI4(1); il.Stloc(branch_to_lastdefault); // GOTO last_default_label; il.Emit(OpCodes.Br, last_default_label); } il.MarkLabel(temp, true); // END IF; il.ForgetLabel(last_default_label); } if (fall_through == true) { il.MarkLabel(fall_through_label, true); } il.MarkLabel(exit_label); codeGenerator.BranchingStack.EndLoop(); il.ForgetLabel(exit_label); }
/// <summary> /// Emits call to a default comparator method. /// </summary> /// <param name="codeGenerator">A code generator.</param> /// <param name="equality">Whether to emit equality comparison (or generic comparison otherwise).</param> /// <returns>A type code of the result.</returns> private PhpTypeCode EmitComparison(CodeGenerator codeGenerator, bool equality) { PhpTypeCode x, y; // PhpComparer.Default.<CompareEq | Compare>(box left, box right <|, false>); /*changed to static method*/ //codeGenerator.IL.Emit(OpCodes.Ldsfld, Fields.PhpComparer_Default); if (equality) { return codeGenerator.EmitCompareEq(cg => this.leftExpr.Emit(cg), cg => this.rightExpr.Emit(cg)); } else { x = leftExpr.Emit(codeGenerator); if (x == PhpTypeCode.Integer) { y = rightExpr.Emit(codeGenerator); // int, ? if (y == PhpTypeCode.Integer) { // int, int codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_int_int); return PhpTypeCode.Integer; } else { codeGenerator.EmitBoxing(y); // int, object codeGenerator.IL.LdcI4(0); // throws = false codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_int_object_bool); return PhpTypeCode.Integer; } } else { codeGenerator.EmitBoxing(x); y = rightExpr.Emit(codeGenerator); // object, ? if (y == PhpTypeCode.Integer) { // object, int codeGenerator.IL.LdcI4(0); // throws = false codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_object_int_bool); return PhpTypeCode.Integer; } else { codeGenerator.EmitBoxing(y); // object, object codeGenerator.IL.LdcI4(0); // throws = false codeGenerator.IL.Emit(OpCodes.Call, Methods.CompareOp_object_object_bool); return PhpTypeCode.Integer; } } } }