Example #1
0
        /// <summary>
        /// Builds <see cref="Expression"/> that properly wraps given expression to return valid PHP type.
        /// It does not perform any conversion for PHP primitive types. Byte array is wrapped into <see cref="PhpBytes"/> and
        /// anything else is wrapped using <see cref="ClrObject.Create"/> method.
        /// </summary>
        /// <param name="expression">Expression returning an object/value.</param>
        /// <returns><see cref="Expression"/> returning valid PHP object.</returns>
        public static Expression /*!*/ ClrObjectWrapDynamic(Expression /*!*/ expression)
        {
            Debug.Assert(expression != null);

            var type = expression.Type;

            if (type.IsGenericParameter)
            {
                type = Types.Object[0];
            }

            // PHP types as they are:
            if (PhpVariable.IsPrimitiveType(type) || /*Types.DObject[0].IsAssignableFrom(type) || */ typeof(IPhpVariable).IsAssignableFrom(type))
            {
                return(expression);
            }

            // (byte[])<expression> -> PhpBytes( <expression> )
            // (byte[])null -> null
            if (type == typeof(byte[]))
            {
                var value = Expression.Variable(typeof(byte[]));
                return
                    (Expression.Block(Types.PhpBytes[0],
                                      new[] { value },
                                      Expression.Condition(
                                          Expression.Equal(Expression.Assign(value, expression), Expression.Constant(null)),
                                          Expression.Constant(null, Types.PhpBytes[0]),
                                          Expression.New(Constructors.PhpBytes_ByteArray, value)
                                          )));
            }

            // from Emit/ClrOverloadBuilder.cs, ClrOverloadBuilder.EmitConvertToPhp:
            switch (Type.GetTypeCode(type))
            {
            case TypeCode.Boolean:
                return(Expression.Convert(expression, Types.Bool[0]));

            // coercion:
            case TypeCode.SByte:
            case TypeCode.Int16:
            case TypeCode.Byte:
            case TypeCode.UInt16:
            case TypeCode.Int32:
                return(Expression.Convert(expression, Types.Int[0]));

            case TypeCode.Int64:
            case TypeCode.UInt32:
                return(Expression.Convert(expression, Types.LongInt[0]));

            case TypeCode.UInt64:
            case TypeCode.Single:
            case TypeCode.Double:
                return(Expression.Convert(expression, Types.Double[0]));

            case TypeCode.Char:
                return(Expression.Call(Expression.Convert(expression, Types.Object[0]), Methods.Object_ToString));

            case TypeCode.DBNull:
                return(Expression.Constant(null, Types.Object[0]));
            }

            // value type -> ClrValue<T>
            // ref type -> ClrObject
            return(Expression.Call(null,
                                   type == Types.Object[0] ?
                                   Methods.ClrObject_WrapDynamic :   // expression can represent anything, check type in run time and wrap dynamically
                                   Methods.ClrObject_WrapRealObject, // expression is surely not PHP primitive type, DObject nor byte[], wrap into ClrObject or IClrValue
                                   Expression.Convert(expression, Types.Object[0])));
        }