Exemplo n.º 1
0
        /// <summary>
        /// Visit switch-case item.
        /// Case expression and case body.
        /// </summary>
        /// <param name="x"></param>
        virtual public void VisitCaseItem(CaseItem x)
        {
            VisitElement(x.CaseVal);

            VisitSwitchItem(x);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Visit switch-case item.
        /// Case expression and case body.
        /// </summary>
        /// <param name="x"></param>
        virtual public void VisitCaseItem(CaseItem x)
        {
            VisitElement(x.CaseVal);

            VisitSwitchItem(x);
        }
Exemplo n.º 3
0
        /// <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);
        }