5 #include "duk_internal.h"
7 DUK_LOCAL duk_double_t
duk__push_this_number_plain(duk_context
*ctx
) {
10 /* Number built-in accepts a plain number or a Number object (whose
11 * internal value is operated on). Other types cause TypeError.
15 if (duk_is_number(ctx
, -1)) {
16 DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval
*) duk_get_tval(ctx
, -1)));
19 h
= duk_get_hobject(ctx
, -1);
21 (DUK_HOBJECT_GET_CLASS_NUMBER(h
) != DUK_HOBJECT_CLASS_NUMBER
)) {
22 DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval
*) duk_get_tval(ctx
, -1)));
23 DUK_ERROR((duk_hthread
*) ctx
, DUK_ERR_TYPE_ERROR
, "expected a number");
25 duk_get_prop_stridx(ctx
, -1, DUK_STRIDX_INT_VALUE
);
26 DUK_ASSERT(duk_is_number(ctx
, -1));
27 DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
28 (duk_tval
*) duk_get_tval(ctx
, -2), (duk_tval
*) duk_get_tval(ctx
, -1)));
32 return duk_get_number(ctx
, -1);
35 DUK_INTERNAL duk_ret_t
duk_bi_number_constructor(duk_context
*ctx
) {
36 duk_hthread
*thr
= (duk_hthread
*) ctx
;
43 * The Number constructor uses ToNumber(arg) for number coercion
44 * (coercing an undefined argument to NaN). However, if the
45 * argument is not given at all, +0 must be used instead. To do
46 * this, a vararg function is used.
49 nargs
= duk_get_top(ctx
);
53 duk_to_number(ctx
, 0);
55 DUK_ASSERT_TOP(ctx
, 1);
57 if (!duk_is_constructor_call(ctx
)) {
62 * E5 Section 15.7.2.1 requires that the constructed object
63 * must have the original Number.prototype as its internal
64 * prototype. However, since Number.prototype is non-writable
65 * and non-configurable, this doesn't have to be enforced here:
66 * The default object (bound to 'this') is OK, though we have
67 * to change its class.
69 * Internal value set to ToNumber(arg) or +0; if no arg given,
70 * ToNumber(undefined) = NaN, so special treatment is needed
71 * (above). String internal value is immutable.
76 h_this
= duk_get_hobject(ctx
, -1);
77 DUK_ASSERT(h_this
!= NULL
);
78 DUK_HOBJECT_SET_CLASS_NUMBER(h_this
, DUK_HOBJECT_CLASS_NUMBER
);
80 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr
->heap
, h_this
) == thr
->builtins
[DUK_BIDX_NUMBER_PROTOTYPE
]);
81 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this
) == DUK_HOBJECT_CLASS_NUMBER
);
82 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this
));
84 duk_dup(ctx
, 0); /* -> [ val obj val ] */
85 duk_xdef_prop_stridx(ctx
, -2, DUK_STRIDX_INT_VALUE
, DUK_PROPDESC_FLAGS_NONE
);
86 return 0; /* no return value -> don't replace created value */
89 DUK_INTERNAL duk_ret_t
duk_bi_number_prototype_value_of(duk_context
*ctx
) {
90 (void) duk__push_this_number_plain(ctx
);
94 DUK_INTERNAL duk_ret_t
duk_bi_number_prototype_to_string(duk_context
*ctx
) {
95 duk_small_int_t radix
;
96 duk_small_uint_t n2s_flags
;
98 (void) duk__push_this_number_plain(ctx
);
99 if (duk_is_undefined(ctx
, 0)) {
102 radix
= (duk_small_int_t
) duk_to_int_check_range(ctx
, 0, 2, 36);
104 DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix
));
108 duk_numconv_stringify(ctx
,
111 n2s_flags
/*flags*/);
115 DUK_INTERNAL duk_ret_t
duk_bi_number_prototype_to_locale_string(duk_context
*ctx
) {
116 /* XXX: just use toString() for now; permitted although not recommended.
117 * nargs==1, so radix is passed to toString().
119 return duk_bi_number_prototype_to_string(ctx
);
123 * toFixed(), toExponential(), toPrecision()
126 /* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
128 DUK_INTERNAL duk_ret_t
duk_bi_number_prototype_to_fixed(duk_context
*ctx
) {
129 duk_small_int_t frac_digits
;
132 duk_small_uint_t n2s_flags
;
134 frac_digits
= (duk_small_int_t
) duk_to_int_check_range(ctx
, 0, 0, 20);
135 d
= duk__push_this_number_plain(ctx
);
137 c
= (duk_small_int_t
) DUK_FPCLASSIFY(d
);
138 if (c
== DUK_FP_NAN
|| c
== DUK_FP_INFINITE
) {
142 if (d
>= 1.0e21
|| d
<= -1.0e21
) {
146 n2s_flags
= DUK_N2S_FLAG_FIXED_FORMAT
|
147 DUK_N2S_FLAG_FRACTION_DIGITS
;
149 duk_numconv_stringify(ctx
,
151 frac_digits
/*digits*/,
152 n2s_flags
/*flags*/);
156 DUK_ASSERT_TOP(ctx
, 2);
157 duk_to_string(ctx
, -1);
161 DUK_INTERNAL duk_ret_t
duk_bi_number_prototype_to_exponential(duk_context
*ctx
) {
162 duk_bool_t frac_undefined
;
163 duk_small_int_t frac_digits
;
166 duk_small_uint_t n2s_flags
;
168 d
= duk__push_this_number_plain(ctx
);
170 frac_undefined
= duk_is_undefined(ctx
, 0);
171 duk_to_int(ctx
, 0); /* for side effects */
173 c
= (duk_small_int_t
) DUK_FPCLASSIFY(d
);
174 if (c
== DUK_FP_NAN
|| c
== DUK_FP_INFINITE
) {
178 frac_digits
= (duk_small_int_t
) duk_to_int_check_range(ctx
, 0, 0, 20);
180 n2s_flags
= DUK_N2S_FLAG_FORCE_EXP
|
181 (frac_undefined
? 0 : DUK_N2S_FLAG_FIXED_FORMAT
);
183 duk_numconv_stringify(ctx
,
185 frac_digits
+ 1 /*leading digit + fractions*/,
186 n2s_flags
/*flags*/);
190 DUK_ASSERT_TOP(ctx
, 2);
191 duk_to_string(ctx
, -1);
195 DUK_INTERNAL duk_ret_t
duk_bi_number_prototype_to_precision(duk_context
*ctx
) {
196 /* The specification has quite awkward order of coercion and
197 * checks for toPrecision(). The operations below are a bit
198 * reordered, within constraints of observable side effects.
202 duk_small_int_t prec
;
204 duk_small_uint_t n2s_flags
;
206 DUK_ASSERT_TOP(ctx
, 1);
208 d
= duk__push_this_number_plain(ctx
);
209 if (duk_is_undefined(ctx
, 0)) {
212 DUK_ASSERT_TOP(ctx
, 2);
214 duk_to_int(ctx
, 0); /* for side effects */
216 c
= (duk_small_int_t
) DUK_FPCLASSIFY(d
);
217 if (c
== DUK_FP_NAN
|| c
== DUK_FP_INFINITE
) {
221 prec
= (duk_small_int_t
) duk_to_int_check_range(ctx
, 0, 1, 21);
223 n2s_flags
= DUK_N2S_FLAG_FIXED_FORMAT
|
224 DUK_N2S_FLAG_NO_ZERO_PAD
;
226 duk_numconv_stringify(ctx
,
229 n2s_flags
/*flags*/);
233 /* Used when precision is undefined; also used for NaN (-> "NaN"),
234 * and +/- infinity (-> "Infinity", "-Infinity").
237 DUK_ASSERT_TOP(ctx
, 2);
238 duk_to_string(ctx
, -1);