예제 #1
0
        internal PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator, bool ensureChainWritable)
        {
            codeGenerator.ChainBuilder.Create();

            if (ensureChainWritable)
            {
                codeGenerator.ChainBuilder.EnsureWritable = true;
            }

            try
            {
                return(expression.Emit(codeGenerator));
            }
            finally
            {
                codeGenerator.ChainBuilder.End();
            }
        }
예제 #2
0
        /// <summary>
        /// Emits load of an argument of a concatenation.
        /// </summary>
        private static PhpTypeCode EmitConcatExpressionLoad(CodeGenerator /*!*/ codeGenerator, Expression /*!*/ expression)
        {
            // tries to evaluate the expression:
            if (expression.HasValue)
            {
                if (expression.Value is PhpBytes)
                {
                    codeGenerator.IL.LoadLiteral(expression.Value);
                    return(PhpTypeCode.PhpBytes);
                }
                else
                {
                    // evaluated expression is converted to a string if necessary:
                    codeGenerator.IL.Emit(OpCodes.Ldstr, Convert.ObjectToString(expression.Value));
                    return(PhpTypeCode.String);
                }
            }
            else
            {
                // emits non-evaluable expression:
                PhpTypeCode result = expression.Emit(codeGenerator);

                // the result should be converted to string: (so we know the type for the further analysis)
                if (result != PhpTypeCode.String && // string already
                    result != PhpTypeCode.Object && // object can contain PhpBytes, should be converted just when we know we need string
                    result != PhpTypeCode.PhpBytes  // keep PhpBytes
                    )
                {
                    codeGenerator.EmitBoxing(result);   // in case of value-type
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                    result = PhpTypeCode.String;
                }

                return(result);
            }
        }
예제 #3
0
파일: Chains.cs 프로젝트: dw4dev/Phalanger
		/// <summary>
		/// Emits IL instructions that load the value of an item of given array.
		/// </summary>
		/// <param name="array"><see cref="Expression"/> determining the array.</param>
		/// <param name="index"><see cref="Expression"/> determining the index whose value 
		/// should be obtained from the array.</param>
		/// <param name="kind">A kind of getter.</param>
		/// <remarks>Nothing is supposed on the evaluation stack. The value of the item is left
		/// on the evaluation stack.</remarks>
		public PhpTypeCode EmitGetItem(Expression/*!*/ array, Expression/*!*/ index, Operators.GetItemKinds kind)
		{
			ILEmitter il = codeGenerator.IL;
			
			// array:
			var arrayTypeCode = array.Emit(codeGenerator);

            // ensure the array is writeable is required
            if (EnsureWritable)
                codeGenerator.EmitEnsureWritable(arrayTypeCode);

			// index:
			PhpTypeCode index_type_code = codeGenerator.EmitArrayKey(this, index);

			// kind:
			if (kind == Operators.GetItemKinds.Get && QuietRead)
				kind = Operators.GetItemKinds.QuietGet;
			il.LdcI4((int)kind);

			// CALL Operators.GetItem(<array>, <index>, <kind>)
			codeGenerator.EmitGetItem(index_type_code, index, false);
			return PhpTypeCode.Object;
		}
예제 #4
0
파일: Chains.cs 프로젝트: dw4dev/Phalanger
		public void EmitUnsetItem(Expression array, Expression index)
		{
			// Template:
			//		void UnsetItem(object var,object index)

			array.Emit(codeGenerator);

			Debug.Assert(index != null);

			Create();
			codeGenerator.EmitBoxing(index.Emit(codeGenerator));
			End();

			codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.UnsetItem);
		}
예제 #5
0
        /// <author>Tomas Matousek</author>
        /// <remarks>
        /// Emits the following code:
        /// <code>
        /// IPhpEnumerable enumerable = ARRAY as IPhpEnumerable;
        /// if (enumerable==null)
        /// {
        ///   PhpException.InvalidForeachArgument();
        /// }
        /// else
        /// FOREACH_BEGIN:
        /// {
        ///   IDictionaryEnumerator enumerator = enumerable.GetForeachEnumerator(KEYED,ALIASED,TYPE_HANDLE);
        ///
        ///   goto LOOP_TEST;
        ///   LOOP_BEGIN:
        ///   {
        ///     ASSIGN(value,enumerator.Value);
        ///     ASSIGN(key,enumerator.Key);
        ///
        ///     BODY;
        ///   }
        ///   LOOP_TEST:
        ///   if (enumerator.MoveNext()) goto LOOP_BEGIN;
        /// }
        /// FOREACH_END:
        /// </code>
        /// </remarks>
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override void Emit(CodeGenerator codeGenerator)
        {
            Statistics.AST.AddNode("Loop.Foreach");
            ILEmitter il = codeGenerator.IL;

            Label foreach_end   = il.DefineLabel();
            Label foreach_begin = il.DefineLabel();
            Label loop_begin    = il.DefineLabel();
            Label loop_test     = il.DefineLabel();

            codeGenerator.BranchingStack.BeginLoop(loop_test, foreach_end,
                                                   codeGenerator.ExceptionBlockNestingLevel);

            LocalBuilder enumerable = il.GetTemporaryLocal(typeof(IPhpEnumerable));

            // marks foreach "header" (the first part of the IL code):
            codeGenerator.MarkSequencePoint(
                enumeree.Position.FirstLine,
                enumeree.Position.FirstColumn,
                valueVariable.Position.LastLine,
                valueVariable.Position.LastColumn + 1);

            // enumerable = array as IPhpEnumerable;
            enumeree.Emit(codeGenerator);
            il.Emit(OpCodes.Isinst, typeof(IPhpEnumerable));
            il.Stloc(enumerable);

            // if (enumerable==null)
            il.Ldloc(enumerable);
            il.Emit(OpCodes.Brtrue, foreach_begin);
            {
                // CALL PhpException.InvalidForeachArgument();
                codeGenerator.EmitPhpException(Methods.PhpException.InvalidForeachArgument);
                il.Emit(OpCodes.Br, foreach_end);
            }
            // FOREACH_BEGIN:
            il.MarkLabel(foreach_begin);
            {
                LocalBuilder enumerator = il.GetTemporaryLocal(typeof(System.Collections.IDictionaryEnumerator));

                // enumerator = enumerable.GetForeachEnumerator(KEYED,ALIASED,TYPE_HANDLE);
                il.Ldloc(enumerable);
                il.LoadBool(keyVariable != null);
                il.LoadBool(valueVariable.Alias);
                codeGenerator.EmitLoadClassContext();
                il.Emit(OpCodes.Callvirt, Methods.IPhpEnumerable_GetForeachEnumerator);
                il.Stloc(enumerator);

                // goto LOOP_TEST;
                il.Emit(OpCodes.Br, loop_test);

                // LOOP_BEGIN:
                il.MarkLabel(loop_begin);
                {
                    // enumerator should do dereferencing and deep copying (if applicable):
                    // ASSIGN(value,enumerator.Value);
                    valueVariable.Emit(codeGenerator);
                    il.Ldloc(enumerator);
                    il.Emit(OpCodes.Callvirt, Properties.IDictionaryEnumerator_Value.GetGetMethod());
                    if (valueVariable.Alias)
                    {
                        il.Emit(OpCodes.Castclass, typeof(PhpReference));
                    }
                    valueVariable.EmitAssign(codeGenerator);

                    if (keyVariable != null)
                    {
                        // enumerator should do dereferencing and deep copying (if applicable):
                        // ASSIGN(key,enumerator.Key);
                        keyVariable.Emit(codeGenerator);
                        il.Ldloc(enumerator);
                        il.Emit(OpCodes.Callvirt, Properties.IDictionaryEnumerator_Key.GetGetMethod());
                        keyVariable.EmitAssign(codeGenerator);
                    }

                    // BODY:
                    body.Emit(codeGenerator);
                }
                // LOOP_TEST:
                il.MarkLabel(loop_test);

                // marks foreach "header" (the second part of the code):
                codeGenerator.MarkSequencePoint(
                    enumeree.Position.FirstLine,
                    enumeree.Position.FirstColumn,
                    valueVariable.Position.LastLine,
                    valueVariable.Position.LastColumn + 1);

                // if (enumerator.MoveNext()) goto LOOP_BEGIN;
                il.Ldloc(enumerator);
                il.Emit(OpCodes.Callvirt, Methods.IEnumerator_MoveNext);
                il.Emit(OpCodes.Brtrue, loop_begin);

                //
                il.ReturnTemporaryLocal(enumerator);
            }
            // FOREACH_END:
            il.MarkLabel(foreach_end);

            il.ReturnTemporaryLocal(enumerable);

            codeGenerator.BranchingStack.EndLoop();

            il.ForgetLabel(foreach_end);
            il.ForgetLabel(foreach_begin);
            il.ForgetLabel(loop_begin);
            il.ForgetLabel(loop_test);
        }
