diff --git a/moo/kernel/Magnitu.moo b/moo/kernel/Magnitu.moo index 6a55bbd..a2e386c 100644 --- a/moo/kernel/Magnitu.moo +++ b/moo/kernel/Magnitu.moo @@ -247,7 +247,7 @@ class(#limited) Number(Magnitude) method printStringRadix: aNumber { - + self primitiveFailed. } diff --git a/moo/lib/exec.c b/moo/lib/exec.c index e6b875d..09fd748 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -3013,6 +3013,26 @@ static moo_pfrc_t pf_number_ge (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) return MOO_PF_SUCCESS; } +static moo_pfrc_t pf_number_numtostr (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +{ + moo_oop_t rcv, arg, str; + moo_ooi_t radix; + + MOO_ASSERT (moo, nargs == 1); + + rcv = MOO_STACK_GETRCV(moo, nargs); + arg = MOO_STACK_GETARG(moo, nargs, 0); + + if (!MOO_OOP_IS_SMOOI(arg)) return MOO_PF_FAILURE; + radix = MOO_OOP_TO_SMOOI(arg); + + if (radix < 2 || radix > 36) return MOO_PF_FAILURE; + str = moo_numtostr(moo, rcv, radix); + if (!str) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); + + MOO_STACK_SETRET (moo, nargs, str); + return MOO_PF_SUCCESS; +} /* ------------------------------------------------------------------ */ static moo_pfrc_t pf_integer_add (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { @@ -3856,6 +3876,7 @@ static pf_t pftab[] = { "_number_mul", { pf_number_mul, 1, 1 } }, { "_number_ne", { pf_number_ne, 1, 1 } }, { "_number_negated", { pf_number_negated, 0, 0 } }, + { "_number_numtostr", { pf_number_numtostr, 1, 1 } }, { "_number_sub", { pf_number_sub, 1, 1 } }, { "_utf8_seqlen", { moo_pf_utf8_seqlen, 0, 0 } }, diff --git a/moo/lib/logfmt.c b/moo/lib/logfmt.c index 4caf489..b913bca 100644 --- a/moo/lib/logfmt.c +++ b/moo/lib/logfmt.c @@ -421,6 +421,10 @@ static int print_object (moo_t* moo, moo_bitmask_t mask, moo_oop_t oop, outbfmt_ } else if (c == moo->_fixed_point_decimal) { +#if 1 + if (!moo_numtostr(moo, oop, 10 | MOO_NUMTOSTR_NONEWOBJ)) return -1; + if (outbfmt(moo, mask, "%.*js", moo->inttostr.xbuf.len, moo->inttostr.xbuf.ptr) <= -1) return -1; +#else moo_ooch_t* ptr; moo_oow_t len; moo_ooi_t scale; @@ -453,6 +457,7 @@ static int print_object (moo_t* moo, moo_bitmask_t mask, moo_oop_t oop, outbfmt_ { if (outbfmt(moo, mask, "%.*js.%.*js", len - scale, &ptr[0], scale, &ptr[len - scale]) <= -1) return -1; } +#endif } else if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_CHAR) { diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index d91a014..e1ca445 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -1353,8 +1353,9 @@ moo_oop_t moo_strtoint ( int radix ); -#define MOO_INTTOSTR_LOWERCASE (1 << 14) -#define MOO_INTTOSTR_NONEWOBJ (1 << 15) +#define MOO_INTTOSTR_RADIXMASK (0xFF) +#define MOO_INTTOSTR_LOWERCASE (1 << 8) +#define MOO_INTTOSTR_NONEWOBJ (1 << 9) moo_oop_t moo_inttostr ( moo_t* moo, @@ -1460,6 +1461,18 @@ moo_oop_t moo_absnum ( moo_oop_t x ); + +#define MOO_NUMTOSTR_RADIXMASK MOO_INTTOSTR_RADIXMASK +#define MOO_NUMTOSTR_LOWERCASE MOO_INTTOSTR_LOWERCASE +#define MOO_NUMTOSTR_NONEWOBJ MOO_INTTOSTR_NONEWOBJ + +moo_oop_t moo_numtostr ( + moo_t* moo, + moo_oop_t num, + int flagged_radix /* radix between 2 and 36 inclusive, optionally bitwise ORed of MOO_INTTOSTR_XXX bits */ +); + + /* ========================================================================= */ /* logfmt.c */ /* ========================================================================= */ diff --git a/moo/lib/number.c b/moo/lib/number.c index a28908a..4ed438b 100644 --- a/moo/lib/number.c +++ b/moo/lib/number.c @@ -440,3 +440,70 @@ moo_oop_t moo_absnum (moo_t* moo, moo_oop_t x) return moo_makefpdec(moo, v, scale); } } + +moo_oop_t moo_numtostr (moo_t* moo, moo_oop_t num, int flagged_radix) +{ + if (!MOO_OOP_IS_FPDEC(moo, num)) + { + return moo_inttostr(moo, num, flagged_radix); + } + else + { + /* ignore radix for fixed-point decimal */ + moo_ooch_t* ptr; + moo_oow_t len, inc, reqcapa; + moo_ooi_t scale; + int flags; + + flags = 10 | (flagged_radix & ~MOO_INTTOSTR_RADIXMASK) | MOO_INTTOSTR_NONEWOBJ; + if (!moo_inttostr(moo, ((moo_oop_fpdec_t)num)->value, flags)) return MOO_NULL; + + scale = MOO_OOP_TO_SMOOI(((moo_oop_fpdec_t)num)->scale); + + start_over: + ptr = moo->inttostr.xbuf.ptr; + len = moo->inttostr.xbuf.len; + if (ptr[0] == '-') + { + ptr++; + len--; + } + + inc = (scale >= len)? (scale - len + 2): 1; + reqcapa = moo->inttostr.xbuf.len + inc + 20000; + if (moo->inttostr.xbuf.capa < reqcapa) + { + moo_ooch_t* xbuf = (moo_ooch_t*)moo_reallocmem(moo, moo->inttostr.xbuf.ptr, reqcapa * MOO_SIZEOF(*xbuf)); + if (!xbuf) return MOO_NULL; + moo->inttostr.xbuf.capa = reqcapa; + moo->inttostr.xbuf.ptr = xbuf; + goto start_over; + } + + if (scale >= len) + { + moo_oow_t i, j; + MOO_MEMMOVE (&ptr[inc], ptr, len * MOO_SIZEOF(*ptr)); + ptr[0] = '0'; + ptr[1] = '.'; + for (i = len, j = 2; i < scale; i++) ptr[j++] = '0'; + } + else + { + moo_oow_t pos; + pos = len - scale; + MOO_MEMMOVE (&ptr[pos + 1], &ptr[pos], scale * MOO_SIZEOF(*ptr)); + ptr[pos] = '.'; /* squeeze in the fixed point */ + } + moo->inttostr.xbuf.len += inc; + + if (flagged_radix & MOO_INTTOSTR_NONEWOBJ) + { + /* special case. don't create a new object. + * the caller can use the data left in moo->inttostr.xbuf */ + return moo->_nil; + } + + return moo_makestring(moo, moo->inttostr.xbuf.ptr, moo->inttostr.xbuf.len); + } +}