1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is Mozilla Communicator client code, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 * JS number type and wrapper class.
45 #if defined(XP_WIN) || defined(XP_OS2)
54 #include "jsutil.h" /* Added by JSIFY */
57 #include "jsbuiltins.h"
59 #include "jsversion.h"
71 num_isNaN(JSContext
*cx
, uintN argc
, jsval
*vp
)
79 x
= js_ValueToNumber(cx
, &vp
[2]);
80 if (JSVAL_IS_NULL(vp
[2]))
82 *vp
= BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x
));
87 num_isFinite(JSContext
*cx
, uintN argc
, jsval
*vp
)
95 x
= js_ValueToNumber(cx
, &vp
[2]);
96 if (JSVAL_IS_NULL(vp
[2]))
98 *vp
= BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x
));
103 num_parseFloat(JSContext
*cx
, uintN argc
, jsval
*vp
)
107 const jschar
*bp
, *end
, *ep
;
110 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
113 str
= js_ValueToString(cx
, vp
[2]);
116 JSSTRING_CHARS_AND_END(str
, bp
, end
);
117 if (!js_strtod(cx
, bp
, end
, &ep
, &d
))
120 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
123 return js_NewNumberInRootedValue(cx
, d
, vp
);
128 js_ParseFloat(JSContext
* cx
, JSString
* str
)
135 JSSTRING_CHARS_AND_END(str
, bp
, end
);
136 if (!js_strtod(cx
, bp
, end
, &ep
, &d
) || ep
== bp
)
142 /* See ECMA 15.1.2.2. */
144 num_parseInt(JSContext
*cx
, uintN argc
, jsval
*vp
)
149 const jschar
*bp
, *end
, *ep
;
152 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
156 radix
= js_ValueToECMAInt32(cx
, &vp
[3]);
157 if (JSVAL_IS_NULL(vp
[3]))
162 if (radix
!= 0 && (radix
< 2 || radix
> 36)) {
163 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
167 if (JSVAL_IS_INT(vp
[2]) && (radix
== 0 || radix
== 10)) {
172 str
= js_ValueToString(cx
, vp
[2]);
175 JSSTRING_CHARS_AND_END(str
, bp
, end
);
176 if (!js_strtointeger(cx
, bp
, end
, &ep
, radix
, &d
))
179 *vp
= DOUBLE_TO_JSVAL(cx
->runtime
->jsNaN
);
182 return js_NewNumberInRootedValue(cx
, d
, vp
);
187 js_ParseInt(JSContext
* cx
, JSString
* str
)
194 JSSTRING_CHARS_AND_END(str
, bp
, end
);
195 if (!js_strtointeger(cx
, bp
, end
, &ep
, 0, &d
) || ep
== bp
)
201 js_ParseIntDouble(jsdouble d
)
203 if (!JSDOUBLE_IS_FINITE(d
))
209 const char js_Infinity_str
[] = "Infinity";
210 const char js_NaN_str
[] = "NaN";
211 const char js_isNaN_str
[] = "isNaN";
212 const char js_isFinite_str
[] = "isFinite";
213 const char js_parseFloat_str
[] = "parseFloat";
214 const char js_parseInt_str
[] = "parseInt";
218 JS_DEFINE_CALLINFO_2(DOUBLE
, ParseInt
, CONTEXT
, STRING
, 1, 1)
219 JS_DEFINE_CALLINFO_1(DOUBLE
, ParseIntDouble
, DOUBLE
, 1, 1)
220 JS_DEFINE_CALLINFO_2(DOUBLE
, ParseFloat
, CONTEXT
, STRING
, 1, 1)
222 static const JSTraceableNative num_parseInt_trcinfo
[] = {
223 { num_parseInt
, &ci_ParseInt
, "C", "s", INFALLIBLE
| JSTN_MORE
},
224 { num_parseInt
, &ci_ParseIntDouble
, "", "d", INFALLIBLE
}
226 static const JSTraceableNative num_parseFloat_trcinfo
[] = {
227 { num_parseFloat
, &ci_ParseFloat
, "C", "s", INFALLIBLE
}
230 #endif /* JS_TRACER */
232 static JSFunctionSpec number_functions
[] = {
233 JS_FN(js_isNaN_str
, num_isNaN
, 1,0),
234 JS_FN(js_isFinite_str
, num_isFinite
, 1,0),
235 JS_TN(js_parseFloat_str
, num_parseFloat
, 1,0, num_parseFloat_trcinfo
),
236 JS_TN(js_parseInt_str
, num_parseInt
, 2,0, num_parseInt_trcinfo
),
240 JSClass js_NumberClass
= {
242 JSCLASS_HAS_PRIVATE
| JSCLASS_HAS_CACHED_PROTO(JSProto_Number
),
243 JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
, JS_PropertyStub
,
244 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
, JS_FinalizeStub
,
245 JSCLASS_NO_OPTIONAL_MEMBERS
249 Number(JSContext
*cx
, JSObject
*obj
, uintN argc
, jsval
*argv
, jsval
*rval
)
255 d
= js_ValueToNumber(cx
, &argv
[0]);
257 if (JSVAL_IS_NULL(v
))
259 if (v
!= JSVAL_TRUE
) {
260 JS_ASSERT(JSVAL_IS_INT(v
) || JSVAL_IS_DOUBLE(v
));
262 if (!js_NewNumberInRootedValue(cx
, d
, &argv
[0]))
269 if (!(cx
->fp
->flags
& JSFRAME_CONSTRUCTING
)) {
273 STOBJ_SET_SLOT(obj
, JSSLOT_PRIVATE
, v
);
279 num_toSource(JSContext
*cx
, uintN argc
, jsval
*vp
)
283 char numBuf
[DTOSTR_STANDARD_BUFFER_SIZE
], *numStr
;
287 if (!js_GetPrimitiveThis(cx
, vp
, &js_NumberClass
, &v
))
289 JS_ASSERT(JSVAL_IS_NUMBER(v
));
290 d
= JSVAL_IS_INT(v
) ? (jsdouble
)JSVAL_TO_INT(v
) : *JSVAL_TO_DOUBLE(v
);
291 numStr
= JS_dtostr(numBuf
, sizeof numBuf
, DTOSTR_STANDARD
, 0, d
);
293 JS_ReportOutOfMemory(cx
);
296 JS_snprintf(buf
, sizeof buf
, "(new %s(%s))", js_NumberClass
.name
, numStr
);
297 str
= JS_NewStringCopyZ(cx
, buf
);
300 *vp
= STRING_TO_JSVAL(str
);
305 /* The buf must be big enough for MIN_INT to fit including '-' and '\0'. */
307 js_IntToCString(jsint i
, char *buf
, size_t bufSize
)
312 u
= (i
< 0) ? -i
: i
;
314 cp
= buf
+ bufSize
; /* one past last buffer cell */
315 *--cp
= '\0'; /* null terminate the string to be */
318 * Build the string from behind. We use multiply and subtraction
319 * instead of modulus because that's much faster.
322 jsuint newu
= u
/ 10;
323 *--cp
= (char)(u
- newu
* 10) + '0';
330 JS_ASSERT(cp
>= buf
);
335 num_toString(JSContext
*cx
, uintN argc
, jsval
*vp
)
342 if (!js_GetPrimitiveThis(cx
, vp
, &js_NumberClass
, &v
))
344 JS_ASSERT(JSVAL_IS_NUMBER(v
));
345 d
= JSVAL_IS_INT(v
) ? (jsdouble
)JSVAL_TO_INT(v
) : *JSVAL_TO_DOUBLE(v
);
347 if (argc
!= 0 && !JSVAL_IS_VOID(vp
[2])) {
348 base
= js_ValueToECMAInt32(cx
, &vp
[2]);
349 if (JSVAL_IS_NULL(vp
[2]))
351 if (base
< 2 || base
> 36) {
353 char *numStr
= js_IntToCString(base
, numBuf
, sizeof numBuf
);
354 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_BAD_RADIX
,
360 str
= js_NumberToString(cx
, d
);
362 char *dStr
= JS_dtobasestr(base
, d
);
364 JS_ReportOutOfMemory(cx
);
367 str
= JS_NewStringCopyZ(cx
, dStr
);
372 *vp
= STRING_TO_JSVAL(str
);
377 num_toLocaleString(JSContext
*cx
, uintN argc
, jsval
*vp
)
379 char thousandsLength
, decimalLength
;
380 const char *numGrouping
, *tmpGroup
;
382 JSString
*numStr
, *str
;
383 const char *num
, *end
, *tmpSrc
;
386 int digits
, size
, remainder
, nrepeat
;
389 * Create the string, move back to bytes to make string twiddling
390 * a bit easier and so we can insert platform charset seperators.
392 if (!num_toString(cx
, 0, vp
))
394 JS_ASSERT(JSVAL_IS_STRING(*vp
));
395 numStr
= JSVAL_TO_STRING(*vp
);
396 num
= js_GetStringBytes(cx
, numStr
);
401 * Find the first non-integer value, whether it be a letter as in
402 * 'Infinity', a decimal point, or an 'e' from exponential notation.
407 while (*nint
>= '0' && *nint
<= '9')
415 thousandsLength
= strlen(rt
->thousandsSeparator
);
416 decimalLength
= strlen(rt
->decimalSeparator
);
418 /* Figure out how long resulting string will be. */
419 size
= digits
+ (*nint
? strlen(nint
+ 1) + 1 : 0);
421 size
+= decimalLength
;
423 numGrouping
= tmpGroup
= rt
->numGrouping
;
428 while (*tmpGroup
!= CHAR_MAX
&& *tmpGroup
!= '\0') {
429 if (*tmpGroup
>= remainder
)
431 size
+= thousandsLength
;
432 remainder
-= *tmpGroup
;
435 if (*tmpGroup
== '\0' && *numGrouping
!= '\0') {
436 nrepeat
= (remainder
- 1) / tmpGroup
[-1];
437 size
+= thousandsLength
* nrepeat
;
438 remainder
-= nrepeat
* tmpGroup
[-1];
444 buf
= (char *)JS_malloc(cx
, size
+ 1);
451 while (*tmpSrc
== '-' || remainder
--)
452 *tmpDest
++ = *tmpSrc
++;
453 while (tmpSrc
< end
) {
454 strcpy(tmpDest
, rt
->thousandsSeparator
);
455 tmpDest
+= thousandsLength
;
456 memcpy(tmpDest
, tmpSrc
, *tmpGroup
);
457 tmpDest
+= *tmpGroup
;
464 strcpy(tmpDest
, rt
->decimalSeparator
);
465 tmpDest
+= decimalLength
;
466 strcpy(tmpDest
, nint
+ 1);
468 strcpy(tmpDest
, nint
);
471 if (cx
->localeCallbacks
&& cx
->localeCallbacks
->localeToUnicode
)
472 return cx
->localeCallbacks
->localeToUnicode(cx
, buf
, vp
);
474 str
= JS_NewString(cx
, buf
, size
);
480 *vp
= STRING_TO_JSVAL(str
);
485 num_valueOf(JSContext
*cx
, uintN argc
, jsval
*vp
)
491 if (JSVAL_IS_NUMBER(v
)) {
495 obj
= JS_THIS_OBJECT(cx
, vp
);
496 if (!JS_InstanceOf(cx
, obj
, &js_NumberClass
, vp
+ 2))
498 *vp
= OBJ_GET_SLOT(cx
, obj
, JSSLOT_PRIVATE
);
503 #define MAX_PRECISION 100
506 num_to(JSContext
*cx
, JSDToStrMode zeroArgMode
, JSDToStrMode oneArgMode
,
507 jsint precisionMin
, jsint precisionMax
, jsint precisionOffset
,
508 uintN argc
, jsval
*vp
)
511 jsdouble d
, precision
;
514 /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
515 char buf
[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION
+1)];
518 if (!js_GetPrimitiveThis(cx
, vp
, &js_NumberClass
, &v
))
520 JS_ASSERT(JSVAL_IS_NUMBER(v
));
521 d
= JSVAL_IS_INT(v
) ? (jsdouble
)JSVAL_TO_INT(v
) : *JSVAL_TO_DOUBLE(v
);
525 oneArgMode
= zeroArgMode
;
527 precision
= js_ValueToNumber(cx
, &vp
[2]);
528 if (JSVAL_IS_NULL(vp
[2]))
530 precision
= js_DoubleToInteger(precision
);
531 if (precision
< precisionMin
|| precision
> precisionMax
) {
532 numStr
= JS_dtostr(buf
, sizeof buf
, DTOSTR_STANDARD
, 0, precision
);
534 JS_ReportOutOfMemory(cx
);
536 JS_ReportErrorNumber(cx
, js_GetErrorMessage
, NULL
, JSMSG_PRECISION_RANGE
, numStr
);
541 numStr
= JS_dtostr(buf
, sizeof buf
, oneArgMode
, (jsint
)precision
+ precisionOffset
, d
);
543 JS_ReportOutOfMemory(cx
);
546 str
= JS_NewStringCopyZ(cx
, numStr
);
549 *vp
= STRING_TO_JSVAL(str
);
554 * In the following three implementations, we allow a larger range of precision
555 * than ECMA requires; this is permitted by ECMA-262.
558 num_toFixed(JSContext
*cx
, uintN argc
, jsval
*vp
)
560 return num_to(cx
, DTOSTR_FIXED
, DTOSTR_FIXED
, -20, MAX_PRECISION
, 0,
565 num_toExponential(JSContext
*cx
, uintN argc
, jsval
*vp
)
567 return num_to(cx
, DTOSTR_STANDARD_EXPONENTIAL
, DTOSTR_EXPONENTIAL
, 0,
568 MAX_PRECISION
, 1, argc
, vp
);
572 num_toPrecision(JSContext
*cx
, uintN argc
, jsval
*vp
)
574 if (argc
== 0 || JSVAL_IS_VOID(vp
[2]))
575 return num_toString(cx
, 0, vp
);
576 return num_to(cx
, DTOSTR_STANDARD
, DTOSTR_PRECISION
, 1, MAX_PRECISION
, 0,
582 JS_DEFINE_CALLINFO_2(STRING
, NumberToString
, CONTEXT
, DOUBLE
, 1, 1)
584 static const JSTraceableNative num_toString_trcinfo
[] = {
585 { num_toString
, &ci_NumberToString
, "DC", "", FAIL_NULL
}
588 #endif /* JS_TRACER */
590 static JSFunctionSpec number_methods
[] = {
592 JS_FN(js_toSource_str
, num_toSource
, 0,JSFUN_THISP_NUMBER
),
594 JS_TN(js_toString_str
, num_toString
, 1,JSFUN_THISP_NUMBER
,
595 num_toString_trcinfo
),
596 JS_FN(js_toLocaleString_str
, num_toLocaleString
, 0,JSFUN_THISP_NUMBER
),
597 JS_FN(js_valueOf_str
, num_valueOf
, 0,JSFUN_THISP_NUMBER
),
598 JS_FN(js_toJSON_str
, num_valueOf
, 0,JSFUN_THISP_NUMBER
),
599 JS_FN("toFixed", num_toFixed
, 1,JSFUN_THISP_NUMBER
),
600 JS_FN("toExponential", num_toExponential
, 1,JSFUN_THISP_NUMBER
),
601 JS_FN("toPrecision", num_toPrecision
, 1,JSFUN_THISP_NUMBER
),
605 /* NB: Keep this in synch with number_constants[]. */
608 NC_POSITIVE_INFINITY
,
609 NC_NEGATIVE_INFINITY
,
616 * Some to most C compilers forbid spelling these at compile time, or barf
617 * if you try, so all but MAX_VALUE are set up by js_InitRuntimeNumberState
618 * using union jsdpun.
620 static JSConstDoubleSpec number_constants
[] = {
621 {0, js_NaN_str
, 0,{0,0,0}},
622 {0, "POSITIVE_INFINITY", 0,{0,0,0}},
623 {0, "NEGATIVE_INFINITY", 0,{0,0,0}},
624 {1.7976931348623157E+308, "MAX_VALUE", 0,{0,0,0}},
625 {0, "MIN_VALUE", 0,{0,0,0}},
631 #if (defined XP_WIN || defined XP_OS2) && \
633 !defined __MWERKS__ && \
634 (defined _M_IX86 || \
635 (defined __GNUC__ && !defined __MINGW32__))
638 * Set the exception mask to mask all exceptions and set the FPU precision
639 * to 53 bit mantissa.
640 * On Alpha platform this is handled via Compiler option.
642 #define FIX_FPU() _control87(MCW_EM | PC_53, MCW_EM | MCW_PC)
646 #define FIX_FPU() ((void)0)
651 js_InitRuntimeNumberState(JSContext
*cx
)
655 struct lconv
*locale
;
658 JS_ASSERT(!rt
->jsNaN
);
662 u
.s
.hi
= JSDOUBLE_HI32_EXPMASK
| JSDOUBLE_HI32_MANTMASK
;
664 number_constants
[NC_NaN
].dval
= js_NaN
= u
.d
;
665 rt
->jsNaN
= js_NewWeaklyRootedDouble(cx
, js_NaN
);
669 u
.s
.hi
= JSDOUBLE_HI32_EXPMASK
;
671 number_constants
[NC_POSITIVE_INFINITY
].dval
= u
.d
;
672 rt
->jsPositiveInfinity
= js_NewWeaklyRootedDouble(cx
, u
.d
);
673 if (!rt
->jsPositiveInfinity
)
676 u
.s
.hi
= JSDOUBLE_HI32_SIGNBIT
| JSDOUBLE_HI32_EXPMASK
;
678 number_constants
[NC_NEGATIVE_INFINITY
].dval
= u
.d
;
679 rt
->jsNegativeInfinity
= js_NewWeaklyRootedDouble(cx
, u
.d
);
680 if (!rt
->jsNegativeInfinity
)
685 number_constants
[NC_MIN_VALUE
].dval
= u
.d
;
687 locale
= localeconv();
688 rt
->thousandsSeparator
=
689 JS_strdup(cx
, locale
->thousands_sep
? locale
->thousands_sep
: "'");
690 rt
->decimalSeparator
=
691 JS_strdup(cx
, locale
->decimal_point
? locale
->decimal_point
: ".");
693 JS_strdup(cx
, locale
->grouping
? locale
->grouping
: "\3\0");
695 return rt
->thousandsSeparator
&& rt
->decimalSeparator
&& rt
->numGrouping
;
699 js_TraceRuntimeNumberState(JSTracer
*trc
)
703 rt
= trc
->context
->runtime
;
705 JS_CALL_DOUBLE_TRACER(trc
, rt
->jsNaN
, "NaN");
706 if (rt
->jsPositiveInfinity
)
707 JS_CALL_DOUBLE_TRACER(trc
, rt
->jsPositiveInfinity
, "+Infinity");
708 if (rt
->jsNegativeInfinity
)
709 JS_CALL_DOUBLE_TRACER(trc
, rt
->jsNegativeInfinity
, "-Infinity");
713 js_FinishRuntimeNumberState(JSContext
*cx
)
715 JSRuntime
*rt
= cx
->runtime
;
717 js_UnlockGCThingRT(rt
, rt
->jsNaN
);
718 js_UnlockGCThingRT(rt
, rt
->jsNegativeInfinity
);
719 js_UnlockGCThingRT(rt
, rt
->jsPositiveInfinity
);
722 rt
->jsNegativeInfinity
= NULL
;
723 rt
->jsPositiveInfinity
= NULL
;
725 JS_free(cx
, (void *)rt
->thousandsSeparator
);
726 JS_free(cx
, (void *)rt
->decimalSeparator
);
727 JS_free(cx
, (void *)rt
->numGrouping
);
728 rt
->thousandsSeparator
= rt
->decimalSeparator
= rt
->numGrouping
= NULL
;
732 js_InitNumberClass(JSContext
*cx
, JSObject
*obj
)
734 JSObject
*proto
, *ctor
;
737 /* XXX must do at least once per new thread, so do it per JSContext... */
740 if (!JS_DefineFunctions(cx
, obj
, number_functions
))
743 proto
= JS_InitClass(cx
, obj
, NULL
, &js_NumberClass
, Number
, 1,
744 NULL
, number_methods
, NULL
, NULL
);
745 if (!proto
|| !(ctor
= JS_GetConstructor(cx
, proto
)))
747 STOBJ_SET_SLOT(proto
, JSSLOT_PRIVATE
, JSVAL_ZERO
);
748 if (!JS_DefineConstDoubles(cx
, ctor
, number_constants
))
753 if (!JS_DefineProperty(cx
, obj
, js_NaN_str
, DOUBLE_TO_JSVAL(rt
->jsNaN
),
754 NULL
, NULL
, JSPROP_PERMANENT
)) {
759 if (!JS_DefineProperty(cx
, obj
, js_Infinity_str
,
760 DOUBLE_TO_JSVAL(rt
->jsPositiveInfinity
),
761 NULL
, NULL
, JSPROP_PERMANENT
)) {
768 js_NewNumberInRootedValue(JSContext
*cx
, jsdouble d
, jsval
*vp
)
772 if (JSDOUBLE_IS_INT(d
, i
) && INT_FITS_IN_JSVAL(i
)) {
773 *vp
= INT_TO_JSVAL(i
);
776 return js_NewDoubleInRootedValue(cx
, d
, vp
);
780 js_NumberToCString(JSContext
*cx
, jsdouble d
, char *buf
, size_t bufSize
)
785 JS_ASSERT(bufSize
>= DTOSTR_STANDARD_BUFFER_SIZE
);
786 if (JSDOUBLE_IS_INT(d
, i
)) {
787 numStr
= js_IntToCString(i
, buf
, bufSize
);
789 numStr
= JS_dtostr(buf
, bufSize
, DTOSTR_STANDARD
, 0, d
);
791 JS_ReportOutOfMemory(cx
);
798 JSString
* JS_FASTCALL
799 js_NumberToString(JSContext
*cx
, jsdouble d
)
801 char buf
[DTOSTR_STANDARD_BUFFER_SIZE
];
804 numStr
= js_NumberToCString(cx
, d
, buf
, sizeof buf
);
807 return JS_NewStringCopyZ(cx
, numStr
);
811 js_ValueToNumber(JSContext
*cx
, jsval
*vp
)
815 const jschar
*bp
, *end
, *ep
;
818 JSTempValueRooter tvr
;
823 return (jsdouble
) JSVAL_TO_INT(v
);
824 if (JSVAL_IS_DOUBLE(v
))
825 return *JSVAL_TO_DOUBLE(v
);
826 if (JSVAL_IS_STRING(v
)) {
827 str
= JSVAL_TO_STRING(v
);
830 * Note that ECMA doesn't treat a string beginning with a '0' as
831 * an octal number here. This works because all such numbers will
832 * be interpreted as decimal by js_strtod and will never get
833 * passed to js_strtointeger (which would interpret them as
836 JSSTRING_CHARS_AND_END(str
, bp
, end
);
837 if ((!js_strtod(cx
, bp
, end
, &ep
, &d
) ||
838 js_SkipWhiteSpace(ep
, end
) != end
) &&
839 (!js_strtointeger(cx
, bp
, end
, &ep
, 0, &d
) ||
840 js_SkipWhiteSpace(ep
, end
) != end
)) {
845 * JSVAL_TRUE indicates that double jsval was never constructed
851 if (JSVAL_IS_BOOLEAN(v
)) {
852 if (JSVAL_TO_BOOLEAN(v
)) {
860 if (JSVAL_IS_NULL(v
)) {
864 if (JSVAL_IS_VOID(v
))
867 JS_ASSERT(!JSVAL_IS_PRIMITIVE(v
));
868 obj
= JSVAL_TO_OBJECT(v
);
871 * vp roots obj so we cannot use it as an extra root for
872 * OBJ_DEFAULT_VALUE result when calling the hook.
874 JS_PUSH_SINGLE_TEMP_ROOT(cx
, v
, &tvr
);
875 if (!OBJ_DEFAULT_VALUE(cx
, obj
, JSTYPE_NUMBER
, &tvr
.u
.value
))
878 v
= *vp
= tvr
.u
.value
;
879 JS_POP_TEMP_ROOT(cx
, &tvr
);
884 if (!JSVAL_IS_PRIMITIVE(v
))
888 dp
= cx
->runtime
->jsNaN
;
889 *vp
= DOUBLE_TO_JSVAL(dp
);
894 js_ValueToECMAInt32(JSContext
*cx
, jsval
*vp
)
901 return JSVAL_TO_INT(v
);
902 if (JSVAL_IS_DOUBLE(v
)) {
903 d
= *JSVAL_TO_DOUBLE(v
);
906 d
= js_ValueToNumber(cx
, vp
);
907 if (JSVAL_IS_NULL(*vp
))
911 return js_DoubleToECMAInt32(d
);
915 js_DoubleToECMAInt32(jsdouble d
)
918 jsdouble two32
, two31
;
920 if (!JSDOUBLE_IS_FINITE(d
))
924 if ((jsdouble
) i
== d
)
927 two32
= 4294967296.0;
928 two31
= 2147483648.0;
930 d
= (d
>= 0) ? floor(d
) : ceil(d
) + two32
;
931 return (int32
) (d
>= two31
? d
- two32
: d
);
935 js_ValueToECMAUint32(JSContext
*cx
, jsval
*vp
)
942 if (JSVAL_IS_INT(v
)) {
948 if (JSVAL_IS_DOUBLE(v
)) {
949 d
= *JSVAL_TO_DOUBLE(v
);
952 d
= js_ValueToNumber(cx
, vp
);
953 if (JSVAL_IS_NULL(*vp
))
957 return js_DoubleToECMAUint32(d
);
961 js_DoubleToECMAUint32(jsdouble d
)
967 if (!JSDOUBLE_IS_FINITE(d
))
971 * We check whether d fits int32, not uint32, as all but the ">>>" bit
972 * manipulation bytecode stores the result as int, not uint. When the
973 * result does not fit int jsval, it will be stored as a negative double.
976 if ((jsdouble
) i
== d
)
980 d
= floor(neg
? -d
: d
);
983 two32
= 4294967296.0;
986 return (uint32
) (d
>= 0 ? d
: d
+ two32
);
990 js_ValueToInt32(JSContext
*cx
, jsval
*vp
)
997 return JSVAL_TO_INT(v
);
998 d
= js_ValueToNumber(cx
, vp
);
999 if (JSVAL_IS_NULL(*vp
))
1001 if (JSVAL_IS_INT(*vp
))
1002 return JSVAL_TO_INT(*vp
);
1005 if (JSDOUBLE_IS_NaN(d
) || d
<= -2147483649.0 || 2147483648.0 <= d
) {
1006 js_ReportValueError(cx
, JSMSG_CANT_CONVERT
,
1007 JSDVG_SEARCH_STACK
, v
, NULL
);
1011 return (int32
) floor(d
+ 0.5); /* Round to nearest */
1015 js_ValueToUint16(JSContext
*cx
, jsval
*vp
)
1022 d
= js_ValueToNumber(cx
, vp
);
1023 if (JSVAL_IS_NULL(*vp
))
1026 if (JSVAL_IS_INT(*vp
)) {
1027 u
= (uint16
) JSVAL_TO_INT(*vp
);
1028 } else if (d
== 0 || !JSDOUBLE_IS_FINITE(d
)) {
1032 if ((jsdouble
) u
!= d
) {
1034 d
= floor(neg
? -d
: d
);
1037 d
= fmod(d
, (double) m
);
1043 *vp
= INT_TO_JSVAL(u
);
1048 js_DoubleToInteger(jsdouble d
)
1054 if (!JSDOUBLE_IS_FINITE(d
)) {
1055 if (JSDOUBLE_IS_NaN(d
))
1060 d
= floor(neg
? -d
: d
);
1061 return neg
? -d
: d
;
1065 js_strtod(JSContext
*cx
, const jschar
*s
, const jschar
*send
,
1066 const jschar
**ep
, jsdouble
*dp
)
1071 char *cstr
, *istr
, *estr
;
1075 s1
= js_SkipWhiteSpace(s
, send
);
1078 /* Use cbuf to avoid malloc */
1079 if (length
>= sizeof cbuf
) {
1080 cstr
= (char *) JS_malloc(cx
, length
+ 1);
1087 for (i
= 0; i
!= length
; i
++) {
1090 cstr
[i
] = (char)s1
[i
];
1095 if ((negative
= (*istr
== '-')) != 0 || *istr
== '+')
1097 if (!strncmp(istr
, js_Infinity_str
, sizeof js_Infinity_str
- 1)) {
1098 d
= *(negative
? cx
->runtime
->jsNegativeInfinity
: cx
->runtime
->jsPositiveInfinity
);
1102 d
= JS_strtod(cstr
, &estr
, &err
);
1104 d
= *cx
->runtime
->jsPositiveInfinity
;
1105 else if (d
== -HUGE_VAL
)
1106 d
= *cx
->runtime
->jsNegativeInfinity
;
1108 if (d
== 0.0 && negative
) {
1110 * "-0", "-1e-2000" come out as positive zero
1111 * here on HPUX. Force a negative zero instead.
1113 JSDOUBLE_HI32(d
) = JSDOUBLE_HI32_SIGNBIT
;
1114 JSDOUBLE_LO32(d
) = 0;
1122 *ep
= i
? s1
+ i
: s
;
1127 struct BinaryDigitReader
1129 uintN base
; /* Base of number; must be a power of 2 */
1130 uintN digit
; /* Current digit value in radix given by base */
1131 uintN digitMask
; /* Mask to extract the next bit from digit */
1132 const jschar
*digits
; /* Pointer to the remaining digits */
1133 const jschar
*end
; /* Pointer to first non-digit */
1136 /* Return the next binary digit from the number or -1 if done */
1137 static intN
GetNextBinaryDigit(struct BinaryDigitReader
*bdr
)
1141 if (bdr
->digitMask
== 0) {
1144 if (bdr
->digits
== bdr
->end
)
1148 if ('0' <= c
&& c
<= '9')
1149 bdr
->digit
= c
- '0';
1150 else if ('a' <= c
&& c
<= 'z')
1151 bdr
->digit
= c
- 'a' + 10;
1152 else bdr
->digit
= c
- 'A' + 10;
1153 bdr
->digitMask
= bdr
->base
>> 1;
1155 bit
= (bdr
->digit
& bdr
->digitMask
) != 0;
1156 bdr
->digitMask
>>= 1;
1161 js_strtointeger(JSContext
*cx
, const jschar
*s
, const jschar
*send
,
1162 const jschar
**ep
, jsint base
, jsdouble
*dp
)
1164 const jschar
*s1
, *start
;
1168 s1
= js_SkipWhiteSpace(s
, send
);
1171 if ((negative
= (*s1
== '-')) != 0 || *s1
== '+') {
1178 /* No base supplied, or some base that evaluated to 0. */
1180 /* It's either hex or octal; only increment char if str isn't '0' */
1181 if (s1
+ 1 != send
&& (s1
[1] == 'X' || s1
[1] == 'x')) {
1190 base
= 10; /* Default to decimal. */
1192 } else if (base
== 16) {
1193 /* If base is 16, ignore hex prefix. */
1194 if (*s1
== '0' && s1
+ 1 != send
&& (s1
[1] == 'X' || s1
[1] == 'x')) {
1202 * Done with the preliminaries; find some prefix of the string that's
1203 * a number in the given base.
1205 JS_ASSERT(s1
< send
);
1211 if ('0' <= c
&& c
<= '9')
1213 else if ('a' <= c
&& c
<= 'z')
1214 digit
= c
- 'a' + 10;
1215 else if ('A' <= c
&& c
<= 'Z')
1216 digit
= c
- 'A' + 10;
1219 if (digit
>= (uintN
)base
)
1221 value
= value
* base
+ digit
;
1222 } while (++s1
!= send
);
1224 if (value
>= 9007199254740992.0) {
1227 * If we're accumulating a decimal number and the number is >=
1228 * 2^53, then the result from the repeated multiply-add above may
1229 * be inaccurate. Call JS_strtod to get the correct answer.
1232 size_t length
= s1
- start
;
1233 char *cstr
= (char *) JS_malloc(cx
, length
+ 1);
1239 for (i
= 0; i
!= length
; i
++)
1240 cstr
[i
] = (char)start
[i
];
1243 value
= JS_strtod(cstr
, &estr
, &err
);
1244 if (err
== JS_DTOA_ENOMEM
) {
1245 JS_ReportOutOfMemory(cx
);
1249 if (err
== JS_DTOA_ERANGE
&& value
== HUGE_VAL
)
1250 value
= *cx
->runtime
->jsPositiveInfinity
;
1252 } else if ((base
& (base
- 1)) == 0) {
1254 * The number may also be inaccurate for power-of-two bases. This
1255 * happens if the addition in value * base + digit causes a round-
1256 * down to an even least significant mantissa bit when the first
1257 * dropped bit is a one. If any of the following digits in the
1258 * number (which haven't been added in yet) are nonzero, then the
1259 * correct action would have been to round up instead of down. An
1260 * example occurs when reading the number 0x1000000000000081, which
1261 * rounds to 0x1000000000000000 instead of 0x1000000000000100.
1263 struct BinaryDigitReader bdr
;
1273 /* Skip leading zeros. */
1275 bit
= GetNextBinaryDigit(&bdr
);
1279 /* Gather the 53 significant bits (including the leading 1) */
1281 for (j
= 52; j
; j
--) {
1282 bit
= GetNextBinaryDigit(&bdr
);
1285 value
= value
*2 + bit
;
1287 /* bit2 is the 54th bit (the first dropped from the mantissa) */
1288 bit2
= GetNextBinaryDigit(&bdr
);
1290 jsdouble factor
= 2.0;
1291 intN sticky
= 0; /* sticky is 1 if any bit beyond the 54th is 1 */
1294 while ((bit3
= GetNextBinaryDigit(&bdr
)) >= 0) {
1298 value
+= bit2
& (bit
| sticky
);
1305 /* We don't worry about inaccurate numbers for any other base. */
1312 *dp
= negative
? -value
: value
;