Пример #1
0
        public virtual IokeObject ConvertToRational(IokeObject self, IokeObject m, IokeObject context, bool signalCondition)
        {
            if (signalCondition)
            {
                IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                             m,
                                                                             context,
                                                                             "Error",
                                                                             "Type",
                                                                             "IncorrectType"), context).Mimic(m, context);
                condition.SetCell("message", m);
                condition.SetCell("context", context);
                condition.SetCell("receiver", self);
                condition.SetCell("expectedType", context.runtime.GetSymbol("Rational"));

                object[] newCell = new object[] { self };

                context.runtime.WithRestartReturningArguments(() => { context.runtime.ErrorCondition(condition); },
                                                              context,
                                                              new IokeObject.UseValue("rational", newCell));

                return(IokeObject.ConvertToRational(newCell[0], m, context, signalCondition));
            }
            return(null);
        }
Пример #2
0
        public override void Init(IokeObject obj)
        {
            Runtime runtime = obj.runtime;

            obj.Kind        = "Number Decimal";
            runtime.Decimal = obj;

            obj.RegisterMethod(runtime.NewNativeMethod("returns true if the left hand side decimal is equal to the right hand side decimal.",
                                                       new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(runtime.Decimal)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                Decimal d    = (Decimal)IokeObject.dataOf(on);
                object other = args[0];
                return(((other is IokeObject) &&
                        (IokeObject.dataOf(other) is Decimal) &&
                        ((on == context.runtime.Decimal && other == on) ||
                         d.value.Equals(((Decimal)IokeObject.dataOf(other)).value))) ? context.runtime.True : context.runtime.False);
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("Returns a text representation of the object",
                                                       new TypeCheckingNativeMethod.WithNoArguments("asText", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                return(runtime.NewText(on.ToString()));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the square root of the receiver. this should return the same result as calling ** with 0.5",
                                                       new TypeCheckingNativeMethod.WithNoArguments("sqrt", obj,
                                                                                                    (method, on, args, keywords, context, message) => {
                BigDecimal value = ((Decimal)IokeObject.dataOf(on)).value;

                if (value.CompareTo(BigDecimal.ZERO) < 1)
                {
                    IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                                 message,
                                                                                 context,
                                                                                 "Error",
                                                                                 "Arithmetic"), context).Mimic(message, context);
                    condition.SetCell("message", message);
                    condition.SetCell("context", context);
                    condition.SetCell("receiver", on);

                    context.runtime.ErrorCondition(condition);
                }

                return(runtime.NewDecimal(new BigSquareRoot().Get(value)));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns a text inspection of the object",
                                                           new TypeCheckingNativeMethod.WithNoArguments("inspect", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                return(method.runtime.NewText(Decimal.GetInspect(on)));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("Returns a brief text inspection of the object",
                                                           new TypeCheckingNativeMethod.WithNoArguments("notice", obj,
                                                                                                        (method, on, args, keywords, context, message) => {
                return(method.runtime.NewText(Decimal.GetInspect(on)));
            })));

            obj.RegisterMethod(obj.runtime.NewNativeMethod("returns a hash for the decimal number",
                                                           new NativeMethod.WithNoArguments("hash", (method, context, message, on, outer) => {
                outer.ArgumentsDefinition.CheckArgumentCount(context, message, on);
                return(context.runtime.NewNumber(Decimal.GetValue(on).GetHashCode()));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("compares this number against the argument, true if this number is the same, otherwise false",
                                                       new TypeCheckingNativeMethod("==", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg = args[0];
                if (IokeObject.dataOf(arg) is Number)
                {
                    return((Decimal.GetValue(on).CompareTo(Number.GetValue(arg).AsBigDecimal()) == 0) ? context.runtime.True : context.runtime.False);
                }
                else if (IokeObject.dataOf(arg) is Decimal)
                {
                    return((Decimal.GetValue(on).CompareTo(Decimal.GetValue(arg)) == 0) ? context.runtime.True : context.runtime.False);
                }
                else
                {
                    return(context.runtime.False);
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("compares this number against the argument, returning -1, 0 or 1 based on which one is larger. if the argument is a rational, it will be converted into a form suitable for comparing against a decimal, and then compared. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that doesn't work it returns nil.",
                                                       new TypeCheckingNativeMethod("<=>", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("other")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg    = args[0];
                IokeData data = IokeObject.dataOf(arg);

                if (data is Number)
                {
                    return(context.runtime.NewNumber(Decimal.GetValue(on).CompareTo(Number.GetValue(arg).AsBigDecimal())));
                }
                else
                {
                    if (!(data is Decimal))
                    {
                        arg = IokeObject.ConvertToDecimal(arg, message, context, false);
                        if (!(IokeObject.dataOf(arg) is Decimal))
                        {
                            // Can't compare, so bail out
                            return(context.runtime.nil);
                        }
                    }

                    if (on == context.runtime.Decimal || arg == context.runtime.Decimal)
                    {
                        if (arg == on)
                        {
                            return(context.runtime.NewNumber(0));
                        }
                        return(context.runtime.nil);
                    }

                    return(context.runtime.NewNumber(Decimal.GetValue(on).CompareTo(Decimal.GetValue(arg))));
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the difference between this number and the argument. if the argument is a rational, it will be converted into a form suitable for subtracting against a decimal, and then subtracted. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that fails it signals a condition.",
                                                       new TypeCheckingNativeMethod("-", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("subtrahend")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg = args[0];

                IokeData data = IokeObject.dataOf(arg);

                if (data is Number)
                {
                    return(context.runtime.NewDecimal(Decimal.GetValue(on).subtract(Number.GetValue(arg).AsBigDecimal())));
                }
                else
                {
                    if (!(data is Decimal))
                    {
                        arg = IokeObject.ConvertToDecimal(arg, message, context, true);
                    }

                    return(context.runtime.NewDecimal(Decimal.GetValue(on).subtract(Decimal.GetValue(arg))));
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the sum of this number and the argument. if the argument is a rational, it will be converted into a form suitable for addition against a decimal, and then added. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that fails it signals a condition.",
                                                       new TypeCheckingNativeMethod("+", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("addend")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg    = args[0];
                IokeData data = IokeObject.dataOf(arg);

                if (data is Number)
                {
                    return(context.runtime.NewDecimal(Decimal.GetValue(on).add(Number.GetValue(arg).AsBigDecimal())));
                }
                else
                {
                    if (!(data is Decimal))
                    {
                        arg = IokeObject.ConvertToDecimal(arg, message, context, true);
                    }

                    return(context.runtime.NewDecimal(Decimal.GetValue(on).add(Decimal.GetValue(arg))));
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the product of this number and the argument. if the argument is a rational, the receiver will be converted into a form suitable for multiplying against a decimal, and then multiplied. if the argument is neither a Rational nor a Decimal, it tries to call asDecimal, and if that fails it signals a condition.",
                                                       new TypeCheckingNativeMethod("*", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("multiplier")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg = args[0];

                IokeData data = IokeObject.dataOf(arg);

                if (data is Number)
                {
                    return(context.runtime.NewDecimal(Decimal.GetValue(on).multiply(Number.GetValue(arg).AsBigDecimal())));
                }
                else
                {
                    if (!(data is Decimal))
                    {
                        arg = IokeObject.ConvertToDecimal(arg, message, context, true);
                    }

                    return(context.runtime.NewDecimal(Decimal.GetValue(on).multiply(Decimal.GetValue(arg))));
                }
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns this number to the power of the argument (which has to be an integer)",
                                                       new TypeCheckingNativeMethod("**", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("exponent")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg    = args[0];
                IokeData data = IokeObject.dataOf(arg);

                if (!(data is Number))
                {
                    arg = IokeObject.ConvertToRational(arg, message, context, true);
                }
                return(context.runtime.NewDecimal(Decimal.GetValue(on).pow(Number.IntValue(arg).intValue())));
            })));

            obj.RegisterMethod(runtime.NewNativeMethod("returns the quotient of this number and the argument.",
                                                       new TypeCheckingNativeMethod("/", TypeCheckingArgumentsDefinition.builder()
                                                                                    .ReceiverMustMimic(obj)
                                                                                    .WithRequiredPositional("divisor")
                                                                                    .Arguments,
                                                                                    (method, on, args, keywords, context, message) => {
                object arg    = args[0];
                IokeData data = IokeObject.dataOf(arg);

                if (data is Number)
                {
                    return(context.runtime.NewDecimal(Decimal.GetValue(on).divide(Number.GetValue(arg).AsBigDecimal())));
                }
                else
                {
                    if (!(data is Decimal))
                    {
                        arg = IokeObject.ConvertToDecimal(arg, message, context, true);
                    }

                    while (Decimal.GetValue(arg).CompareTo(BigDecimal.ZERO) == 0)
                    {
                        IokeObject condition = IokeObject.As(IokeObject.GetCellChain(context.runtime.Condition,
                                                                                     message,
                                                                                     context,
                                                                                     "Error",
                                                                                     "Arithmetic",
                                                                                     "DivisionByZero"), context).Mimic(message, context);
                        condition.SetCell("message", message);
                        condition.SetCell("context", context);
                        condition.SetCell("receiver", on);

                        object[] newCell = new object[] { arg };

                        context.runtime.WithRestartReturningArguments(() => { context.runtime.ErrorCondition(condition); },
                                                                      context,
                                                                      new IokeObject.UseValue("newValue", newCell));
                        arg = newCell[0];
                    }

                    BigDecimal result = null;
                    try {
                        result = Decimal.GetValue(on).divide(Decimal.GetValue(arg), BigDecimal.ROUND_UNNECESSARY);
                    } catch (System.ArithmeticException) {
                        result = Decimal.GetValue(on).divide(Decimal.GetValue(arg), MathContext.DECIMAL128);
                    }
                    return(context.runtime.NewDecimal(result));
                }
            })));
        }