Esempio n. 1
0
        /// <summary>
        /// Emits code that loads a specified parameter on the evaluation stack.
        /// </summary>
        /// <param name="paramInfo">The parameter to load.</param>
        /// <param name="requiredTypeCode">Specifies whether <see cref="PhpReference"/>
        /// (<see cref="PhpTypeCode.PhpReference"/>), <see cref="object"/> (<see cref="PhpTypeCode.Object"/>),
        /// or the most fitting of these two should be loaded.</param>
        public void EmitLoadClrParameter(ParameterInfo /*!*/ paramInfo, PhpTypeCode requiredTypeCode)
        {
            if (paramInfo.IsOut)
            {
                il.Emit(OpCodes.Ldnull);
            }
            else
            {
                il.Ldarg(paramInfo.Position + paramOffset);

                // dereference ref param
                Type param_type = paramInfo.ParameterType;
                if (param_type.IsByRef)
                {
                    param_type = param_type.GetElementType();

                    il.Ldind(param_type);
                }

                // convert the parameter to PHP type
                PhpTypeCode type_code = ClrOverloadBuilder.EmitConvertToPhp(
                    il,
                    param_type /*,
                                * scriptContextPlace*/);

                il.EmitBoxing(type_code);
            }

            // check whether we have to create a PhpReference
            if (requiredTypeCode == PhpTypeCode.Object ||
                (requiredTypeCode == PhpTypeCode.Unknown && !paramInfo.ParameterType.IsByRef))
            {
                return;
            }

            if (paramInfo.ParameterType.IsByRef)
            {
                LocalBuilder ref_local = il.DeclareLocal(Types.PhpReference[0]);

                // remember the PhpReference in a local
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
                il.Emit(OpCodes.Dup);
                il.Stloc(ref_local);

                referenceLocals[paramInfo.Position] = ref_local;
            }
            else
            {
                // no reference store-back is necessary
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
            }
        }