예제 #6
0
		internal PhpTypeCode EmitArrayKey(ChainBuilder chain, Expression key)
		{
			PhpTypeCode result;

			if (key != null)
			{
				if (chain != null) chain.Create();
				
                // convert the key into integer if necessary and possible in compile time
                IntStringKey array_key;
                if (key.HasValue() && Convert.ObjectToArrayKey(key.GetValue(), out array_key) && array_key.IsInteger)
                {
                    il.LdcI4(array_key.Integer);
                    result = PhpTypeCode.Integer;
                }
                else
                {
                    // Emit index and box the result
                    switch (result = key.Emit(this))
                    {
                        case PhpTypeCode.Integer:
                            break;

                        case PhpTypeCode.String:
                            break;

                        default:
                            EmitBoxing(result);
                            result = PhpTypeCode.Object;
                            break;
                    }
                }
				
				if (chain != null) chain.End();
			}
			else
				result = PhpTypeCode.Invalid;

			return result;
		}
예제 #7
0
		/// <summary>
		/// Emits IL instructions that convert the top of evaluation stack to a specified type.
		/// </summary>
		/// <remarks>
		/// Emits a call to one of <see cref="PHP.Core.Convert"/> methods to do the conversion.
		/// The method result is left on the evaluation stack.
		/// </remarks>
		internal void EmitConversion(Expression/*!*/ expression, PhpTypeCode dst)
		{
			// expression is evaluable:
			if (expression.HasValue())
			{
				switch (dst)
				{
					case PhpTypeCode.String:
						il.Emit(OpCodes.Ldstr, PHP.Core.Convert.ObjectToString(expression.GetValue()));
						break;

					case PhpTypeCode.Boolean:
                        il.LdcI4(PHP.Core.Convert.ObjectToBoolean(expression.GetValue()) ? 1 : 0);
						break;

					case PhpTypeCode.Integer:
                        il.LdcI4(PHP.Core.Convert.ObjectToInteger(expression.GetValue()));
						break;

					case PhpTypeCode.Double:
                        il.Emit(OpCodes.Ldc_R8, PHP.Core.Convert.ObjectToDouble(expression.GetValue()));
						break;

					case PhpTypeCode.Object:
                        il.LoadLiteral(expression.GetValue());
						break;

					default:
						Debug.Fail("Conversion not implemented.");
						break;
				}
			}
			else
			{
				// emits the expression:
				PhpTypeCode src = expression.Emit(this);

				// emits no conversion if types are the same:
				if (src == dst) return;

				// emits boxing if needed (conversion methods takes object):
				EmitBoxing(src);

				switch (dst)
				{
					case PhpTypeCode.String:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
						break;

					case PhpTypeCode.Boolean:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
						break;

					case PhpTypeCode.Integer:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
						break;

					case PhpTypeCode.Double:
						il.Emit(OpCodes.Call, Methods.Convert.ObjectToDouble);
						break;

					case PhpTypeCode.Object:
						// nop //
						break;

					default:
						Debug.Fail("Conversion is not implemented.");
						break;
				}
			}
		}
예제 #8
0
		/// <summary>
		/// Emits IL instructions to process the <B>echo</B> and <B>print</B> commands.
		/// </summary>
		/// <param name="parameter">Expression to be sent to output.</param>
		public void EmitEcho(Expression parameter)
		{
			// Template:
			//	context.Echo(value);

			ConcatEx concat;
			//BinaryEx binary_expr;

			if ((concat = parameter as ConcatEx) != null && concat.Expressions.Length > 1)
			{
                //foreach (Expression expr in concat.Expressions)
                //{
                //    EmitLoadScriptContext();
                //    EmitEchoCall(expr.Emit(this));
                //}

				// obsolete: (but expressions must be first emitted and processed, then echoed)
                // array = new object[] { expr1, expr2, ..., exprn };
                //LocalBuilder array = EmitObjectArrayPopulation(concat.Expressions, null);

                //// context.Echo(array);
                //EmitLoadScriptContext();
                //il.Ldloc(array);
                //il.Emit(OpCodes.Call, Methods.ScriptContext.Echo.ObjectArray);

                EmitEcho(concat.Expressions);
			}
            //// obsolete: wrong order of expressions execution (evaluate first, then echo!)
            //else if ((binary_expr = parameter as BinaryEx) != null && binary_expr.Operation == Operations.Concat)
            //{
            //    // context.Echo(<left>)
            //    EmitLoadScriptContext();
            //    EmitEchoCall(binary_expr.LeftExpr.Emit(this));

            //    // context.Echo(<right>)
            //    EmitLoadScriptContext();
            //    EmitEchoCall(binary_expr.RightExpr.Emit(this));
            //}
			else
			{
                var typecode = parameter.Emit(this);
				EmitLoadScriptContext();
                // CALL ScriptContext.Echo(<parameter>, <context>)
                EmitEchoStaticCall(typecode);
			}
		}
예제 #9
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);
        }
예제 #10
0
 internal PhpTypeCode EmitCaseValue(CodeGenerator codeGenerator)
 {
     return(caseVal.Emit(codeGenerator));
 }
