public object ResolveToConstant(string name, MethodInfo fn, object[] values)
        {
            Contracts.CheckNonEmpty(name, nameof(name));
            Contracts.CheckValue(fn, nameof(fn));
            Contracts.CheckParam(Utils.Size(values) > 0, nameof(values), "Expected values to have positive length");
            Contracts.CheckParam(!values.All(x => x != null), nameof(values), "Expected values to contain at least one null");

            switch (name)
            {
            case "na":
            {
                Contracts.Assert(values.Length == 1);

                Type type = fn.ReturnType;
                if (type == typeof(R4))
                {
                    return(R4.NaN);
                }
                if (type == typeof(R8))
                {
                    return(R8.NaN);
                }
                return(null);
            }

            case "default":
            {
                Contracts.Assert(values.Length == 1);

                Type type = fn.ReturnType;
                if (type == typeof(I4))
                {
                    return(default(I4));
                }
                if (type == typeof(I8))
                {
                    return(default(I8));
                }
                if (type == typeof(R4))
                {
                    return(default(R4));
                }
                if (type == typeof(R8))
                {
                    return(default(R8));
                }
                if (type == typeof(BL))
                {
                    return(default(BL));
                }
                if (type == typeof(TX))
                {
                    return(default(TX));
                }
                Contracts.Assert(false, "Unexpected return type!");
                return(null);
            }
            }

            // By default, constant NA arguments produce an NA result. Note that this is not true for isna,
            // but those functions will get here only if values contains a single null, not an NA.
            for (int i = 0; i < values.Length; i++)
            {
                if (FunctionProviderUtils.IsNA(values[i]))
                {
                    Contracts.Assert(values.Length > 1);
                    return(FunctionProviderUtils.GetNA(fn.ReturnType));
                }
            }

            return(null);
        }
        public MethodInfo[] Lookup(string name)
        {
            switch (name)
            {
            case "pi":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <R8>(Pi)));

            case "na":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(NA),
                           FunctionProviderUtils.Fn <R8, R8>(NA)));

            case "default":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, I4>(Default),
                           FunctionProviderUtils.Fn <I8, I8>(Default),
                           FunctionProviderUtils.Fn <R4, R4>(Default),
                           FunctionProviderUtils.Fn <R8, R8>(Default),
                           FunctionProviderUtils.Fn <BL, BL>(Default),
                           FunctionProviderUtils.Fn <TX, TX>(Default)));

            case "abs":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, I4>(Math.Abs),
                           FunctionProviderUtils.Fn <I8, I8>(Math.Abs),
                           FunctionProviderUtils.Fn <R4, R4>(Math.Abs),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Abs)));

            case "sign":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, I4>(Sign),
                           FunctionProviderUtils.Fn <I8, I8>(Sign),
                           FunctionProviderUtils.Fn <R4, R4>(Sign),
                           FunctionProviderUtils.Fn <R8, R8>(Sign)));

            case "exp":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Exp),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Exp)));

            case "ln":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Log),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Log)));

            case "log":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Log),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Log),
                           FunctionProviderUtils.Fn <R4, R4, R4>(Log),
                           FunctionProviderUtils.Fn <R8, R8, R8>(Math.Log)));

            case "deg":
            case "degrees":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Deg),
                           FunctionProviderUtils.Fn <R8, R8>(Deg)));

            case "rad":
            case "radians":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Rad),
                           FunctionProviderUtils.Fn <R8, R8>(Rad)));

            case "sin":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Sin),
                           FunctionProviderUtils.Fn <R8, R8>(Sin)));

            case "sind":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(SinD),
                           FunctionProviderUtils.Fn <R8, R8>(SinD)));

            case "cos":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Cos),
                           FunctionProviderUtils.Fn <R8, R8>(Cos)));

            case "cosd":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(CosD),
                           FunctionProviderUtils.Fn <R8, R8>(CosD)));

            case "tan":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Tan),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Tan)));

            case "tand":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(TanD),
                           FunctionProviderUtils.Fn <R8, R8>(TanD)));

            case "asin":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Asin),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Asin)));

            case "acos":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Acos),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Acos)));

            case "atan":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Atan),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Atan)));

            case "atan2":
            case "atanyx":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4, R4>(Atan2),
                           FunctionProviderUtils.Fn <R8, R8, R8>(Atan2)));

            case "sinh":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Sinh),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Sinh)));

            case "cosh":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Cosh),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Cosh)));

            case "tanh":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Tanh),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Tanh)));

            case "sqrt":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Sqrt),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Sqrt)));

            case "trunc":
            case "truncate":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Truncate),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Truncate)));

            case "floor":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Floor),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Floor)));

            case "ceil":
            case "ceiling":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Ceiling),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Ceiling)));

            case "round":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, R4>(Round),
                           FunctionProviderUtils.Fn <R8, R8>(Math.Round)));

            case "min":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, I4, I4>(Math.Min),
                           FunctionProviderUtils.Fn <I8, I8, I8>(Math.Min),
                           FunctionProviderUtils.Fn <R4, R4, R4>(Math.Min),
                           FunctionProviderUtils.Fn <R8, R8, R8>(Math.Min)));

            case "max":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, I4, I4>(Math.Max),
                           FunctionProviderUtils.Fn <I8, I8, I8>(Math.Max),
                           FunctionProviderUtils.Fn <R4, R4, R4>(Math.Max),
                           FunctionProviderUtils.Fn <R8, R8, R8>(Math.Max)));

            case "len":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <TX, I4>(Len)));

            case "lower":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <TX, TX>(Lower)));

            case "upper":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <TX, TX>(Upper)));

            case "right":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <TX, I4, TX>(Right)));

            case "left":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <TX, I4, TX>(Left)));

            case "mid":
                return(FunctionProviderUtils.Ret(FunctionProviderUtils.Fn <TX, I4, I4, TX>(Mid)));

            case "concat":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <TX>(Empty),
                           Id <TX>(),
                           FunctionProviderUtils.Fn <TX, TX, TX>(Concat),
                           FunctionProviderUtils.Fn <TX, TX, TX, TX>(Concat),
                           FunctionProviderUtils.Fn <TX[], TX>(Concat)));

            case "isna":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <R4, BL>(IsNA),
                           FunctionProviderUtils.Fn <R8, BL>(IsNA)));

            case "bool":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <TX, BL>(ToBL),
                           Id <BL>()));

            case "int":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I8, I4>(Convert.ToInt32),
                           FunctionProviderUtils.Fn <R4, I4>(Convert.ToInt32),
                           FunctionProviderUtils.Fn <R8, I4>(Convert.ToInt32),
                           FunctionProviderUtils.Fn <BL, I4>(Convert.ToInt32),
                           FunctionProviderUtils.Fn <TX, I4>(ToI4),
                           Id <I4>()));

            case "long":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, I8>(Convert.ToInt64),
                           FunctionProviderUtils.Fn <R4, I8>(Convert.ToInt64),
                           FunctionProviderUtils.Fn <R8, I8>(Convert.ToInt64),
                           FunctionProviderUtils.Fn <BL, I8>(Convert.ToInt64),
                           FunctionProviderUtils.Fn <TX, I8>(ToI8),
                           Id <I8>()));

            case "float":
            case "single":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, R4>(Convert.ToSingle),
                           FunctionProviderUtils.Fn <I8, R4>(Convert.ToSingle),
                           FunctionProviderUtils.Fn <R4, R4>(ToR4),
                           FunctionProviderUtils.Fn <R8, R4>(ToR4),
                           FunctionProviderUtils.Fn <BL, R4>(Convert.ToSingle),
                           FunctionProviderUtils.Fn <TX, R4>(ToR4)));

            case "double":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, R8>(Convert.ToDouble),
                           FunctionProviderUtils.Fn <I8, R8>(Convert.ToDouble),
                           FunctionProviderUtils.Fn <R4, R8>(ToR8),
                           FunctionProviderUtils.Fn <R8, R8>(ToR8),
                           FunctionProviderUtils.Fn <BL, R8>(Convert.ToDouble),
                           FunctionProviderUtils.Fn <TX, R8>(ToR8)));

            case "text":
                return(FunctionProviderUtils.Ret(
                           FunctionProviderUtils.Fn <I4, TX>(ToTX),
                           FunctionProviderUtils.Fn <I8, TX>(ToTX),
                           FunctionProviderUtils.Fn <R4, TX>(ToTX),
                           FunctionProviderUtils.Fn <R8, TX>(ToTX),
                           FunctionProviderUtils.Fn <BL, TX>(ToTX),
                           Id <TX>()));
            }

            return(null);
        }