+++ /dev/null
-/*
- * 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;
-}