예제 #11
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Debug.Assert(access == AccessType.Read || access == AccessType.None);
            Statistics.AST.AddNode("UnaryEx");

            ILEmitter il = codeGenerator.IL;

            PhpTypeCode returned_typecode, o_typecode;

            switch (operation)
            {
            case Operations.AtSign:                     // special arrangement
                // Template:
                //		context.DisableErrorReporting();
                //		s;
                //		context.EnableErrorReporting();
                codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Call, Methods.ScriptContext.DisableErrorReporting);
                returned_typecode = expr.Emit(codeGenerator);
                codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Call, Methods.ScriptContext.EnableErrorReporting);
                break;

            case Operations.BitNegation:
                //Template: "~x" Operators.BitNot(x)
                codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
                il.Emit(OpCodes.Call, Methods.Operators.BitNot);
                returned_typecode = PhpTypeCode.Object;
                break;

            case Operations.Clone:
                // Template: clone x        Operators.Clone(x,DTypeDesc,ScriptContext)
                codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
                codeGenerator.EmitLoadClassContext();
                codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Call, Methods.Operators.Clone);
                returned_typecode = PhpTypeCode.Object;
                break;

            case Operations.LogicNegation:
                //Template: "!x"  !Convert.ObjectToBoolean(x);
                if (((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.Boolean))
                {
                    codeGenerator.EmitBoxing(returned_typecode);
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                }
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Ceq);
                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.Minus:
                //Template: "-x"  Operators.Minus(x)
                switch (o_typecode = expr.Emit(codeGenerator))
                {
                case PhpTypeCode.Double:
                    il.Emit(OpCodes.Neg);
                    returned_typecode = PhpTypeCode.Double;
                    break;

                default:
                    codeGenerator.EmitBoxing(o_typecode);
                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Minus);
                    break;
                }
                break;

            case Operations.ObjectCast:
                //Template: "(object)x"   Convert.ObjectToDObject(x,ScriptContext)
                codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
                codeGenerator.EmitLoadScriptContext();
                il.Emit(OpCodes.Call, Methods.Convert.ObjectToDObject);
                returned_typecode = PhpTypeCode.Object;
                break;

            case Operations.Plus:
                //Template: "+x"  Operators.Plus(x)
                codeGenerator.EmitBoxing(expr.Emit(codeGenerator));
                il.Emit(OpCodes.Call, Methods.Operators.Plus);
                returned_typecode = PhpTypeCode.Object;
                break;

            case Operations.Print:
                codeGenerator.EmitEcho(this.expr);
                // Always returns 1
                il.Emit(OpCodes.Ldc_I4_1);
                returned_typecode = PhpTypeCode.Integer;
                break;

            case Operations.BoolCast:
                //Template: "(bool)x"     Convert.ObjectToBoolean(x)
                if (((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.Boolean))
                {
                    codeGenerator.EmitBoxing(returned_typecode);
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                    returned_typecode = PhpTypeCode.Boolean;
                }
                break;

            case Operations.Int8Cast:
            case Operations.Int16Cast:
            case Operations.Int32Cast:
            case Operations.UInt8Cast:
            case Operations.UInt16Cast:
                // CALL int Convert.ObjectToInteger(<expr>)
                o_typecode = expr.Emit(codeGenerator);
                if (o_typecode != PhpTypeCode.Integer)
                {
                    codeGenerator.EmitBoxing(o_typecode);
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToInteger);
                }

                // CONV for unsigned:
                switch (operation)
                {
                case Operations.UInt8Cast: il.Emit(OpCodes.Conv_U1); il.Emit(OpCodes.Conv_I4); break;

                case Operations.UInt16Cast: il.Emit(OpCodes.Conv_U2); il.Emit(OpCodes.Conv_I4); break;
                }

                returned_typecode = PhpTypeCode.Integer;
                break;

            case Operations.UInt64Cast:
            case Operations.UInt32Cast:
            case Operations.Int64Cast:
                // CALL long Convert.ObjectToLongInteger(<expr>)
                o_typecode = expr.Emit(codeGenerator);
                if (o_typecode != PhpTypeCode.LongInteger)
                {
                    codeGenerator.EmitBoxing(o_typecode);
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToLongInteger);
                }

                // CONV for unsigned:
                switch (operation)
                {
                case Operations.UInt32Cast: il.Emit(OpCodes.Conv_U4); il.Emit(OpCodes.Conv_I8); break;

                case Operations.UInt64Cast: il.Emit(OpCodes.Conv_U8); il.Emit(OpCodes.Conv_I8); break;
                }

                returned_typecode = PhpTypeCode.LongInteger;
                break;

            case Operations.DecimalCast:
            case Operations.DoubleCast:
            case Operations.FloatCast:
                // CALL double Convert.ObjectToDouble(<expr>)
                o_typecode = expr.Emit(codeGenerator);
                if (o_typecode != PhpTypeCode.Double)
                {
                    codeGenerator.EmitBoxing(o_typecode);
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToDouble);
                }
                returned_typecode = PhpTypeCode.Double;
                break;

            case Operations.UnicodeCast:                     // TODO
            case Operations.StringCast:
                if ((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.String)
                {
                    codeGenerator.EmitBoxing(returned_typecode);
                    //codeGenerator.EmitLoadClassContext();
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                    returned_typecode = PhpTypeCode.String;
                }
                break;

            case Operations.BinaryCast:
                if ((returned_typecode = expr.Emit(codeGenerator)) != PhpTypeCode.PhpBytes)
                {
                    codeGenerator.EmitBoxing(returned_typecode);
                    //codeGenerator.EmitLoadClassContext();
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpBytes);
                    returned_typecode = PhpTypeCode.PhpBytes;
                }
                break;

            case Operations.ArrayCast:
                //Template: "(array)x"   Convert.ObjectToArray(x)
                o_typecode = expr.Emit(codeGenerator);
                if (o_typecode != PhpTypeCode.PhpArray)
                {
                    codeGenerator.EmitBoxing(o_typecode);
                    il.Emit(OpCodes.Call, Methods.Convert.ObjectToPhpArray);
                }
                returned_typecode = PhpTypeCode.PhpArray;
                break;

            case Operations.UnsetCast:
                // Template: "(unset)x"  null
                il.Emit(OpCodes.Ldnull);
                returned_typecode = PhpTypeCode.Object;
                break;

            default:
                Debug.Assert(false, "illegal type of operation!");
                returned_typecode = PhpTypeCode.Void;
                break;
            }

            switch (access)
            {
            case AccessType.Read:
                // do nothing
                break;

            case AccessType.None:
                // pop operation's result value from stack
                if (returned_typecode != PhpTypeCode.Void)
                {
                    il.Emit(OpCodes.Pop);
                }
                return(PhpTypeCode.Void);
            }

            return(returned_typecode);
        }
