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())); }