Example #1
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);
		}
Example #2
0
		/// <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;
                    }
                }
			}
		}