예제 #12
0
        internal void Emit(CodeGenerator codeGenerator)
        {
            ILEmitter il = codeGenerator.IL;
            string    id = codeGenerator.GetLocationId();

            if (id == null)
            {
                // we are in global code -> just assign the iniVal to the variable
                variable.Emit(codeGenerator);

                if (initializer != null)
                {
                    codeGenerator.EmitBoxing(initializer.Emit(codeGenerator));
                    il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
                }
                else
                {
                    il.Emit(OpCodes.Newobj, Constructors.PhpReference_Void);
                }

                variable.EmitAssign(codeGenerator);
            }
            else
            {
                // (J): cache the integer index of static local variable to access its value fast from within the array

                // unique static local variable string ID
                id = String.Format("{0}${1}${2}${3}", id, variable.VarName, position.FirstLine, position.FirstColumn);

                // create static field for static local index: private static int <id>;
                var type = codeGenerator.IL.TypeBuilder;
                Debug.Assert(type != null, "The method does not have declaring type! (global code in pure mode?)");
                var field_id = type.DefineField(id, Types.Int[0], System.Reflection.FieldAttributes.Private | System.Reflection.FieldAttributes.Static);

                // we are in a function or method -> try to retrieve the local value from ScriptContext
                variable.Emit(codeGenerator);

                // <context>.GetStaticLocal( <field> )
                codeGenerator.EmitLoadScriptContext();                           // <context>
                il.Emit(OpCodes.Ldsfld, field_id);                               // <field>
                il.Emit(OpCodes.Callvirt, Methods.ScriptContext.GetStaticLocal); // GetStaticLocal
                il.Emit(OpCodes.Dup);

                // ?? <context>.AddStaticLocal( <field> != 0 ? <field> : ( <field> = ScriptContext.GetStaticLocalId(<id>) ), <initializer> )
                if (true)
                {
                    // if (GetStaticLocal(<field>) == null)
                    Label local_initialized = il.DefineLabel();
                    il.Emit(OpCodes.Brtrue /*not .S, initializer can emit really long code*/, local_initialized);

                    il.Emit(OpCodes.Pop);

                    // <field> != 0 ? <field> : ( <field> = ScriptContext.GetStaticLocalId(<id>) )
                    il.Emit(OpCodes.Ldsfld, field_id);         // <field>

                    if (true)
                    {
                        // if (<field> == 0)
                        Label id_initialized = il.DefineLabel();
                        il.Emit(OpCodes.Brtrue_S, id_initialized);

                        // <field> = GetStaticLocalId( <id> )
                        il.Emit(OpCodes.Ldstr, id);
                        il.Emit(OpCodes.Call, Methods.ScriptContext.GetStaticLocalId);
                        il.Emit(OpCodes.Stsfld, field_id);

                        il.MarkLabel(id_initialized);
                    }

                    // <context>.AddStaticLocal(<field>,<initialize>)
                    codeGenerator.EmitLoadScriptContext();  // <context>
                    il.Emit(OpCodes.Ldsfld, field_id);      // <field>
                    if (initializer != null)
                    {
                        codeGenerator.EmitBoxing(initializer.Emit(codeGenerator));                      // <initializer>
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldnull);
                    }
                    il.Emit(OpCodes.Callvirt, Methods.ScriptContext.AddStaticLocal);    // AddStaticLocal

                    //
                    il.MarkLabel(local_initialized);
                }

                // (J) Following code used Dictionary. It was replaced by the code above.

                /*
                 * codeGenerator.EmitLoadScriptContext();
                 *              il.Emit(OpCodes.Ldstr, id);
                 *              il.Emit(OpCodes.Call, Methods.ScriptContext.GetStaticLocal);
                 *
                 *              Label reference_gotten = codeGenerator.IL.DefineLabel();
                 *              il.Emit(OpCodes.Dup);
                 *              il.Emit(OpCodes.Brtrue, reference_gotten);
                 *              il.Emit(OpCodes.Pop);
                 *
                 *              // this is the first time execution reach the statement for current request -> initialize the local
                 *              codeGenerator.EmitLoadScriptContext();
                 *              il.Emit(OpCodes.Ldstr, id);
                 *
                 *              if (initializer != null)
                 *                      codeGenerator.EmitBoxing(initializer.Emit(codeGenerator));
                 *              else
                 *                      il.Emit(OpCodes.Ldnull);
                 *
                 *              il.Emit(OpCodes.Call, Methods.ScriptContext.AddStaticLocal);
                 *
                 *              // assign the resulting PhpReference into the variable
                 *              il.MarkLabel(reference_gotten, true);
                 */

                variable.EmitAssign(codeGenerator);
            }
        }
