/// <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]))); }