diff options
Diffstat (limited to 'src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_number.c')
-rw-r--r-- | src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_number.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_number.c b/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_number.c new file mode 100644 index 000000000..4b7abf516 --- /dev/null +++ b/src/civetweb/src/third_party/duktape-1.5.2/src-separate/duk_bi_number.c @@ -0,0 +1,240 @@ +/* + * Number built-ins + */ + +#include "duk_internal.h" + +DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) { + duk_hobject *h; + + /* Number built-in accepts a plain number or a Number object (whose + * internal value is operated on). Other types cause TypeError. + */ + + duk_push_this(ctx); + if (duk_is_number(ctx, -1)) { + DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1))); + goto done; + } + h = duk_get_hobject(ctx, -1); + if (!h || + (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) { + DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1))); + DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected"); + } + duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_VALUE); + DUK_ASSERT(duk_is_number(ctx, -1)); + DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T", + (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1))); + duk_remove(ctx, -2); + + done: + return duk_get_number(ctx, -1); +} + +DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) { + duk_hthread *thr = (duk_hthread *) ctx; + duk_idx_t nargs; + duk_hobject *h_this; + + DUK_UNREF(thr); + + /* + * The Number constructor uses ToNumber(arg) for number coercion + * (coercing an undefined argument to NaN). However, if the + * argument is not given at all, +0 must be used instead. To do + * this, a vararg function is used. + */ + + nargs = duk_get_top(ctx); + if (nargs == 0) { + duk_push_int(ctx, 0); + } + duk_to_number(ctx, 0); + duk_set_top(ctx, 1); + DUK_ASSERT_TOP(ctx, 1); + + if (!duk_is_constructor_call(ctx)) { + return 1; + } + + /* + * E5 Section 15.7.2.1 requires that the constructed object + * must have the original Number.prototype as its internal + * prototype. However, since Number.prototype is non-writable + * and non-configurable, this doesn't have to be enforced here: + * The default object (bound to 'this') is OK, though we have + * to change its class. + * + * Internal value set to ToNumber(arg) or +0; if no arg given, + * ToNumber(undefined) = NaN, so special treatment is needed + * (above). String internal value is immutable. + */ + + /* XXX: helper */ + duk_push_this(ctx); + h_this = duk_get_hobject(ctx, -1); + DUK_ASSERT(h_this != NULL); + DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER); + + DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]); + DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER); + DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this)); + + duk_dup(ctx, 0); /* -> [ val obj val ] */ + duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); + return 0; /* no return value -> don't replace created value */ +} + +DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) { + (void) duk__push_this_number_plain(ctx); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) { + duk_small_int_t radix; + duk_small_uint_t n2s_flags; + + (void) duk__push_this_number_plain(ctx); + if (duk_is_undefined(ctx, 0)) { + radix = 10; + } else { + radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36); + } + DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix)); + + n2s_flags = 0; + + duk_numconv_stringify(ctx, + radix /*radix*/, + 0 /*digits*/, + n2s_flags /*flags*/); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) { + /* XXX: just use toString() for now; permitted although not recommended. + * nargs==1, so radix is passed to toString(). + */ + return duk_bi_number_prototype_to_string(ctx); +} + +/* + * toFixed(), toExponential(), toPrecision() + */ + +/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */ + +DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) { + duk_small_int_t frac_digits; + duk_double_t d; + duk_small_int_t c; + duk_small_uint_t n2s_flags; + + frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20); + d = duk__push_this_number_plain(ctx); + + c = (duk_small_int_t) DUK_FPCLASSIFY(d); + if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { + goto use_to_string; + } + + if (d >= 1.0e21 || d <= -1.0e21) { + goto use_to_string; + } + + n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | + DUK_N2S_FLAG_FRACTION_DIGITS; + + duk_numconv_stringify(ctx, + 10 /*radix*/, + frac_digits /*digits*/, + n2s_flags /*flags*/); + return 1; + + use_to_string: + DUK_ASSERT_TOP(ctx, 2); + duk_to_string(ctx, -1); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) { + duk_bool_t frac_undefined; + duk_small_int_t frac_digits; + duk_double_t d; + duk_small_int_t c; + duk_small_uint_t n2s_flags; + + d = duk__push_this_number_plain(ctx); + + frac_undefined = duk_is_undefined(ctx, 0); + duk_to_int(ctx, 0); /* for side effects */ + + c = (duk_small_int_t) DUK_FPCLASSIFY(d); + if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { + goto use_to_string; + } + + frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20); + + n2s_flags = DUK_N2S_FLAG_FORCE_EXP | + (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT); + + duk_numconv_stringify(ctx, + 10 /*radix*/, + frac_digits + 1 /*leading digit + fractions*/, + n2s_flags /*flags*/); + return 1; + + use_to_string: + DUK_ASSERT_TOP(ctx, 2); + duk_to_string(ctx, -1); + return 1; +} + +DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) { + /* The specification has quite awkward order of coercion and + * checks for toPrecision(). The operations below are a bit + * reordered, within constraints of observable side effects. + */ + + duk_double_t d; + duk_small_int_t prec; + duk_small_int_t c; + duk_small_uint_t n2s_flags; + + DUK_ASSERT_TOP(ctx, 1); + + d = duk__push_this_number_plain(ctx); + if (duk_is_undefined(ctx, 0)) { + goto use_to_string; + } + DUK_ASSERT_TOP(ctx, 2); + + duk_to_int(ctx, 0); /* for side effects */ + + c = (duk_small_int_t) DUK_FPCLASSIFY(d); + if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) { + goto use_to_string; + } + + prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21); + + n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT | + DUK_N2S_FLAG_NO_ZERO_PAD; + + duk_numconv_stringify(ctx, + 10 /*radix*/, + prec /*digits*/, + n2s_flags /*flags*/); + return 1; + + use_to_string: + /* Used when precision is undefined; also used for NaN (-> "NaN"), + * and +/- infinity (-> "Infinity", "-Infinity"). + */ + + DUK_ASSERT_TOP(ctx, 2); + duk_to_string(ctx, -1); + return 1; +} |