예제 #13
0
        /// <remarks>
        /// Nothing is expected at the evaluation stack. If AST node is read by other node,
        /// the operation result is left at the stack, otherwise it is poped from the stack.
        /// </remarks>
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator codeGenerator)
        {
            Debug.Assert(access == AccessType.None || access == AccessType.Read);
            Statistics.AST.AddNode("BinaryEx");

            PhpTypeCode returned_typecode;
            PhpTypeCode lo_typecode;
            PhpTypeCode ro_typecode;

            switch (operation)
            {
                #region Arithmetic Operations

            case Operations.Add:
                // Template: x + y : Operators.Add(x,y) [overloads]

                switch (lo_typecode = leftExpr.Emit(codeGenerator))
                {
                case PhpTypeCode.Double:
                    switch (ro_typecode = rightExpr.Emit(codeGenerator))
                    {
                    case PhpTypeCode.Integer:
                        codeGenerator.IL.Emit(OpCodes.Conv_R8);
                        goto case PhpTypeCode.Double;               // fallback:

                    case PhpTypeCode.Double:
                        codeGenerator.IL.Emit(OpCodes.Add);
                        returned_typecode = PhpTypeCode.Double;
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Double_Object);
                        break;
                    }

                    break;

                default:
                    codeGenerator.EmitBoxing(lo_typecode);
                    ro_typecode = rightExpr.Emit(codeGenerator);

                    switch (ro_typecode)
                    {
                    case PhpTypeCode.Integer:
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Int32);
                        break;

                    case PhpTypeCode.Double:
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Double);
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Add.Object_Object);
                        break;
                    }
                    break;
                }
                break;

            case Operations.Sub:
                //Template: "x - y"        Operators.Subtract(x,y) [overloads]
                lo_typecode = leftExpr.Emit(codeGenerator);
                switch (lo_typecode)
                {
                case PhpTypeCode.Integer:
                    codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Int32_Object);
                    break;

                case PhpTypeCode.Double:
                    switch (ro_typecode = rightExpr.Emit(codeGenerator))
                    {
                    case PhpTypeCode.Integer:
                        codeGenerator.IL.Emit(OpCodes.Conv_R8);
                        goto case PhpTypeCode.Double;               // fallback:

                    case PhpTypeCode.Double:
                        codeGenerator.IL.Emit(OpCodes.Sub);
                        returned_typecode = PhpTypeCode.Double;
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Double_Object);
                        break;
                    }

                    break;

                default:
                    codeGenerator.EmitBoxing(lo_typecode);
                    ro_typecode = rightExpr.Emit(codeGenerator);
                    if (ro_typecode == PhpTypeCode.Integer)
                    {
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Int);
                    }
                    else
                    {
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Subtract.Object_Object);
                    }
                    break;
                }
                break;

            case Operations.Div:
                //Template: "x / y"   Operators.Divide(x,y)

                lo_typecode = leftExpr.Emit(codeGenerator);
                switch (lo_typecode)
                {
                case PhpTypeCode.Integer:
                    codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Int32_Object);
                    break;

                case PhpTypeCode.Double:
                    switch (ro_typecode = rightExpr.Emit(codeGenerator))
                    {
                    case PhpTypeCode.Double:
                        codeGenerator.IL.Emit(OpCodes.Div);
                        returned_typecode = PhpTypeCode.Double;
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Double_Object);
                        break;
                    }
                    break;

                default:
                    codeGenerator.EmitBoxing(lo_typecode);
                    ro_typecode = rightExpr.Emit(codeGenerator);

                    switch (ro_typecode)
                    {
                    case PhpTypeCode.Integer:
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Int32);
                        break;

                    case PhpTypeCode.Double:
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Double);
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Divide.Object_Object);
                        break;
                    }
                    break;
                }
                break;

            case Operations.Mul:
                switch (lo_typecode = leftExpr.Emit(codeGenerator))
                {
                case PhpTypeCode.Double:
                    // "x * (double)y"
                    // Operators.Multiply((double)x,(object)y)

                    switch (ro_typecode = rightExpr.Emit(codeGenerator))
                    {
                    case PhpTypeCode.Integer:
                        codeGenerator.IL.Emit(OpCodes.Conv_R8);
                        goto case PhpTypeCode.Double;               // fallback:

                    case PhpTypeCode.Double:
                        codeGenerator.IL.Emit(OpCodes.Mul);
                        returned_typecode = PhpTypeCode.Double;
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Double_Object);
                        break;
                    }

                    break;

                default:
                    //Template: "x * y"  Operators.Multiply((object)x,y) [overloads]
                    codeGenerator.EmitBoxing(lo_typecode);

                    ro_typecode = rightExpr.Emit(codeGenerator);
                    switch (ro_typecode)
                    {
                    case PhpTypeCode.Integer:
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Int32);
                        break;

                    case PhpTypeCode.Double:
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Double);
                        break;

                    default:
                        codeGenerator.EmitBoxing(ro_typecode);
                        returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Multiply.Object_Object);
                        break;
                    }
                    break;
                }
                break;

            case Operations.Mod:
                //Template: "x % y"        Operators.Remainder(x,y)
                codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
                ro_typecode = rightExpr.Emit(codeGenerator);
                switch (ro_typecode)
                {
                case PhpTypeCode.Integer:
                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Int32);
                    break;

                default:
                    codeGenerator.EmitBoxing(ro_typecode);
                    returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.Remainder.Object_Object);
                    break;
                }
                break;

            case Operations.ShiftLeft:

                // LOAD Operators.ShiftLeft(box left, box right);
                codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
                codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftLeft);
                break;

            case Operations.ShiftRight:

                // LOAD Operators.ShiftRight(box left, box right);
                codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
                codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                returned_typecode = codeGenerator.EmitMethodCall(Methods.Operators.ShiftRight);
                break;

                #endregion

                #region Boolean and Bitwise Operations

            case Operations.And:
                returned_typecode = EmitBinaryBooleanOperation(codeGenerator, true);
                break;

            case Operations.Or:
                returned_typecode = EmitBinaryBooleanOperation(codeGenerator, false);
                break;

            case Operations.Xor:

                // LOAD <(bool) leftSon> == <(bool) rightSon>;
                codeGenerator.EmitConversion(leftExpr, PhpTypeCode.Boolean);
                codeGenerator.EmitConversion(rightExpr, PhpTypeCode.Boolean);
                codeGenerator.IL.Emit(OpCodes.Ceq);

                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Ceq);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.BitAnd:
                returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.And);
                break;

            case Operations.BitOr:
                returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Or);
                break;

            case Operations.BitXor:
                returned_typecode = EmitBitOperation(codeGenerator, Operators.BitOp.Xor);
                break;

                #endregion

                #region Comparing Operations

            case Operations.Equal:

                // LOAD PhpComparer.Default.CompareEq
                returned_typecode = EmitComparison(codeGenerator, true);
                break;

            case Operations.NotEqual:

                // LOAD PhpComparer.Default.CompareEq == false
                EmitComparison(codeGenerator, true);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Ceq);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.GreaterThan:

                // LOAD PhpComparer.Default.Compare > 0;
                EmitComparison(codeGenerator, false);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Cgt);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.LessThan:

                // LOAD PhpComparer.Default.Compare < 0;
                EmitComparison(codeGenerator, false);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Clt);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.GreaterThanOrEqual:

                // LOAD PhpComparer.Default.Compare >= 0 (not less than)
                EmitComparison(codeGenerator, false);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Clt);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Ceq);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.LessThanOrEqual:

                // LOAD PhpComparer.Default.Compare >= 0 (not greater than)
                EmitComparison(codeGenerator, false);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Cgt);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Ceq);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.Identical:

                // LOAD Operators.StrictEquality(box left,box right);
                codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
                codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality);

                returned_typecode = PhpTypeCode.Boolean;
                break;

            case Operations.NotIdentical:

                // LOAD Operators.StrictEquality(box left,box right) == false;
                codeGenerator.EmitBoxing(leftExpr.Emit(codeGenerator));
                codeGenerator.EmitBoxing(rightExpr.Emit(codeGenerator));
                codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEquality);
                codeGenerator.IL.Emit(OpCodes.Ldc_I4_0);
                codeGenerator.IL.Emit(OpCodes.Ceq);

                returned_typecode = PhpTypeCode.Boolean;
                break;

                #endregion

            case Operations.Concat:
                returned_typecode = ConcatEx.EmitConcat(codeGenerator, leftExpr, rightExpr);
                break;

            default:
                throw null;
            }

            switch (access)
            {
            case AccessType.Read:
                // Result is read, do nothing.
                break;

            case AccessType.None:
                // Result is not read, pop the result
                codeGenerator.IL.Emit(OpCodes.Pop);
                returned_typecode = PhpTypeCode.Void;
                break;
            }

            return(returned_typecode);
        }
예제 #14
0
파일: Chains.cs 프로젝트: dw4dev/Phalanger
		/// <summary>
		/// Emits IL instructions that ensure that a static field is of <see cref="PhpObject"/> or <see cref="PhpArray"/>
		/// type. Handles the case when field name is unknown at compile time (see <see cref="AST.IndirectStFldUse"/>).
		/// </summary>
        /// <param name="typeRef">The class name (identifier index).</param>
		/// <param name="propertyName">The property name.</param>
		/// <param name="propertyNameExpr">The expression that evaluates to property name.</param>
		/// <param name="ensureArray">Whether to ensure that static field is an array (or an object).</param>
		/// <remarks>
		/// Nothing is expected on the evaluation stack. A <see cref="PhpArray"/> or <see cref="DObject"/> is left on the
		/// evaluation stack.
		/// </remarks>
		public PhpTypeCode EmitEnsureStaticProperty(TypeRef typeRef, VariableName? propertyName,
			Expression propertyNameExpr, bool ensureArray)
		{
			Debug.Assert(propertyName != null ^ propertyNameExpr != null);

			ResolveTypeFlags flags = ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors;

			// LOAD Operators.EnsureStaticFieldIs[Object|Array](<type desc>, <field name>, <type desc>, <context>)
            typeRef.EmitLoadTypeDesc(codeGenerator, flags);

			if (propertyNameExpr != null)
				codeGenerator.EmitBoxing(propertyNameExpr.Emit(codeGenerator));
			else
				codeGenerator.IL.Emit(OpCodes.Ldstr, propertyName.Value.ToString());

			codeGenerator.EmitLoadClassContext();
			codeGenerator.EmitLoadScriptContext();

			if (ensureArray)
				codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.EnsureStaticPropertyIsArray);
			else
				codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.EnsureStaticPropertyIsObject);

			EmitErrorCheck(ensureArray);
			return (ensureArray) ? PhpTypeCode.PhpArray : PhpTypeCode.DObject;
		}
