Ejemplo n.º 1
0
        public static bool CoerceArgument(out object clr, Type ty, Variable var)
        {
            P6any obj = var.Fetch();

            clr = null;

            // type objects are typed nulls
            if (!obj.IsDefined())
            {
                if (obj is BoxObject <object> )
                {
                    Type t = obj.mo.box_type;
                    // is this enough?
                    return(ty.IsAssignableFrom(t) && !ty.IsValueType &&
                           ty != typeof(void));
                }
                else if (obj.mo == Kernel.MuMO || obj.mo == Kernel.AnyMO)
                {
                    // untyped-ish null
                    return(!ty.IsValueType && ty != typeof(void));
                }
                else
                {
                    // we'll pass this by value anyway
                    clr = obj;
                    return(ty.IsAssignableFrom(obj.GetType()));
                }
            }
            // in all other cases we're definitely passing a non-null value

            // Boolean values marshal to bool
            if (obj.Does(Kernel.BoolMO))
            {
                clr = Kernel.UnboxAny <int>(obj) != 0;
            }
            // note, Bool ~~ Int ~~ Integral
            else if (obj.Does(Kernel.IntegralMO))
            {
                // important type directed case!
                int        small;
                BigInteger big;
                bool       use_big = Builtins.GetAsInteger(var, out small, out big);

                if (ty == typeof(sbyte))
                {
                    clr = (!use_big && small >= sbyte.MinValue && small <= sbyte.MaxValue) ? (object)(sbyte)small : null;
                }
                else if (ty == typeof(byte))
                {
                    clr = (!use_big && small >= byte.MinValue && small <= byte.MaxValue) ? (object)(byte)small : null;
                }
                else if (ty == typeof(short))
                {
                    clr = (!use_big && small >= short.MinValue && small <= short.MaxValue) ? (object)(short)small : null;
                }
                else if (ty == typeof(ushort))
                {
                    clr = (!use_big && small >= ushort.MinValue && small <= ushort.MaxValue) ? (object)(ushort)small : null;
                }
                else
                {
                    big = use_big ? big : (BigInteger)small;

                    if (ty == typeof(int))
                    {
                        clr = (big >= int.MinValue && big <= int.MaxValue) ? (object)(int)big : null;
                    }
                    else if (ty == typeof(uint))
                    {
                        clr = (big >= uint.MinValue && big <= uint.MaxValue) ? (object)(uint)big : null;
                    }
                    else if (ty == typeof(long))
                    {
                        clr = (big >= long.MinValue && big <= long.MaxValue) ? (object)(long)big : null;
                    }
                    else if (ty == typeof(ulong))
                    {
                        clr = (big >= ulong.MinValue && big <= ulong.MaxValue) ? (object)(ulong)big : null;
                    }

                    else if (ty == typeof(float))
                    {
                        clr = (object)(float)big;
                    }
                    else if (ty == typeof(double))
                    {
                        clr = (object)(double)big;
                    }
                    else if (ty == typeof(decimal))
                    {
                        clr = big.GetWords().Length <= 3 ? (object)(decimal)big : null;
                    }
                    else if (ty == typeof(object))
                    {
                        clr = use_big ? null : (object)small;
                    }
                    else
                    {
                        clr = obj;
                    }
                }
            }
            else if (obj.Does(Kernel.RealMO))
            {
                // fractional value

                if (ty == typeof(decimal))
                {
                    // decimal is for people who care about exactness
                    int        rk;
                    P6any      n = Builtins.GetNumber(var, obj, out rk);
                    BigInteger num, den;
                    if (rk == Builtins.NR_FATRAT)
                    {
                        FatRat r = Kernel.UnboxAny <FatRat>(n);
                        num = r.num; den = r.den;
                    }
                    else if (rk == Builtins.NR_FIXRAT)
                    {
                        Rat r = Kernel.UnboxAny <Rat>(n);
                        num = r.num; den = r.den;
                    }
                    else if (rk == Builtins.NR_BIGINT)
                    {
                        num = Kernel.UnboxAny <BigInteger>(n); den = BigInteger.One;
                    }
                    else if (rk == Builtins.NR_FIXINT)
                    {
                        num = Kernel.UnboxAny <int>(n); den = BigInteger.One;
                    }
                    else
                    {
                        return(false);
                    }
                    BigInteger div, rem;
                    int        scale = 0;
                    while (true)
                    {
                        div = BigInteger.DivRem(den, 10, out rem);
                        if (rem.Sign != 0)
                        {
                            break;
                        }
                        den = div;
                        scale++;
                    }
                    while (true)
                    {
                        div = BigInteger.DivRem(den, 5, out rem);
                        if (rem.Sign != 0)
                        {
                            break;
                        }
                        den  = div;
                        num *= 2;
                        scale++;
                    }
                    while (true)
                    {
                        div = BigInteger.DivRem(den, 2, out rem);
                        if (rem.Sign != 0)
                        {
                            break;
                        }
                        den  = div;
                        num *= 5;
                        scale++;
                    }
                    if (den != BigInteger.One)
                    {
                        return(false);
                    }
                    if (scale > 28)
                    {
                        return(false);
                    }
                    int[] bits = decimal.GetBits((decimal)num);
                    bits[3] = scale << 16;
                    clr     = new decimal(bits);
                }
                else
                {
                    double val = obj.mo.mro_raw_Numeric.Get(var);
                    if (ty == typeof(float))
                    {
                        clr = (object)(float)val;
                    }
                    else if (ty == typeof(double) || ty == typeof(object))
                    {
                        clr = (object)val;
                    }
                }
            }
            else if (obj.Does(Kernel.StrMO))
            {
                string s = Kernel.UnboxAny <string>(obj);
                if (ty == typeof(char) && s.Length == 1)
                {
                    clr = s[0];
                }
                else if (ty == typeof(string))
                {
                    clr = s;
                }
                else if (ty == typeof(object))
                {
                    clr = s;
                }
                else
                {
                    clr = obj;
                }
            }
            // "Callable"
            else if (typeof(Delegate).IsAssignableFrom(ty))
            {
                MethodInfo      needed = ty.GetMethod("Invoke");
                ParameterInfo[] pi     = needed.GetParameters();

                if (pi.Length >= 10)
                {
                    clr = null;
                }
                else if (needed.ReturnType != typeof(void))
                {
                    Type[] args = new Type[pi.Length + 1];
                    args[0] = needed.ReturnType;
                    for (int i = 0; i < pi.Length; i++)
                    {
                        args[i + 1] = pi[i].ParameterType;
                    }
                    MethodInfo compat = delegate_methods[pi.Length * 2 + 1].
                                        MakeGenericMethod(args);
                    clr = Delegate.CreateDelegate(ty, obj, compat);
                }
                else
                {
                    Type[] args = new Type[pi.Length];
                    for (int i = 0; i < pi.Length; i++)
                    {
                        args[i] = pi[i].ParameterType;
                    }
                    MethodInfo compat = delegate_methods[pi.Length * 2];
                    if (args.Length != 0)
                    {
                        compat = compat.MakeGenericMethod(args);
                    }
                    clr = Delegate.CreateDelegate(ty, obj, compat);
                }
            }
            else if (obj is BoxObject <object> )
            {
                clr = Kernel.UnboxAny <object>(obj);
            }
            else
            {
                clr = obj;
            }

            return(clr != null && ty.IsAssignableFrom(clr.GetType()));
        }