Esempio n. 2
0
        public void EmitConvertReturnValue(Type /*!*/ returnType, PhpTypeCode expectedTypeCode)
        {
            if (returnType == Types.Void)
            {
                il.Emit(OpCodes.Pop);
            }
            else
            {
                if (expectedTypeCode == PhpTypeCode.PhpReference)
                {
                    // dereference
                    il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                    expectedTypeCode = PhpTypeCode.Object;
                }

                ClrOverloadBuilder.EmitConvertToClr(
                    il,
                    expectedTypeCode,
                    returnType);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Emits code that stores a <see cref="PhpReference"/>'s value back to a ref/out parameter.
        /// </summary>
        /// <param name="paramInfo">The parameter to store back.</param>
        public void EmitStoreClrParameter(ParameterInfo /*!*/ paramInfo)
        {
            if (paramInfo.ParameterType.IsByRef && referenceLocals[paramInfo.Position] != null)
            {
                il.Ldarg(paramInfo.Position + paramOffset);

                Type param_type = paramInfo.ParameterType.GetElementType();

                // load the new parameter value
                il.Ldloc(referenceLocals[paramInfo.Position]);
                il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);

                // convert it to CLR type
                ClrOverloadBuilder.EmitConvertToClr(
                    il,
                    PhpTypeCode.Object,
                    param_type);

                // store it back
                il.Stind(param_type);
            }
        }
Esempio n. 4
0
        /// <summary> Emit PHP to CLR conversion </summary>
        /// <remarks>If the return type is interface marked using <seealso cref="DuckTypeAttribute"/>
        /// it is wrapped again.
        /// <code>
        /// // type is IDuckEnumerable&lt;T&gt;
        /// return new DuckEnumerableWrapper&lt;T&gt;(obj.GetForeachEnumerator(false, false, null))
        ///
        /// // type is IDuckKeyedEnumerable&lt;T&gt;
        /// return new DuckKeyedEnumerableWrapper&lt;T&gt;(obj.GetForeachEnumerator(true, false, null))
        ///
        /// // type is marked using [DuckType]
        /// return DuckTyping.Instance.ImplementDuckType&lt;T&gt;(obj);
        ///
        /// // otherwise uses standard ConvertToClr conversion method
        /// </code>
        /// </remarks>
        private static void EmitReturn(ILEmitter il, Type returnedType, bool isPhpRef)
        {
            Type[]   gargs = returnedType.GetGenericArguments();
            object[] attrs = returnedType.GetCustomAttributes(typeof(DuckTypeAttribute), false);

            bool isDuckEnumerable      = (gargs.Length == 1 && returnedType.Equals(typeof(IDuckEnumerable <>).MakeGenericType(gargs)));
            bool isDuckKeyedEnumerable = (gargs.Length == 2 && returnedType.Equals(typeof(IDuckKeyedEnumerable <,>).MakeGenericType(gargs)));
            bool isDuckType            = attrs != null && attrs.Length > 0;

            if (returnedType.Equals(typeof(void)))
            {
                il.Emit(OpCodes.Pop);
                il.Emit(OpCodes.Ret);
            }
            else if (isDuckType || isDuckEnumerable || isDuckKeyedEnumerable)
            {
                LocalBuilder tmp = il.DeclareLocal(typeof(object));

                //store the value local var (after unwrapping it from the reference)
                if (isPhpRef)
                {
                    il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                }
                il.Stloc(tmp);

                Label lblTestMinusOne = il.DefineLabel();
                Label lblWrap         = il.DefineLabel();
                Label lblInvalidInt   = il.DefineLabel();

                // test whether the value is null
                il.Ldloc(tmp);
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brfalse, lblTestMinusOne);
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ret);

                il.MarkLabel(lblTestMinusOne);

                // test whether value is -1
                il.Ldloc(tmp);
                il.Emit(OpCodes.Isinst, typeof(int));
                il.Emit(OpCodes.Brfalse, lblWrap);                 // value is not int, so we can wrap the value
                il.Ldloc(tmp);
                il.Emit(OpCodes.Unbox_Any, typeof(int));
                il.Emit(OpCodes.Ldc_I4, -1);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brfalse, lblWrap);                 // value is int but not -1
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ret);

                il.MarkLabel(lblWrap);

                // specific duck type wrapping
                if (isDuckEnumerable || isDuckKeyedEnumerable)
                {
                    il.Ldloc(tmp);
                    il.Emit(OpCodes.Dup);
                    // Standard: new DuckEnumerableWrapper<T>(obj.GetForeachEnumerator(false, false, null))
                    // Keyed:    new DuckKeyedEnumerableWrapper<T>(obj.GetForeachEnumerator(false, false, null))
                    il.LoadLiteral(gargs.Length == 2);                     // keyed?
                    il.LoadLiteral(false);
                    il.LoadLiteral(null);
                    il.Emit(OpCodes.Callvirt, Methods.IPhpEnumerable_GetForeachEnumerator);
                    if (isDuckEnumerable)
                    {
                        il.Emit(OpCodes.Newobj, typeof(DuckEnumerableWrapper <>).
                                MakeGenericType(gargs).GetConstructors()[0]);
                    }
                    else
                    {
                        il.Emit(OpCodes.Newobj, typeof(DuckKeyedEnumerableWrapper <,>).
                                MakeGenericType(gargs).GetConstructors()[0]);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Call, typeof(DuckTyping).GetProperty("Instance", BindingFlags.Public | BindingFlags.Static).GetGetMethod());
                    il.Ldloc(tmp);
                    il.Emit(OpCodes.Call, typeof(DuckTyping).GetMethod("ImplementDuckType", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(returnedType));
                }

                il.Emit(OpCodes.Ret);
            }
            else
            {
                if (returnedType == typeof(object))
                {
                    Label lbl = il.DefineLabel();

                    if (isPhpRef)
                    {
                        il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                    }

                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Isinst, typeof(PhpBytes));
                    il.Emit(OpCodes.Brfalse, lbl);
                    il.EmitCall(OpCodes.Call, typeof(IPhpConvertible).GetMethod("ToString", Type.EmptyTypes), Type.EmptyTypes);
                    il.Emit(OpCodes.Ret);
                    il.MarkLabel(lbl);
                    ClrOverloadBuilder.EmitConvertToClr(il, PhpTypeCode.Object, returnedType);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    ClrOverloadBuilder.EmitConvertToClr(il, isPhpRef ? PhpTypeCode.PhpReference : PhpTypeCode.Object, returnedType);
                    il.Emit(OpCodes.Ret);
                }
            }
        }