예제 #15
0
파일: AssignEx.cs 프로젝트: ikvm/Phalanger
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override PhpTypeCode Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Debug.Assert(access == AccessType.None || access == AccessType.Read || access == AccessType.ReadRef ||
                         access == AccessType.ReadUnknown);
            Statistics.AST.AddNode("Assign.Ref");

            //ChainBuilder.RefErrorLabelInfo labelInfo;
            ILEmitter il = codeGenerator.IL;

            // Strict Standards: Only variables should be assigned by reference

            /*if (rvalue is FunctionCall)//TODO: only variables (but also variables given by function call return value!)
             * {
             *  il.LdcI4( (int)PhpError.Strict );
             *  il.Emit(OpCodes.Ldstr, CoreResources.GetString("only_vars_assign ed_by_ref"));
             *  codeGenerator.EmitPhpException(il,Methods.PhpException.Throw);
             * }*/

            // PREPARE:
            codeGenerator.ChainBuilder.Create();
            lvalue.Emit(codeGenerator);

            // LOAD <right hand side>:
            codeGenerator.ChainBuilder.Create();
            rvalue.Emit(codeGenerator);
            codeGenerator.ChainBuilder.End();

            PhpTypeCode result;

            // Dup source value if assignment is read
            switch (access)
            {
            case AccessType.Read:
            case AccessType.ReadUnknown:
            case AccessType.ReadRef:
            {
                // DUP
                il.Emit(OpCodes.Dup);

                // STORE tmp
                il.Stloc(il.GetAssignmentLocalRef());

                // STORE prepared,result
                lvalue.EmitAssign(codeGenerator);

                // LOAD DEREF tmp
                il.Ldloc(il.GetAssignmentLocalRef());

                if (access == AccessType.Read)
                {
                    il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                    result = PhpTypeCode.Object;
                }
                else
                {
                    result = PhpTypeCode.PhpReference;
                }
                break;
            }

            case AccessType.None:
                lvalue.EmitAssign(codeGenerator);
                result = PhpTypeCode.Void;
                break;

            default:
                Debug.Fail();
                result = PhpTypeCode.Invalid;
                break;
            }
            codeGenerator.ChainBuilder.End();

            return(result);
        }
예제 #16
0
파일: Chains.cs 프로젝트: dw4dev/Phalanger
		/// <summary>
		/// Emits IL instructions that ensure that the specified item of specified array is of
		/// type <see cref="PhpArray"/>.
		/// </summary>
		/// <param name="array">Array which item is examined.</param>
		/// <param name="index">Index determining the item which should be examined (can be <B>null</B>).</param>
		/// <param name="ensureArray">Whether to ensure that static field is an array (or an object).</param>
		/// <remarks>
		/// This method is used in operators chains. Nothing is expected on the evaluation stack. 
		/// If the item is of type <see cref="PhpArray"/> and <see cref="PhpObject"/> (respectively) 
		/// it is left on the evaluation stack. Otherwise the control is transfered to the end of chain.
		/// </remarks>
		public PhpTypeCode EmitEnsureItem(Expression/*!*/ array, Expression index, bool ensureArray)
		{
			if (!ensureArray) Lengthen();

			array.Emit(codeGenerator);

			if (index != null)
			{
				// keyed item:
				Create();
				codeGenerator.EmitBoxing(index.Emit(codeGenerator));
				End();

				if (ensureArray)
				{
					codeGenerator.IL.Emit(OpCodes.Callvirt, Methods.PhpArray.EnsureItemIsArray_Object);
				}
				else
				{
					codeGenerator.EmitLoadScriptContext();
					codeGenerator.IL.Emit(OpCodes.Callvirt, Methods.PhpArray.EnsureItemIsObject_Object);
				}
			}
			else
			{
				// key-less item:
				if (ensureArray)
				{
					codeGenerator.IL.Emit(OpCodes.Callvirt, Methods.PhpArray.EnsureItemIsArray);
				}
				else
				{
					codeGenerator.EmitLoadScriptContext();
					codeGenerator.IL.Emit(OpCodes.Callvirt, Methods.PhpArray.EnsureItemIsObject);
				}
			}
			EmitErrorCheck(ensureArray);
			return (ensureArray) ? PhpTypeCode.PhpArray : PhpTypeCode.DObject;
		}
예제 #17
0
        /// <summary>
        /// Emit the target of instance method invocation.
        /// </summary>
        /// <param name="cg"></param>
        /// <param name="targetExpr"></param>
        private static void EmitMethodTargetExpr(PHP.Core.CodeGenerator/*!*/cg, Expression/*!*/targetExpr)
        {
            // start a new operators chain (as the rest of chain is read)
            cg.ChainBuilder.Create();
            cg.ChainBuilder.Begin();
            cg.ChainBuilder.Lengthen(); // for hop over ->

            // prepare for operator invocation
            cg.EmitBoxing(targetExpr.Emit(cg));
            cg.ChainBuilder.End();
        }
예제 #18
0
		/// <summary>
		/// Emits a call to a routine with specified name using an operator.
		/// </summary>
        internal PhpTypeCode EmitRoutineOperatorCall(DType type, Expression targetExpr,
            string routineFullName, string fallbackRoutineFullname, Expression routineNameExpr, CallSignature callSignature, AccessType access)
        {
            Debug.Assert(routineFullName != null ^ routineNameExpr != null);

            MethodInfo operator_method;
            PhpTypeCode return_type_code;

            // (J) use call sites to call the method:
            if (targetExpr != null /*|| type != null*/)
            {
                Debug.Assert(fallbackRoutineFullname == null);

                return this.CallSitesBuilder.EmitMethodCall(this, CallSitesBuilder.AccessToReturnType(access), targetExpr, type, routineFullName, routineNameExpr, callSignature);
            }
            else if (targetExpr != null)
            {
                Debug.Assert(fallbackRoutineFullname == null);

                // LOAD Operators.InvokeMethod(<target>, <method name>, <type desc>, <context>);

                // start a new operators chain (as the rest of chain is read)
                this.ChainBuilder.Create();
                this.ChainBuilder.Begin();
                this.ChainBuilder.Lengthen(); // for hop over ->

                // prepare for operator invocation
                this.EmitBoxing(targetExpr.Emit(this));
                this.ChainBuilder.End();

                this.EmitName(routineFullName, routineNameExpr, true);
                this.EmitLoadClassContext();
                this.EmitLoadScriptContext();

                if (routineFullName != null)
                    operator_method = Methods.Operators.InvokeMethodStr;
                else
                    operator_method = Methods.Operators.InvokeMethodObj;

                return_type_code = PhpTypeCode.PhpReference;
            }
            else if (type != null)
            {
                Debug.Assert(fallbackRoutineFullname == null);

                // LOAD Operators.InvokeStaticMethod(<type desc>, <method name>, <self>, <type desc>, context);
                type.EmitLoadTypeDesc(this, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);

                this.EmitName(routineFullName, routineNameExpr, true);

                this.EmitLoadSelf();
                this.EmitLoadClassContext();
                this.EmitLoadScriptContext();

                operator_method = Methods.Operators.InvokeStaticMethod;
                return_type_code = PhpTypeCode.PhpReference;
            }
            else
            {
                Debug.Assert(routineNameExpr == null || fallbackRoutineFullname == null);   // (routineNameExpr != null) => (fallbackRoutineFullName == null)

                // DRoutineDesc <callHint>;
                FieldInfo hintField = this.CallSitesBuilder.DefineField(
                    "<callHint>'" + (routineFullName ?? "indirect"),
                    typeof(PHP.Core.Reflection.DRoutineDesc),
                    FieldAttributes.Static | FieldAttributes.Assembly);

                // LOAD ScriptContext.Call{|Void|Value}(<local variables>, <naming context>, <function name>, ref <hint>, context);
                this.EmitLoadRTVariablesTable();
                this.EmitLoadNamingContext();
                this.EmitName(routineFullName, routineNameExpr, true);
                if (fallbackRoutineFullname != null) il.Emit(OpCodes.Ldstr, fallbackRoutineFullname); else il.Emit(OpCodes.Ldnull); // fallback fcn name
                il.Emit(OpCodes.Ldsflda, hintField);
                this.EmitLoadScriptContext();

                // (J) only necessary copying, dereferencing or reference making:
                if (access == AccessType.None)
                {
                    operator_method = Methods.ScriptContext.CallVoid;
                    return_type_code = PhpTypeCode.Void;
                }
                else if (access == AccessType.Read)
                {
                    operator_method = Methods.ScriptContext.CallValue;
                    return_type_code = PhpTypeCode.Object;
                }
                else
                {
                    operator_method = Methods.ScriptContext.Call;
                    return_type_code = PhpTypeCode.PhpReference;
                }
            }

            // emits load of parameters to the PHP stack:
            callSignature.EmitLoadOnPhpStack(this);

            // marks transient sequence point just before the call:
            this.MarkTransientSequencePoint();

            il.Emit(OpCodes.Call, operator_method);

            // marks transient sequence point just after the call:
            this.MarkTransientSequencePoint();

            return return_type_code;
        }
