Esempio n. 1
0
            internal override void Emit(SwitchStmt node, 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(node);
                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(node.SwitchValue.Span);

                // Evaluate condition value and store the result into local variable
                codeGenerator.EmitBoxing(node.SwitchValue.Emit(codeGenerator));
                LocalBuilder condition_value = il.DeclareLocal(Types.Object[0]);

                il.Stloc(condition_value);

                foreach (SwitchItem item in node.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.CaseVal.Emit(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.Span);

                    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);
            }