diff --git a/moo/kernel/Collect.moo b/moo/kernel/Collect.moo index 745a3f4..c25476c 100644 --- a/moo/kernel/Collect.moo +++ b/moo/kernel/Collect.moo @@ -265,6 +265,8 @@ class(#character) String(Array) * if no terminating null character exists, it returns the same value as the size method *) method(#primitive,#lenient) _strlen. method(#primitive) strlen. + + method(#primitive,#variadic) strfmt(). } ## ------------------------------------------------------------------------------- diff --git a/moo/lib/bigint.c b/moo/lib/bigint.c index ab1dd69..592f707 100644 --- a/moo/lib/bigint.c +++ b/moo/lib/bigint.c @@ -69,13 +69,12 @@ #define IS_SIGN_DIFF(x,y) (((x) ^ (y)) < 0) -#define IS_PBIGINT(moo,x) (MOO_OBJ_GET_CLASS(x) == (moo)->_large_positive_integer) -#define IS_NBIGINT(moo,x) (MOO_OBJ_GET_CLASS(x) == (moo)->_large_negative_integer) -#define IS_BIGINT(moo,x) (IS_PBIGINT(moo,x) || IS_NBIGINT(moo,x)) - /* digit character array */ -static char _digitc_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; -static char _digitc_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +static char* _digitc_array[] = +{ + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "0123456789abcdefghijklmnopqrstuvwxyz" +}; /* exponent table */ static moo_uint8_t _exp_tab[] = @@ -208,7 +207,7 @@ static int is_normalized_integer (moo_t* moo, moo_oop_t oop) { /* TODO: is it better to introduce a special integer mark into the class itself */ /* TODO: or should it check if it's a subclass, subsubclass, subsubsubclass, etc of a large_integer as well? */ - if (IS_BIGINT(moo, oop)) + if (MOO_POINTER_IS_BIGINT(moo, oop)) { moo_oow_t sz; @@ -228,7 +227,7 @@ MOO_INLINE static int is_bigint (moo_t* moo, moo_oop_t x) /* TODO: is it better to introduce a special integer mark into the class itself */ /* TODO: or should it check if it's a subclass, subsubclass, subsubsubclass, etc of a large_integer as well? */ - return IS_BIGINT(moo, x); + return MOO_POINTER_IS_BIGINT(moo, x); } MOO_INLINE int moo_isint (moo_t* moo, moo_oop_t x) @@ -241,14 +240,14 @@ MOO_INLINE int moo_isint (moo_t* moo, moo_oop_t x) static MOO_INLINE int bigint_to_oow (moo_t* moo, moo_oop_t num, moo_oow_t* w) { MOO_ASSERT (moo, MOO_OOP_IS_POINTER(num)); - MOO_ASSERT (moo, IS_PBIGINT(moo, num) || IS_NBIGINT(moo, num)); + MOO_ASSERT (moo, MOO_POINTER_IS_PBIGINT(moo, num) || MOO_POINTER_IS_NBIGINT(moo, num)); #if (MOO_LIW_BITS == MOO_OOW_BITS) MOO_ASSERT (moo, MOO_OBJ_GET_SIZE(num) >= 1); if (MOO_OBJ_GET_SIZE(num) == 1) { *w = MOO_OBJ_GET_WORD_SLOT(num)[0]; - return (IS_NBIGINT(moo, num))? -1: 1; + return (MOO_POINTER_IS_NBIGINT(moo, num))? -1: 1; } #elif (MOO_LIW_BITS == MOO_OOHW_BITS) @@ -261,7 +260,7 @@ static MOO_INLINE int bigint_to_oow (moo_t* moo, moo_oop_t num, moo_oow_t* w) if (MOO_OBJ_GET_SIZE(num) == 2) { *w = MAKE_WORD (MOO_OBJ_GET_HALFWORD_SLOT(num)[0], MOO_OBJ_GET_HALFWORD_SLOT(num)[1]); - return (IS_NBIGINT(moo, num))? -1: 1; + return (MOO_POINTER_IS_NBIGINT(moo, num))? -1: 1; } #else # error UNSUPPORTED LIW BIT SIZE @@ -574,13 +573,13 @@ static MOO_INLINE moo_oop_t clone_bigint_negated (moo_t* moo, moo_oop_t oop, moo moo_oop_class_t _class; MOO_ASSERT (moo, MOO_OOP_IS_POINTER(oop)); - if (IS_PBIGINT(moo, oop)) + if (MOO_POINTER_IS_PBIGINT(moo, oop)) { _class = moo->_large_negative_integer; } else { - MOO_ASSERT (moo, IS_NBIGINT(moo, oop)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, oop)); _class = moo->_large_positive_integer; } @@ -629,14 +628,14 @@ static moo_oop_t normalize_bigint (moo_t* moo, moo_oop_t oop) moo_oow_t w; w = MOO_OBJ_GET_LIWORD_SLOT(oop)[0]; - if (IS_PBIGINT(moo, oop)) + if (MOO_POINTER_IS_PBIGINT(moo, oop)) { if (w <= MOO_SMOOI_MAX) return MOO_SMOOI_TO_OOP(w); } else { MOO_ASSERT (moo, -MOO_SMOOI_MAX == MOO_SMOOI_MIN); - MOO_ASSERT (moo, IS_NBIGINT(moo, oop)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, oop)); if (w <= MOO_SMOOI_MAX) return MOO_SMOOI_TO_OOP(-(moo_ooi_t)w); } } @@ -644,13 +643,13 @@ static moo_oop_t normalize_bigint (moo_t* moo, moo_oop_t oop) if (count == 1) /* 1 half-word */ { - if (IS_PBIGINT(moo, oop)) + if (MOO_POINTER_IS_PBIGINT(moo, oop)) { return MOO_SMOOI_TO_OOP(MOO_OBJ_GET_LIWORD_SLOT(oop)[0]); } else { - MOO_ASSERT (moo, IS_NBIGINT(moo, oop)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, oop)); return MOO_SMOOI_TO_OOP(-(moo_ooi_t)MOO_OBJ_GET_LIWORD_SLOT(oop)[0]); } } @@ -659,14 +658,14 @@ static moo_oop_t normalize_bigint (moo_t* moo, moo_oop_t oop) moo_oow_t w; w = MAKE_WORD (MOO_OBJ_GET_LIWORD_SLOT(oop)[0], MOO_OBJ_GET_LIWORD_SLOT(oop)[1]); - if (IS_PBIGINT(moo, oop)) + if (MOO_POINTER_IS_PBIGINT(moo, oop)) { if (w <= MOO_SMOOI_MAX) return MOO_SMOOI_TO_OOP(w); } else { MOO_ASSERT (moo, -MOO_SMOOI_MAX == MOO_SMOOI_MIN); - MOO_ASSERT (moo, IS_NBIGINT(moo, oop)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, oop)); if (w <= MOO_SMOOI_MAX) return MOO_SMOOI_TO_OOP(-(moo_ooi_t)w); } } @@ -707,10 +706,10 @@ static MOO_INLINE int is_less (moo_t* moo, moo_oop_t x, moo_oop_t y) { if (MOO_OBJ_GET_CLASS(x) != MOO_OBJ_GET_CLASS(y)) { - return IS_NBIGINT(moo, x); + return MOO_POINTER_IS_NBIGINT(moo, x); } - if (IS_PBIGINT(moo, x)) + if (MOO_POINTER_IS_PBIGINT(moo, x)) { return is_less_unsigned(x, y); } @@ -745,10 +744,10 @@ static MOO_INLINE int is_greater (moo_t* moo, moo_oop_t x, moo_oop_t y) { if (MOO_OBJ_GET_CLASS(x) != MOO_OBJ_GET_CLASS(y)) { - return IS_NBIGINT(moo, y); + return MOO_POINTER_IS_NBIGINT(moo, y); } - if (IS_PBIGINT(moo, x)) + if (MOO_POINTER_IS_PBIGINT(moo, x)) { return is_greater_unsigned(x, y); } @@ -1624,7 +1623,7 @@ moo_oop_t moo_addints (moo_t* moo, moo_oop_t x, moo_oop_t y) i = MOO_OOP_TO_SMOOI(x) + MOO_OOP_TO_SMOOI(y); if (MOO_IN_SMOOI_RANGE(i)) return MOO_SMOOI_TO_OOP(i); - return make_bigint_with_ooi (moo, i); + return make_bigint_with_ooi(moo, i); } else { @@ -1638,7 +1637,7 @@ moo_oop_t moo_addints (moo_t* moo, moo_oop_t x, moo_oop_t y) if (v == 0) return clone_bigint (moo, y, MOO_OBJ_GET_SIZE(y)); moo_pushtmp (moo, &y); - x = make_bigint_with_ooi (moo, v); + x = make_bigint_with_ooi(moo, v); moo_poptmp (moo); if (!x) return MOO_NULL; } @@ -1650,7 +1649,7 @@ moo_oop_t moo_addints (moo_t* moo, moo_oop_t x, moo_oop_t y) if (v == 0) return clone_bigint (moo, x, MOO_OBJ_GET_SIZE(x)); moo_pushtmp (moo, &x); - y = make_bigint_with_ooi (moo, v); + y = make_bigint_with_ooi(moo, v); moo_poptmp (moo); if (!y) return MOO_NULL; } @@ -1662,17 +1661,17 @@ moo_oop_t moo_addints (moo_t* moo, moo_oop_t x, moo_oop_t y) if (MOO_OBJ_GET_CLASS(x) != MOO_OBJ_GET_CLASS(y)) { - if (IS_NBIGINT(moo, x)) + if (MOO_POINTER_IS_NBIGINT(moo, x)) { /* x is negative, y is positive */ - if (is_less_unsigned (x, y)) + if (is_less_unsigned(x, y)) { - z = subtract_unsigned_integers (moo, y, x); + z = subtract_unsigned_integers(moo, y, x); if (!z) return MOO_NULL; } else { - z = subtract_unsigned_integers (moo, x, y); + z = subtract_unsigned_integers(moo, x, y); if (!z) return MOO_NULL; MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); } @@ -1680,15 +1679,15 @@ moo_oop_t moo_addints (moo_t* moo, moo_oop_t x, moo_oop_t y) else { /* x is positive, y is negative */ - if (is_less_unsigned (x, y)) + if (is_less_unsigned(x, y)) { - z = subtract_unsigned_integers (moo, y, x); + z = subtract_unsigned_integers(moo, y, x); if (!z) return MOO_NULL; MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); } else { - z = subtract_unsigned_integers (moo, x, y); + z = subtract_unsigned_integers(moo, x, y); if (!z) return MOO_NULL; } } @@ -1697,14 +1696,14 @@ moo_oop_t moo_addints (moo_t* moo, moo_oop_t x, moo_oop_t y) { int neg; /* both are positive or negative */ - neg = (IS_NBIGINT(moo, x)); - z = add_unsigned_integers (moo, x, y); + neg = (MOO_POINTER_IS_NBIGINT(moo, x)); + z = add_unsigned_integers(moo, x, y); if (!z) return MOO_NULL; if (neg) MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); } } - return normalize_bigint (moo, z); + return normalize_bigint(moo, z); oops_einval: moo_seterrbfmt (moo, MOO_EINVAL, "invalid parameters - %O, %O", x, y); @@ -1770,7 +1769,7 @@ moo_oop_t moo_subints (moo_t* moo, moo_oop_t x, moo_oop_t y) if (MOO_OBJ_GET_CLASS(x) != MOO_OBJ_GET_CLASS(y)) { - neg = (IS_NBIGINT(moo, x)); + neg = (MOO_POINTER_IS_NBIGINT(moo, x)); z = add_unsigned_integers (moo, x, y); if (!z) return MOO_NULL; if (neg) MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); @@ -1780,14 +1779,14 @@ moo_oop_t moo_subints (moo_t* moo, moo_oop_t x, moo_oop_t y) /* both are positive or negative */ if (is_less_unsigned (x, y)) { - neg = (IS_NBIGINT(moo, x)); + neg = (MOO_POINTER_IS_NBIGINT(moo, x)); z = subtract_unsigned_integers (moo, y, x); if (!z) return MOO_NULL; if (!neg) MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); } else { - neg = (IS_NBIGINT(moo, x)); + neg = (MOO_POINTER_IS_NBIGINT(moo, x)); z = subtract_unsigned_integers (moo, x, y); /* take x's sign */ if (!z) return MOO_NULL; if (neg) MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); @@ -2083,8 +2082,8 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop } } - x_neg = (IS_NBIGINT(moo, x)); - y_neg = (IS_NBIGINT(moo, y)); + x_neg = (MOO_POINTER_IS_NBIGINT(moo, x)); + y_neg = (MOO_POINTER_IS_NBIGINT(moo, y)); moo_pushtmp (moo, &x); moo_pushtmp (moo, &y); @@ -2208,7 +2207,7 @@ moo_oop_t moo_bitatint (moo_t* moo, moo_oop_t x, moo_oop_t y) { if (!is_bigint(moo, y)) goto oops_einval; - if (IS_NBIGINT(moo, y)) return MOO_SMOOI_TO_OOP(0); + if (MOO_POINTER_IS_NBIGINT(moo, y)) return MOO_SMOOI_TO_OOP(0); /* y is definitely >= MOO_SMOOI_BITS */ if (MOO_OOP_TO_SMOOI(x) >= 0) @@ -2229,7 +2228,7 @@ moo_oop_t moo_bitatint (moo_t* moo, moo_oop_t x, moo_oop_t y) bp = v - (wp * MOO_LIW_BITS); xs = MOO_OBJ_GET_SIZE(x); - if (IS_PBIGINT(moo, x)) + if (MOO_POINTER_IS_PBIGINT(moo, x)) { if (wp >= xs) return MOO_SMOOI_TO_OOP(0); v = (MOO_OBJ_GET_LIWORD_SLOT(x)[wp] >> bp) & 1; @@ -2265,10 +2264,10 @@ moo_oop_t moo_bitatint (moo_t* moo, moo_oop_t x, moo_oop_t y) if (!is_bigint(moo, x) || !is_bigint(moo, y)) goto oops_einval; #if defined(MOO_LIMIT_OBJ_SIZE) - if (IS_NBIGINT(moo, y)) return MOO_SMOOI_TO_OOP(0); + if (MOO_POINTER_IS_NBIGINT(moo, y)) return MOO_SMOOI_TO_OOP(0); MOO_ASSERT (moo, MOO_OBJ_SIZE_BITS_MAX <= MOO_TYPE_MAX(moo_oow_t)); - if (IS_PBIGINT(moo, x)) + if (MOO_POINTER_IS_PBIGINT(moo, x)) { return MOO_SMOOI_TO_OOP (0); } @@ -2279,7 +2278,7 @@ moo_oop_t moo_bitatint (moo_t* moo, moo_oop_t x, moo_oop_t y) #else xs = MOO_OBJ_GET_SIZE(x); - if (IS_NBIGINT(moo, y)) return MOO_SMOOI_TO_OOP(0); + if (MOO_POINTER_IS_NBIGINT(moo, y)) return MOO_SMOOI_TO_OOP(0); sign = bigint_to_oow (moo, y, &w); MOO_ASSERT (moo, sign >= 0); @@ -2313,7 +2312,7 @@ moo_oop_t moo_bitatint (moo_t* moo, moo_oop_t x, moo_oop_t y) MOO_ASSERT (moo, bp >= 0 && bp < MOO_LIW_BITS); } - if (IS_PBIGINT(moo, x)) + if (MOO_POINTER_IS_PBIGINT(moo, x)) { if (wp >= xs) return MOO_SMOOI_TO_OOP(0); v = (MOO_OBJ_GET_LIWORD_SLOT(x)[wp] >> bp) & 1; @@ -2411,8 +2410,8 @@ moo_oop_t moo_bitandints (moo_t* moo, moo_oop_t x, moo_oop_t y) xs = zs; } - negx = (IS_NBIGINT(moo, x))? 1: 0; - negy = (IS_NBIGINT(moo, y))? 1: 0; + negx = (MOO_POINTER_IS_NBIGINT(moo, x))? 1: 0; + negy = (MOO_POINTER_IS_NBIGINT(moo, y))? 1: 0; if (negx && negy) { @@ -2624,8 +2623,8 @@ moo_oop_t moo_bitorints (moo_t* moo, moo_oop_t x, moo_oop_t y) xs = zs; } - negx = (IS_NBIGINT(moo, x))? 1: 0; - negy = (IS_NBIGINT(moo, y))? 1: 0; + negx = (MOO_POINTER_IS_NBIGINT(moo, x))? 1: 0; + negy = (MOO_POINTER_IS_NBIGINT(moo, y))? 1: 0; if (negx && negy) { @@ -2842,8 +2841,8 @@ moo_oop_t moo_bitxorints (moo_t* moo, moo_oop_t x, moo_oop_t y) xs = zs; } - negx = (IS_NBIGINT(moo, x))? 1: 0; - negy = (IS_NBIGINT(moo, y))? 1: 0; + negx = (MOO_POINTER_IS_NBIGINT(moo, x))? 1: 0; + negy = (MOO_POINTER_IS_NBIGINT(moo, y))? 1: 0; if (negx && negy) { @@ -3012,7 +3011,7 @@ moo_oop_t moo_bitinvint (moo_t* moo, moo_oop_t x) if (!is_bigint(moo,x)) goto oops_einval; xs = MOO_OBJ_GET_SIZE(x); - negx = (IS_NBIGINT(moo, x))? 1: 0; + negx = (MOO_POINTER_IS_NBIGINT(moo, x))? 1: 0; if (negx) { @@ -3100,7 +3099,7 @@ static MOO_INLINE moo_oop_t rshift_negative_bigint (moo_t* moo, moo_oop_t x, moo moo_lidw_t carry; moo_oow_t i, xs; - MOO_ASSERT (moo, IS_NBIGINT(moo, x)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, x)); xs = MOO_OBJ_GET_SIZE(x); moo_pushtmp (moo, &x); @@ -3163,8 +3162,8 @@ static MOO_INLINE moo_oop_t rshift_negative_bigint_and_normalize (moo_t* moo, mo moo_oow_t shift; int sign; - MOO_ASSERT (moo, IS_NBIGINT(moo, x)); - MOO_ASSERT (moo, IS_NBIGINT(moo, y)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, x)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, y)); /* for convenience in subtraction below. * it could be MOO_TYPE_MAX(moo_oow_t) @@ -3241,8 +3240,8 @@ static MOO_INLINE moo_oop_t rshift_positive_bigint_and_normalize (moo_t* moo, mo moo_oow_t zs, shift; int sign; - MOO_ASSERT (moo, IS_PBIGINT(moo, x)); - MOO_ASSERT (moo, IS_NBIGINT(moo, y)); + MOO_ASSERT (moo, MOO_POINTER_IS_PBIGINT(moo, x)); + MOO_ASSERT (moo, MOO_POINTER_IS_NBIGINT(moo, y)); zs = MOO_OBJ_GET_SIZE(x); @@ -3291,7 +3290,7 @@ static MOO_INLINE moo_oop_t lshift_bigint_and_normalize (moo_t* moo, moo_oop_t x moo_oow_t wshift, shift; int sign; - MOO_ASSERT (moo, IS_PBIGINT(moo, y)); + MOO_ASSERT (moo, MOO_POINTER_IS_PBIGINT(moo, y)); /* this loop is very inefficient as shifting is repeated * with lshift_unsigned_array(). however, this part of the @@ -3435,7 +3434,7 @@ moo_oop_t moo_bitshiftint (moo_t* moo, moo_oop_t x, moo_oop_t y) v = MOO_OOP_TO_SMOOI(x); if (v == 0) return MOO_SMOOI_TO_OOP(0); - if (IS_NBIGINT(moo, y)) + if (MOO_POINTER_IS_NBIGINT(moo, y)) { /* right shift - special case. * x is a small integer. it is just a few bytes long. @@ -3460,7 +3459,7 @@ moo_oop_t moo_bitshiftint (moo_t* moo, moo_oop_t x, moo_oop_t y) v = MOO_OOP_TO_SMOOI(y); if (v == 0) return clone_bigint (moo, x, MOO_OBJ_GET_SIZE(x)); - negx = (IS_NBIGINT(moo, x))? 1: 0; + negx = (MOO_POINTER_IS_NBIGINT(moo, x))? 1: 0; if (v > 0) { sign = 1; @@ -3483,8 +3482,8 @@ moo_oop_t moo_bitshiftint (moo_t* moo, moo_oop_t x, moo_oop_t y) if (!is_bigint(moo,x) || !is_bigint(moo, y)) goto oops_einval; bigint_and_bigint: - negx = (IS_NBIGINT(moo, x))? 1: 0; - negy = (IS_NBIGINT(moo, y))? 1: 0; + negx = (MOO_POINTER_IS_NBIGINT(moo, x))? 1: 0; + negy = (MOO_POINTER_IS_NBIGINT(moo, y))? 1: 0; sign = bigint_to_oow (moo, y, &shift); if (sign == 0) @@ -3807,21 +3806,14 @@ oops_einval: return MOO_NULL; } -static moo_oow_t oow_to_text (moo_t* moo, moo_oow_t w, int radix, moo_ooch_t* buf) +static moo_oow_t oow_to_text (moo_t* moo, moo_oow_t w, int flagged_radix, moo_ooch_t* buf) { moo_ooch_t* ptr; const char* _digitc; + int radix; - if (radix < 0) - { - _digitc = _digitc_lower; - radix = -radix; - } - else - { - _digitc = _digitc_upper; - } - + radix = flagged_radix & 0xFF; + _digitc = _digitc_array[!!(flagged_radix & MOO_INTTOSTR_LOWERCASE)]; MOO_ASSERT (moo, radix >= 2 && radix <= 36); ptr = buf; @@ -3900,12 +3892,12 @@ moo_oop_t moo_gtints (moo_t* moo, moo_oop_t x, moo_oop_t y) else if (MOO_OOP_IS_SMOOI(x)) { if (!is_bigint(moo, y)) goto oops_einval; - return (IS_NBIGINT(moo, y))? moo->_true: moo->_false; + return (MOO_POINTER_IS_NBIGINT(moo, y))? moo->_true: moo->_false; } else if (MOO_OOP_IS_SMOOI(y)) { if (!is_bigint(moo, x)) goto oops_einval; - return (IS_PBIGINT(moo, x))? moo->_true: moo->_false; + return (MOO_POINTER_IS_PBIGINT(moo, x))? moo->_true: moo->_false; } else { @@ -3927,12 +3919,12 @@ moo_oop_t moo_geints (moo_t* moo, moo_oop_t x, moo_oop_t y) else if (MOO_OOP_IS_SMOOI(x)) { if (!is_bigint(moo, y)) goto oops_einval; - return (IS_NBIGINT(moo, y))? moo->_true: moo->_false; + return (MOO_POINTER_IS_NBIGINT(moo, y))? moo->_true: moo->_false; } else if (MOO_OOP_IS_SMOOI(y)) { if (!is_bigint(moo, x)) goto oops_einval; - return (IS_PBIGINT(moo, x))? moo->_true: moo->_false; + return (MOO_POINTER_IS_PBIGINT(moo, x))? moo->_true: moo->_false; } else { @@ -3954,12 +3946,12 @@ moo_oop_t moo_ltints (moo_t* moo, moo_oop_t x, moo_oop_t y) else if (MOO_OOP_IS_SMOOI(x)) { if (!is_bigint(moo, y)) goto oops_einval; - return (IS_PBIGINT(moo, y))? moo->_true: moo->_false; + return (MOO_POINTER_IS_PBIGINT(moo, y))? moo->_true: moo->_false; } else if (MOO_OOP_IS_SMOOI(y)) { if (!is_bigint(moo, x)) goto oops_einval; - return (IS_NBIGINT(moo, x))? moo->_true: moo->_false; + return (MOO_POINTER_IS_NBIGINT(moo, x))? moo->_true: moo->_false; } else { @@ -3981,12 +3973,12 @@ moo_oop_t moo_leints (moo_t* moo, moo_oop_t x, moo_oop_t y) else if (MOO_OOP_IS_SMOOI(x)) { if (!is_bigint(moo, y)) goto oops_einval; - return (IS_PBIGINT(moo, y))? moo->_true: moo->_false; + return (MOO_POINTER_IS_PBIGINT(moo, y))? moo->_true: moo->_false; } else if (MOO_OOP_IS_SMOOI(y)) { if (!is_bigint(moo, x)) goto oops_einval; - return (IS_NBIGINT(moo, x))? moo->_true: moo->_false; + return (MOO_POINTER_IS_NBIGINT(moo, x))? moo->_true: moo->_false; } else { @@ -4091,11 +4083,11 @@ moo_oop_t moo_absint (moo_t* moo, moo_oop_t x) x = MOO_SMOOI_TO_OOP(v); } } - else if (IS_NBIGINT(moo, x)) + else if (MOO_POINTER_IS_NBIGINT(moo, x)) { x = _clone_bigint(moo, x, MOO_OBJ_GET_SIZE(x), moo->_large_positive_integer); } - else if (IS_PBIGINT(moo, x)) + else if (MOO_POINTER_IS_PBIGINT(moo, x)) { /* do nothing. return x without change. * [THINK] but do i need to clone a positive bigint? */ @@ -4109,7 +4101,7 @@ moo_oop_t moo_absint (moo_t* moo, moo_oop_t x) return x; } -moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int radix) +moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int flagged_radix) { moo_ooi_t v = 0; moo_oow_t w; @@ -4126,18 +4118,11 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int radix) moo_ooch_t* xbuf = MOO_NULL; moo_oow_t xlen = 0, seglen, reqcapa; + int radix; const char* _digitc; - int orgradix = radix; - if (radix < 0) - { - _digitc = _digitc_lower; - radix = -radix; - } - else - { - _digitc = _digitc_upper; - } + radix = flagged_radix & 0xFF; + _digitc = _digitc_array[!!(flagged_radix & MOO_INTTOSTR_LOWERCASE)]; MOO_ASSERT (moo, radix >= 2 && radix <= 36); if (!moo_isint(moo,num)) goto oops_einval; @@ -4163,10 +4148,17 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int radix) xbuf = moo->inttostr.xbuf.ptr; } - xlen = oow_to_text(moo, w, orgradix, xbuf); + xlen = oow_to_text(moo, w, flagged_radix, xbuf); if (v < 0) xbuf[xlen++] = '-'; reverse_string (xbuf, xlen); + 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 */ + moo->inttostr.xbuf.len = xlen; + return moo->_nil; + } return moo_makestring(moo, xbuf, xlen); } @@ -4223,7 +4215,16 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int radix) } MOO_ASSERT (moo, xpos >= 1); - if (IS_NBIGINT(moo, num)) xbuf[--xpos] = '-'; + if (MOO_POINTER_IS_NBIGINT(moo, num)) xbuf[--xpos] = '-'; + + 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 */ + MOO_MEMMOVE (&xbuf[0], &xbuf[xpos], MOO_SIZEOF(*xbuf) * (xlen - xpos)); + moo->inttostr.xbuf.len = xlen - xpos; + return moo->_nil; + } return moo_makestring(moo, &xbuf[xpos], xlen - xpos); } @@ -4313,7 +4314,7 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int radix) #else # error UNSUPPORTED LIW BIT SIZE #endif - seglen = oow_to_text (moo, w, orgradix, &xbuf[xlen]); + seglen = oow_to_text (moo, w, flagged_radix, &xbuf[xlen]); xlen += seglen; if (r == a) break; /* reached the last block */ @@ -4327,8 +4328,15 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int radix) } while (1); - if (IS_NBIGINT(moo, num)) xbuf[xlen++] = '-'; + if (MOO_POINTER_IS_NBIGINT(moo, num)) xbuf[xlen++] = '-'; reverse_string (xbuf, xlen); + 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 */ + moo->inttostr.xbuf.len = xlen; + return moo->_nil; + } return moo_makestring(moo, xbuf, xlen); diff --git a/moo/lib/exec.c b/moo/lib/exec.c index e9f922e..a7c2f1d 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -2831,7 +2831,7 @@ static moo_pfrc_t pf_integer_add (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_addints (moo, rcv, arg); + res = moo_addints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -2847,7 +2847,7 @@ static moo_pfrc_t pf_integer_sub (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_subints (moo, rcv, arg); + res = moo_subints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -2863,7 +2863,7 @@ static moo_pfrc_t pf_integer_mul (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_mulints (moo, rcv, arg); + res = moo_mulints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -2975,7 +2975,7 @@ static moo_pfrc_t pf_integer_bitand (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_bitandints (moo, rcv, arg); + res = moo_bitandints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -2991,7 +2991,7 @@ static moo_pfrc_t pf_integer_bitor (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_bitorints (moo, rcv, arg); + res = moo_bitorints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3007,7 +3007,7 @@ static moo_pfrc_t pf_integer_bitxor (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_bitxorints (moo, rcv, arg); + res = moo_bitxorints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3022,7 +3022,7 @@ static moo_pfrc_t pf_integer_bitinv (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs rcv = MOO_STACK_GETRCV(moo, nargs); - res = moo_bitinvint (moo, rcv); + res = moo_bitinvint(moo, rcv); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3038,7 +3038,7 @@ static moo_pfrc_t pf_integer_bitshift (moo_t* moo, moo_mod_t* mod, moo_ooi_t nar rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_bitshiftint (moo, rcv, arg); + res = moo_bitshiftint(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3054,7 +3054,7 @@ static moo_pfrc_t pf_integer_eq (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_eqints (moo, rcv, arg); + res = moo_eqints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3070,7 +3070,7 @@ static moo_pfrc_t pf_integer_ne (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_neints (moo, rcv, arg); + res = moo_neints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3086,7 +3086,7 @@ static moo_pfrc_t pf_integer_lt (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_ltints (moo, rcv, arg); + res = moo_ltints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3102,7 +3102,7 @@ static moo_pfrc_t pf_integer_gt (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_gtints (moo, rcv, arg); + res = moo_gtints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3118,7 +3118,7 @@ static moo_pfrc_t pf_integer_le (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_leints (moo, rcv, arg); + res = moo_leints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3134,7 +3134,7 @@ static moo_pfrc_t pf_integer_ge (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) rcv = MOO_STACK_GETRCV(moo, nargs); arg = MOO_STACK_GETARG(moo, nargs, 0); - res = moo_geints (moo, rcv, arg); + res = moo_geints(moo, rcv, arg); if (!res) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, res); @@ -3155,7 +3155,7 @@ static moo_pfrc_t pf_integer_inttostr (moo_t* moo, moo_mod_t* mod, moo_ooi_t nar radix = MOO_OOP_TO_SMOOI(arg); if (radix < 2 || radix > 36) return MOO_PF_FAILURE; - str = moo_inttostr (moo, rcv, radix); + str = moo_inttostr(moo, rcv, radix); if (!str) return (moo->errnum == MOO_EINVAL? MOO_PF_FAILURE: MOO_PF_HARD_FAILURE); MOO_STACK_SETRET (moo, nargs, str); @@ -3389,6 +3389,29 @@ static moo_pfrc_t pf_error_as_string (moo_t* moo, moo_mod_t* mod, moo_ooi_t narg return MOO_PF_SUCCESS; } +static moo_pfrc_t pf_strfmt (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) +{ + moo_oop_t rcv; + + rcv = MOO_STACK_GETRCV(moo, nargs); + MOO_PF_CHECK_RCV (moo, MOO_OBJ_IS_CHAR_POINTER(rcv)); + + if (moo_sprintfmtst(moo, nargs) <= -1) + { + MOO_STACK_SETRETTOERRNUM (moo, nargs); + } + else + { + moo_oop_t str; + str = moo_makestring(moo, moo->sprintf.xbuf.ptr, moo->sprintf.xbuf.len); + if (!str) return MOO_PF_FAILURE; + + MOO_STACK_SETRET (moo, nargs, str); + } + + return MOO_PF_SUCCESS; +} + static moo_pfrc_t pf_strlen (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) { moo_oop_t rcv, ret; @@ -3574,6 +3597,7 @@ static pf_t pftab[] = { "SmallPointer_putUint64", { moo_pf_smptr_put_uint64, 2, 2 } }, { "SmallPointer_putUint8", { moo_pf_smptr_put_uint8, 2, 2 } }, + { "String_strfmt", { pf_strfmt, 0, MA } }, { "String_strlen", { pf_strlen, 0, 0 } }, { "System_calloc", { moo_pf_system_calloc, 1, 1 } }, diff --git a/moo/lib/logfmt.c b/moo/lib/logfmt.c index c128f98..31cbf9b 100644 --- a/moo/lib/logfmt.c +++ b/moo/lib/logfmt.c @@ -130,14 +130,14 @@ static moo_bch_t bch_nullstr[] = { '(','n','u','l','l', ')','\0' }; typedef int (*moo_fmtout_putch_t) ( moo_t* moo, - moo_bitmask_t mask, + moo_bitmask_t mask, moo_ooch_t c, moo_oow_t len ); typedef int (*moo_fmtout_putcs_t) ( moo_t* moo, - moo_bitmask_t mask, + moo_bitmask_t mask, const moo_ooch_t* ptr, moo_oow_t len ); @@ -146,7 +146,7 @@ typedef struct moo_fmtout_t moo_fmtout_t; struct moo_fmtout_t { moo_oow_t count; /* out */ - moo_bitmask_t mask; /* in */ + moo_bitmask_t mask; /* in */ moo_fmtout_putch_t putch; /* in */ moo_fmtout_putcs_t putcs; /* in */ }; @@ -417,7 +417,7 @@ static int print_object (moo_t* moo, moo_bitmask_t mask, moo_oop_t oop, outbfmt_ if (c == moo->_large_negative_integer) { moo_oow_t i; - if (outbfmt (moo, mask, "-16r") <= -1) return -1; + if (outbfmt(moo, mask, "-16r") <= -1) return -1; for (i = MOO_OBJ_GET_SIZE(oop); i > 0;) { if (outbfmt(moo, mask, "%0*lX", (int)(MOO_SIZEOF(moo_liw_t) * 2), (unsigned long int)(MOO_OBJ_GET_LIWORD_SLOT(oop)[--i])) <= -1) return -1; @@ -823,3 +823,740 @@ void moo_seterrufmtv (moo_t* moo, moo_errnum_t errnum, const moo_uch_t* fmt, va_ _errufmtv (moo, fmt, &fo, ap); moo->errnum = errnum; } + + +/* -------------------------------------------------------------------------- + * SUPPORT FOR FORMATTED OUTPUT TO BE USED BY BUILTIN PRIMITIVE FUNCTIONS + * -------------------------------------------------------------------------- */ + +#define PRINT_OOCH(c,n) do { \ + if (n > 0) { \ + int xx; \ + if ((xx = data->putch(moo, data->mask, c, n)) <= -1) goto oops; \ + if (xx == 0) goto done; \ + data->count += n; \ + } \ +} while (0) + +#define PRINT_OOCS(ptr,len) do { \ + if (len > 0) { \ + int xx; \ + if ((xx = data->putcs(moo, data->mask, ptr, len)) <= -1) goto oops; \ + if (xx == 0) goto done; \ + data->count += len; \ + } \ +} while(0) + +#define GET_NEXT_ARG_TO(moo,nargs,arg_state,arg) do { \ + if ((arg_state)->idx >= nargs) { (arg_state)->stop = 1; goto invalid_format; } \ + arg = MOO_STACK_GETARG(moo, nargs, (arg_state)->idx); \ + (arg_state)->idx++; \ +} while(0) + +#define GET_NEXT_CHAR_TO(moo,fmt,fmtend,ch) do { \ + if (fmt >= fmtend) ch = MOO_OOCI_EOF; \ + else { ch = *(fmt); (fmt)++; }\ +} while(0) + +static MOO_INLINE int print_formatted (moo_t* moo, moo_ooi_t nargs, moo_fmtout_t* data, moo_outbfmt_t outbfmt, int ignore_rcv) +{ + const moo_ooch_t* fmt, * fmtend; + const moo_ooch_t* checkpoint, * percent; + + int n, radix, neg, sign, radix_flags; + moo_ooi_t extra, width, precision; + moo_ooch_t padc, ooch; + moo_ooci_t ch; + int flagc; + + struct + { + moo_ooi_t idx; + int stop; + } arg_state; + moo_oop_t arg; + + if (ignore_rcv) + { + arg = MOO_STACK_GETARG(moo, nargs, 0); + arg_state.idx = 1; + } + else + { + arg = MOO_STACK_GETRCV(moo, nargs); + arg_state.idx = 0; + } + + if (!MOO_OOP_IS_POINTER(arg) || MOO_OBJ_GET_FLAGS_TYPE(arg) != MOO_OBJ_TYPE_CHAR) + { + moo_ooi_t i; + /* if the first argument is not a valid formatting string, + * print all arguments as objects */ + if (print_object(moo, data->mask, arg, outbfmt) <= -1) goto oops; + for (i = arg_state.idx; i < nargs; i++) + { + arg = MOO_STACK_GETARG(moo, nargs, i); + if (print_object(moo, data->mask, arg, outbfmt) <= -1) goto oops; + } + return 0; + } + + arg_state.stop = 0; + + fmt = MOO_OBJ_GET_CHAR_SLOT(arg); + fmtend = fmt + MOO_OBJ_GET_SIZE(arg); + + data->count = 0; + + while (1) + { + checkpoint = fmt; + + while (1) + { + GET_NEXT_CHAR_TO (moo, fmt, fmtend, ch); + if (ch == '%' && !arg_state.stop) break; + + if (ch == MOO_OOCI_EOF) + { + /* fmt is not advanced when it is length-bounded. + * so not fmt - checkpoint - 1 */ + PRINT_OOCS (checkpoint, fmt - checkpoint); + goto done; + } + } + PRINT_OOCS (checkpoint, fmt - checkpoint - 1); + + percent = fmt - 1; + + padc = ' '; + width = 0; precision = 0; + neg = 0; sign = 0; + + flagc = 0; + radix_flags = MOO_INTTOSTR_NONEWOBJ; + + reswitch: + GET_NEXT_CHAR_TO (moo, fmt, fmtend, ch); + switch (ch) + { + case '%': /* %% */ + ooch = ch; + goto print_char; + + /* flag characters */ + case '.': + if (flagc & FLAGC_DOT) goto invalid_format; + flagc |= FLAGC_DOT; + goto reswitch; + + case '#': + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SHARP; + goto reswitch; + + case ' ': + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SPACE; + goto reswitch; + + case '+': /* place sign for signed conversion */ + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + flagc |= FLAGC_SIGN; + goto reswitch; + + case '-': /* left adjusted */ + if (flagc & (FLAGC_WIDTH | FLAGC_DOT | FLAGC_LENMOD)) goto invalid_format; + if (flagc & FLAGC_DOT) + { + goto invalid_format; + } + else + { + flagc |= FLAGC_LEFTADJ; + if (flagc & FLAGC_ZEROPAD) + { + padc = ' '; + flagc &= ~FLAGC_ZEROPAD; + } + } + + goto reswitch; + + case '*': /* take the length from the parameter */ + if (flagc & FLAGC_DOT) + { + if (flagc & (FLAGC_STAR2 | FLAGC_PRECISION)) goto invalid_format; + flagc |= FLAGC_STAR2; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (moo_inttoooi(moo, arg, &precision) <= -1) goto invalid_format; + if (precision < 0) + { + /* if precision is less than 0, + * treat it as if no .precision is specified */ + flagc &= ~FLAGC_DOT; + precision = 0; + } + } + else + { + if (flagc & (FLAGC_STAR1 | FLAGC_WIDTH)) goto invalid_format; + flagc |= FLAGC_STAR1; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (moo_inttoooi(moo, arg, &width) <= -1) goto invalid_format; + if (width < 0) + { + flagc |= FLAGC_LEFTADJ; + width = -width; + } + } + goto reswitch; + + case '0': /* zero pad */ + if (flagc & FLAGC_LENMOD) goto invalid_format; + if (!(flagc & (FLAGC_DOT | FLAGC_LEFTADJ))) + { + padc = '0'; + flagc |= FLAGC_ZEROPAD; + goto reswitch; + } + /* end of flags characters */ + + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (flagc & FLAGC_LENMOD) goto invalid_format; + for (n = 0;; ++fmt) + { + n = n * 10 + ch - '0'; + ch = *fmt; + if (ch < '0' || ch > '9') break; + } + if (flagc & FLAGC_DOT) + { + if (flagc & FLAGC_STAR2) goto invalid_format; + precision = n; + flagc |= FLAGC_PRECISION; + } + else + { + if (flagc & FLAGC_STAR1) goto invalid_format; + width = n; + flagc |= FLAGC_WIDTH; + } + goto reswitch; + + /* integer conversions */ + case 'd': + case 'i': /* signed conversion */ + radix = 10; + sign = 1; + goto print_integer; + case 'o': + radix = 8; + goto print_integer; + case 'u': + radix = 10; + goto print_integer; + case 'x': + radix_flags |= MOO_INTTOSTR_LOWERCASE; + case 'X': + radix = 16; + goto print_integer; + case 'b': + radix = 2; + goto print_integer; + /* end of integer conversions */ + + case 'f': + { + const moo_ooch_t* nsptr; + moo_oow_t nslen; + moo_oow_t scale = 0; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (MOO_OOP_IS_CHAR(arg)) + { + arg = MOO_SMOOI_TO_OOP(MOO_OOP_TO_CHAR(arg)); + } + else if (MOO_OOP_IS_FPDEC(moo, arg)) + { + moo_oop_fpdec_t fa = (moo_oop_fpdec_t)arg; + scale = MOO_OOP_TO_SMOOI(fa->scale); + arg = fa->value; + } + + if (!moo_inttostr(moo, arg, 10 | MOO_INTTOSTR_NONEWOBJ)) + { + MOO_LOG1 (moo, MOO_LOG_WARN | MOO_LOG_UNTYPED, "unable to convert %O to string \n", arg); + goto invalid_format; + } + + nsptr = moo->inttostr.xbuf.ptr; + nslen = moo->inttostr.xbuf.len; + MOO_ASSERT (moo, nslen > 0); + + if (nsptr[0] == '-') + { + MOO_ASSERT (moo, (MOO_OOP_IS_SMOOI(arg) && MOO_OOP_TO_SMOOI(arg) < 0) || MOO_OOP_IS_NBIGINT(moo,arg)); + nsptr++; + nslen--; + neg = 1; + } + + if (!(flagc & FLAGC_DOT)) + { + precision = scale; + if (precision <= 0) precision = 1; + } + + if ((flagc & FLAGC_DOT) && precision < scale) + { + moo_oow_t diff = scale - precision; + scale = precision; + nslen = (nslen < diff)? 0: (nslen - diff); + } + + if (nslen < scale + 1) + { + extra = 1; + if (precision > 0) extra += 1 + scale; + } + else + { + extra = 0; + if (nslen > 0) extra += nslen - scale; + if (precision > 0) + { + extra += 1; + if (nslen > 0) extra += scale; + } + } + + if (neg) extra++; + else if (flagc & FLAGC_SIGN) extra++; + else if (flagc & FLAGC_SPACE) extra++; + + if ((flagc & FLAGC_DOT) && precision > scale) + { + /* trailing zeros in the fractional part */ + extra += precision - scale; + } + + if (!(flagc & FLAGC_LEFTADJ) && !(flagc & FLAGC_ZEROPAD) && width > extra) + { + width -= extra; + PRINT_OOCH (padc, width); + width = 0; + } + if (neg) PRINT_OOCH ('-', 1); + else if (flagc & FLAGC_SIGN) PRINT_OOCH ('+', 1); + else if (flagc & FLAGC_SPACE) PRINT_OOCH (' ', 1); + + if (!(flagc & FLAGC_LEFTADJ) && width > extra) + { + width -= extra; + PRINT_OOCH (padc, width); + } + + if (nslen < scale + 1) + { + PRINT_OOCH ('0', 1); + if (precision > 0) + { + PRINT_OOCH ('.', 1); + PRINT_OOCH ('0', scale - nslen); + PRINT_OOCS (nsptr, nslen); + } + } + else + { + if (nslen > 0) PRINT_OOCS (nsptr, nslen - scale); + if (precision > 0) + { + PRINT_OOCH ('.', 1); + if (nslen > 0) PRINT_OOCS (&nsptr[nslen - scale], scale); + } + } + if (precision > scale) + { + /* trailing zeros in the fractional part */ + PRINT_OOCH ('0', precision - scale); + } + + if ((flagc & FLAGC_LEFTADJ) && width > extra) + { + width -= extra; + PRINT_OOCH (padc, width); + } + break; + } + + case 'c': + case 'C': + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (MOO_OOP_IS_SMOOI(arg)) arg = MOO_CHAR_TO_OOP(MOO_OOP_TO_SMOOI(arg)); + if (!MOO_OOP_IS_CHAR(arg)) goto invalid_format; + ooch = MOO_OOP_TO_CHAR(arg); + + print_char: + /* zeropad must not take effect for 'c' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + + /* precision 0 doesn't kill the letter */ + width--; + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PRINT_OOCH (padc, width); + PRINT_OOCH (ooch, 1); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PRINT_OOCH (padc, width); + break; + + case 's': + case 'S': + { + const moo_ooch_t* oosp; + moo_oow_t oosl; + + /* zeropad must not take effect for 'S' */ + if (flagc & FLAGC_ZEROPAD) padc = ' '; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (!MOO_OOP_IS_POINTER(arg) || MOO_OBJ_GET_FLAGS_TYPE(arg) != MOO_OBJ_TYPE_CHAR) goto invalid_format; + + oosp = MOO_OBJ_GET_CHAR_SLOT(arg); + oosl = MOO_OBJ_GET_SIZE(arg); + + if (flagc & FLAGC_DOT) + { + if (oosl > precision) oosl = precision; + } + width -= oosl; + + if (!(flagc & FLAGC_LEFTADJ) && width > 0) PRINT_OOCH (padc, width); + PRINT_OOCS (oosp, oosl); + if ((flagc & FLAGC_LEFTADJ) && width > 0) PRINT_OOCH (padc, width); + break; + } + + case 'O': /* object - ignore precision, width, adjustment */ + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + /*if (print_object(moo, (data->mask & ~MOO_LOG_PREFER_JSON), arg, outbfmt) <= -1) goto oops;*/ + if (print_object(moo, data->mask, arg, outbfmt) <= -1) goto oops; + break; + +#if 0 + case 'J': + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (print_object(moo, (data->mask | MOO_LOG_PREFER_JSON), arg, outbfmt) <= -1) goto oops; + break; +#endif + + print_integer: + { + const moo_ooch_t* nsptr; + moo_oow_t nslen; + + GET_NEXT_ARG_TO (moo, nargs, &arg_state, arg); + if (MOO_OOP_IS_CHAR(arg)) + { + arg = MOO_SMOOI_TO_OOP(MOO_OOP_TO_CHAR(arg)); + } + else if (MOO_OOP_IS_FPDEC(moo, arg)) + { + moo_oop_t nv; + moo_oop_fpdec_t fa = (moo_oop_fpdec_t)arg; + + /* the given number for integer output is a fixed-point decimal. + * i will drop all digits after the fixed point */ + moo_pushtmp (moo, &arg); + nv = moo_truncfpdecval(moo, fa->value, MOO_OOP_TO_SMOOI(fa->scale), 0); + moo_poptmp (moo); + if (!nv) + { + MOO_LOG1 (moo, MOO_LOG_WARN | MOO_LOG_UNTYPED, "unable to truncate a fixed-point number %O to an integer for output\n", arg); + goto invalid_format; + } + + arg = nv; + } + + if (!moo_inttostr(moo, arg, radix | radix_flags)) + { + /*moo_seterrbfmt (moo, MOO_EINVAL, "not a valid number - %O", arg); + goto oops;*/ + MOO_LOG1 (moo, MOO_LOG_WARN | MOO_LOG_UNTYPED, "unable to convert integer %O to string \n", arg); + goto invalid_format; + } + + nsptr = moo->inttostr.xbuf.ptr; + nslen = moo->inttostr.xbuf.len; + + MOO_ASSERT (moo, nslen > 0); + if (nsptr[0] == '-') + { + /* a negative number was given. i must skip the minus sign + * added by moo_inttostr() for a negative number. */ + MOO_ASSERT (moo, (MOO_OOP_IS_SMOOI(arg) && MOO_OOP_TO_SMOOI(arg) < 0) || MOO_OOP_IS_NBIGINT(moo,arg)); + nsptr++; + nslen--; + } + + extra = nslen; + if (sign && ((MOO_OOP_IS_SMOOI(arg) && MOO_OOP_TO_SMOOI(arg) < 0) || MOO_OOP_IS_NBIGINT(moo,arg))) neg = 1; + + if ((flagc & FLAGC_SHARP) && arg != MOO_SMOOI_TO_OOP(0)) + { + if (radix == 2 || radix == 8 || radix == 16) extra += 2; + } + if (neg) extra++; + else if (flagc & FLAGC_SIGN) extra++; + else if (flagc & FLAGC_SPACE) extra++; + + if ((flagc & FLAGC_DOT) && precision > nslen) + { + /* extra zeros for precision specified */ + extra += (precision - nslen); + } + + if (!(flagc & FLAGC_LEFTADJ) && !(flagc & FLAGC_ZEROPAD) && width > 0 && (width -= extra) > 0) + { + PRINT_OOCH (padc, width); + width = 0; + } + + if (neg) PRINT_OOCH ('-', 1); + else if (flagc & FLAGC_SIGN) PRINT_OOCH ('+', 1); + else if (flagc & FLAGC_SPACE) PRINT_OOCH (' ', 1); + + if ((flagc & FLAGC_SHARP) && arg != MOO_SMOOI_TO_OOP(0)) + { + if (radix == 2) + { + PRINT_OOCH ('2', 1); + PRINT_OOCH ('r', 1); + } + if (radix == 8) + { + PRINT_OOCH ('8', 1); + PRINT_OOCH ('r', 1); + } + else if (radix == 16) + { + PRINT_OOCH ('1', 1); + PRINT_OOCH ('6', 1); + PRINT_OOCH ('r', 1); + } + } + + if ((flagc & FLAGC_DOT) && precision > nslen) + { + /* extra zeros for precision specified */ + PRINT_OOCH ('0', precision - nslen); + } + + if (!(flagc & FLAGC_LEFTADJ) && width > 0 && (width -= extra) > 0) + { + PRINT_OOCH (padc, width); + } + + PRINT_OOCS (nsptr, nslen); + + if ((flagc & FLAGC_LEFTADJ) && width > 0 && (width -= extra) > 0) + { + PRINT_OOCH (padc, width); + } + break; + } + + invalid_format: + PRINT_OOCS (percent, fmt - percent); + break; + + default: + PRINT_OOCS (percent, fmt - percent); + /* + * Since we ignore an formatting argument it is no + * longer safe to obey the remaining formatting + * arguments as the arguments will no longer match + * the format specs. + */ + arg_state.stop = 1; + break; + } + } + +done: + return 0; + +oops: + return -1; +} + +#if 0 +/* -------------------------------------------------------------------------- + * SUPPORT FOR THE BUILTIN PRINTF PRIMITIVE FUNCTION + * -------------------------------------------------------------------------- */ + +int moo_printfmtst (moo_t* moo, moo_ooi_t nargs) +{ + moo_fmtout_t fo; + MOO_MEMSET (&fo, 0, MOO_SIZEOF(fo)); + fo.putch = put_prch; + fo.putcs = put_prcs; + return print_formatted(moo, nargs, &fo, moo_proutbfmt, 0); +} + +/* -------------------------------------------------------------------------- + * SUPPORT FOR THE BUILTIN LOGF PRIMITIVE FUNCTION + * -------------------------------------------------------------------------- */ + +int moo_logfmtst (moo_t* moo, moo_ooi_t nargs) +{ + moo_fmtout_t fo; + + MOO_MEMSET (&fo, 0, MOO_SIZEOF(fo)); + fo.mask = MOO_LOG_FATAL | MOO_LOG_APP; + + if (moo->log.default_type_mask & MOO_LOG_ALL_TYPES) + { + /* if a type is given, it's not untyped any more. + * mask off the UNTYPED bit */ + fo.mask &= ~MOO_LOG_UNTYPED; + + /* if the default_type_mask has the UNTYPED bit on, + * it'll get turned back on */ + fo.mask |= (moo->log.default_type_mask & MOO_LOG_ALL_TYPES); + } + + fo.putch = put_logch; + fo.putcs = put_logcs; + return print_formatted(moo, nargs, &fo, moo_logbfmt, 0); +} +#endif + +/* -------------------------------------------------------------------------- + * SUPPORT FOR THE BUILTIN SPRINTF PRIMITIVE FUNCTION + * -------------------------------------------------------------------------- */ +static int put_sprcs (moo_t* moo, moo_bitmask_t mask, const moo_ooch_t* ptr, moo_oow_t len) +{ + if (len > moo->sprintf.xbuf.capa - moo->sprintf.xbuf.len) + { + moo_ooch_t* tmp; + moo_oow_t newcapa; + + newcapa = moo->sprintf.xbuf.len + len + 1; + newcapa = MOO_ALIGN_POW2(newcapa, 256); + + tmp = (moo_ooch_t*)moo_reallocmem(moo, moo->sprintf.xbuf.ptr, newcapa * MOO_SIZEOF(*tmp)); + if (!tmp) return -1; + + moo->sprintf.xbuf.ptr = tmp; + moo->sprintf.xbuf.capa = newcapa; + } + + MOO_MEMCPY (&moo->sprintf.xbuf.ptr[moo->sprintf.xbuf.len], ptr, len * MOO_SIZEOF(*ptr)); + moo->sprintf.xbuf.len += len; + return 1; /* success */ +} + +static int put_sprch (moo_t* moo, moo_bitmask_t mask, moo_ooch_t ch, moo_oow_t len) +{ + if (len > moo->sprintf.xbuf.capa - moo->sprintf.xbuf.len) + { + moo_ooch_t* tmp; + moo_oow_t newcapa; + + newcapa = moo->sprintf.xbuf.len + len + 1; + newcapa = MOO_ALIGN_POW2(newcapa, 256); + + tmp = (moo_ooch_t*)moo_reallocmem(moo, moo->sprintf.xbuf.ptr, newcapa * MOO_SIZEOF(*tmp)); + if (!tmp) return -1; + + moo->sprintf.xbuf.ptr = tmp; + moo->sprintf.xbuf.capa = newcapa; + } + + while (len > 0) + { + --len; + moo->sprintf.xbuf.ptr[moo->sprintf.xbuf.len++] = ch; + } + + return 1; /* success */ +} + +static moo_ooi_t __sprbfmtv (moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt, ...); + +static int _sprbfmtv (moo_t* moo, const moo_bch_t* fmt, moo_fmtout_t* data, va_list ap) +{ + return __logbfmtv (moo, fmt, data, ap, __sprbfmtv); +} + +/* +static int _sprufmtv (moo_t* moo, const moo_uch_t* fmt, moo_fmtout_t* data, va_list ap) +{ + return __logufmtv (moo, fmt, data, ap, __sprbfmtv); +}*/ + +static moo_ooi_t __sprbfmtv (moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt, ...) +{ + va_list ap; + moo_fmtout_t fo; + + fo.mask = mask; /* not used */ + fo.putch = put_sprch; + fo.putcs = put_sprcs; + + va_start (ap, fmt); + _sprbfmtv (moo, fmt, &fo, ap); + va_end (ap); + + return fo.count; +} + +moo_ooi_t moo_sproutbfmt (moo_t* moo, moo_bitmask_t mask, const moo_bch_t* fmt, ...) +{ + int x; + va_list ap; + moo_fmtout_t fo; + + fo.mask = mask; + fo.putch = put_sprch; + fo.putcs = put_sprcs; + + va_start (ap, fmt); + x = _sprbfmtv(moo, fmt, &fo, ap); + va_end (ap); + + return (x <= -1)? -1: fo.count; +} + +/* +moo_ooi_t moo_sproutufmt (moo_t* moo, moo_bitmask_t mask, const moo_uch_t* fmt, ...) +{ + int x; + va_list ap; + moo_fmtout_t fo; + + fo.mask = mask; + fo.putch = put_sprch; + fo.putcs = put_sprcs; + + va_start (ap, fmt); + x = _sprufmtv (moo, fmt, &fo, ap); + va_end (ap); + + return (x <= -1)? -1: fo.count; +}*/ + + +int moo_sprintfmtst (moo_t* moo, moo_ooi_t nargs) +{ + /* format a string using the receiver and arguments on the stack */ + moo_fmtout_t fo; + MOO_MEMSET (&fo, 0, MOO_SIZEOF(fo)); + fo.putch = put_sprch; + fo.putcs = put_sprcs; + moo->sprintf.xbuf.len = 0; + return print_formatted(moo, nargs, &fo, moo_sproutbfmt, 0); +} diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index ea85440..b7951fc 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -257,6 +257,24 @@ #endif +#define MOO_OOP_IS_PBIGINT(moo,x) (MOO_CLASSOF(moo,x) == (moo)->_large_positive_integer) +#define MOO_OOP_IS_NBIGINT(moo,x) (MOO_CLASSOF(moo,x) == (moo)->_large_negative_integer) +#define MOO_OOP_IS_BIGINT(moo,x) (MOO_OOP_IS_PBIGINT(moo,x) || MOO_OOP_IS_NBIGINT(moo,x)) + +#define MOO_POINTER_IS_PBIGINT(moo,x) (MOO_OBJ_GET_CLASS(x) == (moo)->_large_positive_integer) +#define MOO_POINTER_IS_NBIGINT(moo,x) (MOO_OBJ_GET_CLASS(x) == (moo)->_large_negative_integer) +#define MOO_POINTER_IS_BIGINT(moo,x) (MOO_OOP_IS_PBIGINT(moo,x) || MOO_OOP_IS_NBIGINT(moo,x)) + +#define MOO_OOP_IS_FPDEC(moo,x) (MOO_CLASSOF(moo,x) == (moo)->_fixed_point_decimal) +#define MOO_POINTER_IS_FPDEC(moo,x) (MOO_OBJ_GET_CLASS(x) == (moo)->_fixed_point_Decimal) + +typedef moo_ooi_t (*moo_outbfmt_t) ( + moo_t* moo, + moo_bitmask_t mask, + const moo_bch_t* fmt, + ... +); + #if defined(MOO_INCLUDE_COMPILER) /* ========================================================================= */ @@ -981,7 +999,6 @@ enum moo_bcode_t BCODE_NOOP = 0xFF }; - /* i don't want an error raised inside the callback to override * the existing error number and message. */ #define vmprim_log_write(moo,mask,ptr,len) do { \ @@ -1216,13 +1233,6 @@ int moo_regfinalizable (moo_t* moo, moo_oop_t oop); int moo_deregfinalizable (moo_t* moo, moo_oop_t oop); void moo_deregallfinalizables (moo_t* moo); -/* ========================================================================= */ -/* proc.c */ -/* ========================================================================= */ -moo_oop_process_t moo_makeproc ( - moo_t* moo -); - /* ========================================================================= */ /* bigint.c */ /* ========================================================================= */ @@ -1350,10 +1360,29 @@ moo_oop_t moo_strtoint ( int radix ); +#define MOO_INTTOSTR_LOWERCASE (1 << 14) +#define MOO_INTTOSTR_NONEWOBJ (1 << 15) + moo_oop_t moo_inttostr ( moo_t* moo, moo_oop_t num, - int radix + int flagged_radix /* radix between 2 and 36 inclusive, optionally bitwise ORed of MOO_INTTOSTR_XXX bits */ +); + +/* ========================================================================= */ +/* number.c */ +/* ========================================================================= */ +moo_oop_t moo_makefpdec ( + moo_t* moo, + moo_oop_t value, + moo_ooi_t scale +); + +moo_oop_t moo_truncfpdecval ( + moo_t* moo, + moo_oop_t iv, + moo_ooi_t cs, + moo_ooi_t ns ); /* ========================================================================= */ diff --git a/moo/lib/moo.c b/moo/lib/moo.c index 427e4d7..d8d3600 100644 --- a/moo/lib/moo.c +++ b/moo/lib/moo.c @@ -282,6 +282,14 @@ void moo_fini (moo_t* moo) moo->inttostr.t.capa = 0; } + if (moo->sprintf.xbuf.ptr) + { + moo_freemem (moo, moo->sprintf.xbuf.ptr); + moo->sprintf.xbuf.ptr = MOO_NULL; + moo->sprintf.xbuf.capa = 0; + moo->sprintf.xbuf.len = 0; + } + if (moo->vmprim.dl_cleanup) moo->vmprim.dl_cleanup (moo); } diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 4fe2c52..c98e4b6 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -435,6 +435,7 @@ typedef enum moo_gcfin_t moo_gcfin_t; #define MOO_OBJ_IS_HALFWORD_POINTER(oop) (MOO_OOP_IS_POINTER(oop) && (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_HALFWORD)) #define MOO_OBJ_IS_WORD_POINTER(oop) (MOO_OOP_IS_POINTER(oop) && (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_WORD)) + /* [NOTE] this macro doesn't check the range of the actual value. * make sure that the value of each bit fields given falls within the * possible range of the defined bits */ @@ -1632,6 +1633,16 @@ struct moo_t } inttostr; /* == END BIGINT CONVERSION == */ + struct + { + struct + { + moo_ooch_t* ptr; + moo_oow_t capa; + moo_oow_t len; + } xbuf; /* buffer to support sprintf */ + } sprintf; + moo_sbuf_t sbuf[64]; struct diff --git a/moo/lib/number.c b/moo/lib/number.c index c40ef90..ec61cb8 100644 --- a/moo/lib/number.c +++ b/moo/lib/number.c @@ -32,6 +32,15 @@ moo_oop_t moo_makefpdec (moo_t* moo, moo_oop_t value, moo_ooi_t scale) { moo_oop_fpdec_t fpdec; + MOO_ASSERT (moo, moo_isint(moo, value)); + if (scale <= 0) return value; /* if scale is 0 or less, return the value as it it */ + + if (scale > MOO_SMOOI_MAX) + { + moo_seterrbfmt (moo, MOO_EINVAL, "fpdec scale too large - %zd", scale); + return MOO_NULL; + } + moo_pushtmp (moo, &value); fpdec = (moo_oop_fpdec_t)moo_instantiate(moo, moo->_fixed_point_decimal, MOO_NULL, 0); moo_poptmp (moo); diff --git a/moo/lib/sym.c b/moo/lib/sym.c index f8fca68..5aeac61 100644 --- a/moo/lib/sym.c +++ b/moo/lib/sym.c @@ -94,7 +94,7 @@ static moo_oop_t find_or_make_symbol (moo_t* moo, const moo_ooch_t* ptr, moo_oow index = moo_hashoochars(ptr, len) % MOO_OBJ_GET_SIZE(moo->symtab->bucket); /* find a matching symbol in the open-addressed symbol table */ - while ((moo_oop_t)(symbol = MOO_OBJ_GET_OOP_VAL(moo->symtab->bucket, index)) != moo->_nil) + while ((moo_oop_t)(symbol = (moo_oop_char_t)MOO_OBJ_GET_OOP_VAL(moo->symtab->bucket, index)) != moo->_nil) { MOO_ASSERT (moo, MOO_CLASSOF(moo,symbol) == moo->_symbol);