예제 #19
0
        /// <summary>
        /// Create and call <see cref="CallSite"/> for getting property.
        /// </summary>
        /// <param name="cg"><see cref="CodeGenerator"/>.</param>
        /// <param name="wantRef">Wheter <see cref="PhpReference"/> is expected as the result.</param>
        /// <param name="targetExpr">The expression representing the target (object).</param>
        /// <param name="targetObjectPlace">The place representing the target (<see cref="DObject"/>) iff <paramref name="targetExpr"/> is not provided.</param>
        /// <param name="targetPlace">The place representing the target (object) iff <paramref name="targetExpr"/> and <paramref name="targetObjectPlace"/> are not provided.</param>
        /// <param name="targetType">Type of target iff we are getting property statically.</param>
        /// <param name="fieldName">The name of the field. Can be null if the name is not known at compile time (indirect).</param>
        /// <param name="fieldNameExpr">The expression used to get field name in run time (iff <paramref name="fieldName"/> is <c>null</c>.</param>
        /// <param name="issetSemantics">Wheter we are only checking if the property exists. If true, no warnings are thrown during run time.</param>
        /// <returns>Type code of the value that is pushed onto the top of the evaluation stack.</returns>
        public PhpTypeCode EmitGetProperty(
            PHP.Core.CodeGenerator/*!*/cg, bool wantRef,
            Expression targetExpr, IPlace targetObjectPlace, IPlace targetPlace, DType targetType,
            string fieldName, Expression fieldNameExpr,
            bool issetSemantics)
        {
            Debug.Assert(fieldName != null ^ fieldNameExpr != null);
            Debug.Assert(targetExpr != null || targetObjectPlace != null || targetPlace != null || targetType != null);
            
            //
            bool staticCall = (targetExpr == null && targetObjectPlace == null && targetPlace == null); // we are going to access static property
            bool fieldNameIsKnown = (fieldName != null);
            bool classContextIsKnown = (this.classContextPlace != null);

            //
            // binder flags:
            //
            Type returnType = wantRef ? Types.PhpReference[0] : Types.Object[0];
            
            //
            // define the call site:
            //

            //
            List<Type> additionalArgs = new List<Type>();
            if (!classContextIsKnown) additionalArgs.Add(Types.DTypeDesc[0]);
            if (!fieldNameIsKnown) additionalArgs.Add(Types.String[0]);

            var delegateTypeArgs = GetPropertyDelegateTypeArgs(
                staticCall ? Types.DTypeDesc[0] : ((targetObjectPlace != null) ? Types.DObject[0] : Types.Object[0]),   // DTypeDesc of static field's declaring type || DObject if field called on DObject known at compile time || otherwise object
                additionalArgs.ToArray(),
                returnType);

            var delegateType = /*System.Linq.Expressions.Expression.*/delegateBuilder.GetDelegateType(delegateTypeArgs, callSitesCount);    // (J) do not create dynamic delegates in dynamic modules, so they can be referenced from non-transient assemblies

            //
            var field = DefineCallSite(cg.IL, string.Format("get{0}_{1}", wantRef ? "ref" : string.Empty, fieldName ?? "$"), delegateType, (il) =>
            {
                // <LOAD> Binder.{GetProperty|GetStaticProperty}( fieldName, classContext, issetSemantics, <returnType> )
                if (fieldName != null) il.Emit(OpCodes.Ldstr, fieldName); else il.Emit(OpCodes.Ldnull);
                if (this.classContextPlace != null) this.classContextPlace.EmitLoad(il); else il.Emit(OpCodes.Ldsfld, Fields.UnknownTypeDesc.Singleton);
                il.LoadBool(issetSemantics);

                il.Emit(OpCodes.Ldtoken, returnType);
                il.Emit(OpCodes.Call, Methods.GetTypeFromHandle);

                il.Emit(OpCodes.Call, staticCall ? Methods.Binder.StaticGetProperty : Methods.Binder.GetProperty);
            });

            //
            // call the CallSite:
            //

            // <field>.Target( <field>, <targetExpr|targetType>, (classContext)?, <methodNameExpr>? ):

            cg.IL.Emit(OpCodes.Ldsfld, field);
            cg.IL.Emit(OpCodes.Ldfld, field.FieldType.GetField("Target"));
            cg.IL.Emit(OpCodes.Ldsfld, field);
            if (staticCall) targetType.EmitLoadTypeDesc(cg, ResolveTypeFlags.UseAutoload | ResolveTypeFlags.ThrowErrors);
            else if (targetExpr != null)
            {
                cg.ChainBuilder.Lengthen(); // for hop over ->
                cg.EmitBoxing(targetExpr.Emit(cg)); // prepare for operator invocation
            }
            else if (targetObjectPlace != null) targetObjectPlace.EmitLoad(cg.IL);
            else if (targetPlace != null) targetPlace.EmitLoad(cg.IL);
            else Debug.Fail();
            if (!classContextIsKnown) cg.EmitLoadClassContext();
            if (!fieldNameIsKnown) cg.EmitName(fieldName/*null*/, fieldNameExpr, true, PhpTypeCode.String);

            cg.MarkTransientSequencePoint();
            cg.IL.Emit(OpCodes.Callvirt, delegateType.GetMethod("Invoke"));

            cg.MarkTransientSequencePoint();
            
            //
            return PhpTypeCodeEnum.FromType(returnType);
        }
예제 #20
0
        /// <summary>
        /// Emit call to <see cref="DynamicCode.Assert"/> or <see cref="DynamicCode.Eval"/>.
        /// </summary>
        internal PhpTypeCode EmitEval(EvalKinds kind, Expression/*!*/code, Text.Span span, QualifiedName? currentNamespace, Dictionary<string, QualifiedName> currentAliases)
        {
            Debug.Assert(code != null);

            // LOAD DynamicCode.<Eval | Assert>(<code>, context, definedVariables, self, includer, source, line, column, evalId, naming)
            if (kind == EvalKinds.Assert)
            {
                // an argument of the assert is boxed:
                EmitBoxing(code.Emit(this));
            }
            else if (kind == EvalKinds.SyntheticEval)
            {
                Debug.Assert(code.HasValue());
                Debug.Assert(code.GetValue() is string);

                // an argument of the eval is converted to a string:
                il.Emit(OpCodes.Ldstr, (string)code.GetValue());
                il.Emit(OpCodes.Ldc_I4_1);
            }
            else
            {
                // an argument of the eval is converted to a string:
                EmitConversion(code, PhpTypeCode.String);
                il.Emit(OpCodes.Ldc_I4_0);
            }

            var position = new Text.TextPoint(this.SourceUnit.LineBreaks, span.Start);

            EmitLoadScriptContext();
            EmitLoadRTVariablesTable();
            EmitLoadSelf();
            EmitLoadClassContext();
            EmitEvalInfoPass(position.Line, position.Column);
            EmitNamingContext(currentNamespace, currentAliases, span.Start);

            il.Emit(OpCodes.Call, (kind == EvalKinds.Assert) ? Methods.DynamicCode.Assert : Methods.DynamicCode.Eval);

            return (kind == EvalKinds.Assert) ? PhpTypeCode.Boolean : PhpTypeCode.Object;
        }
예제 #21
0
        /// <summary>
        /// Emits load of an argument of a concatenation.
        /// </summary>
        private static PhpTypeCode EmitConcatExpressionLoad(CodeGenerator/*!*/ codeGenerator, Expression/*!*/ expression)
        {
            // tries to evaluate the expression:
            if (expression.HasValue)
            {
                if (expression.Value is PhpBytes)
                {
                    codeGenerator.IL.LoadLiteral(expression.Value);
                    return PhpTypeCode.PhpBytes;
                }
                else
                {
                    // evaluated expression is converted to a string if necessary:
                    codeGenerator.IL.Emit(OpCodes.Ldstr, Convert.ObjectToString(expression.Value));
                    return PhpTypeCode.String;
                }
            }
            else
            {
                // emits non-evaluable expression:
                PhpTypeCode result = expression.Emit(codeGenerator);

                // the result should be converted to string: (so we know the type for the further analysis)
                if (result != PhpTypeCode.String && // string already
                    result != PhpTypeCode.Object && // object can contain PhpBytes, should be converted just when we know we need string
                    result != PhpTypeCode.PhpBytes  // keep PhpBytes
                    )
                {
                    codeGenerator.EmitBoxing(result);   // in case of value-type
                    codeGenerator.IL.Emit(OpCodes.Call, Methods.Convert.ObjectToString);
                    result = PhpTypeCode.String;
                }

                return result;
            }
        }
예제 #22
0
        /// <summary>
        /// Emits conversion to boolean.
        /// </summary>
        /// <param name="expr">Expression to be converted.</param>
        /// <param name="negation">Whether the result should be logic negation of original conversion.</param>
        internal void EmitObjectToBoolean(Expression/*!*/expr, bool negation)
        {
            // <expr>
            var typecode = expr.Emit(this);

            //
            switch (typecode)
            {
                case PhpTypeCode.Boolean:
                    if (negation)
                        this.EmitLogicNegation();
                    break;

                case PhpTypeCode.Integer:
                    // <int> != 0
                    this.EmitLogicNegation();
                    if (!negation)
                        this.EmitLogicNegation();
                    break;

                case PhpTypeCode.LongInteger:
                    // <long> != 0
                    il.Emit(OpCodes.Ldc_I4_0);
                    il.Emit(OpCodes.Conv_I8);
					il.Emit(OpCodes.Ceq);
                    if (!negation)
                        this.EmitLogicNegation();
                    break;

                case PhpTypeCode.Double:
                    // <double> != 0.0
                    il.Emit(OpCodes.Ldc_R8, 0.0);
                    il.Emit(OpCodes.Ceq);
                    if (!negation)
                        this.EmitLogicNegation();
                    break;

                case PhpTypeCode.Void:
                    if (negation)
                        il.Emit(OpCodes.Ldc_I4_1);
                    else
                        il.Emit(OpCodes.Ldc_I4_0);
                    break;

                case PhpTypeCode.String:
                    // StringToBoolean( <string> )
                    IL.Emit(OpCodes.Call, Methods.Convert.StringToBoolean);
                    if (negation)
                        this.EmitLogicNegation();
                    break;

                default:
                    // ObjectToBoolean( (object)<expr> )
                    EmitBoxing(typecode);
                    IL.Emit(OpCodes.Call, Methods.Convert.ObjectToBoolean);
                    if (negation)
                        this.EmitLogicNegation();
                    break;
            }
        }
예제 #23
0
파일: Chains.cs 프로젝트: dw4dev/Phalanger
		public void EmitGetArrayItemRef(Expression/*!*/ array, Expression index)
		{
			array.Emit(codeGenerator);

			PhpTypeCode index_type_code = PhpTypeCode.Invalid;

			if (index != null)
				index_type_code = codeGenerator.EmitArrayKey(this, index);

			codeGenerator.EmitGetArrayItem(index_type_code, index, true);
		}
예제 #24
0
 public void EmitLoad(ILEmitter /*!*/ il)
 {
     Debug.Assert(ReferenceEquals(il, codeGenerator.IL));
     typeCode = expression.Emit(codeGenerator);
 }
예제 #25
0
파일: BinaryEx.cs 프로젝트: proff/Phalanger
        /// <summary>
        /// Emits strict equality to empty PHP array.
        /// </summary>
        /// <param name="codeGenerator">A code generator.</param>
        /// <param name="expr">Expression to be compared against.</param>
        private static void EmitEmptyArrayStrictEquality(CodeGenerator/*!*/codeGenerator, Expression/*!*/expr)
        {
            if (IsEmptyArrayEx(expr))
            {
                // array() === array()
                // LOAD true
                codeGenerator.IL.LoadBool(true);
            }
            else if (expr is Literal)
            {
                // array() === NULL|int|double|string|...
                // LOAD false
                codeGenerator.IL.LoadBool(false);
            }
            else
            {
                // array() === <expr>

                // LOAD <expr>
                var exprTypeCode = expr.Emit(codeGenerator);

                // check whether <expr> type can be an array
                switch (exprTypeCode)
                {
                    case PhpTypeCode.Boolean:
                    case PhpTypeCode.DObject:
                    case PhpTypeCode.Double:
                    case PhpTypeCode.Integer:
                    case PhpTypeCode.LongInteger:
                    case PhpTypeCode.PhpBytes:
                    case PhpTypeCode.PhpString:
                    case PhpTypeCode.String:
                        // always FALSE
                        codeGenerator.IL.Emit(OpCodes.Pop);
                        codeGenerator.IL.LoadBool(false);
                        break;
                    case PhpTypeCode.PhpArray:
                        // compare (PhpArray)<expr> with array()
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEmptyPhpArrayEquality_PhpArray);
                        break;
                    default:
                        // compare <expr> with array()
                        codeGenerator.EmitBoxing(exprTypeCode);
                        codeGenerator.IL.Emit(OpCodes.Call, Methods.Operators.StrictEmptyPhpArrayEquality);
                        break;
                }                
            }
        }