1 /*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package jdk.nashorn.internal.runtime;
27
28 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
29 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
30
31 import jdk.internal.dynalink.beans.StaticClass;
32 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
33 import jdk.nashorn.internal.parser.Lexer;
34
35 /**
36 * Representation for ECMAScript types - this maps directly to the ECMA script standard
37 */
38 public enum JSType {
39 /** The undefined type */
40 UNDEFINED,
41
42 /** The null type */
43 NULL,
44
45 /** The boolean type */
46 BOOLEAN,
47
48 /** The number type */
49 NUMBER,
50
51 /** The string type */
52 STRING,
53
54 /** The object type */
55 OBJECT,
56
57 /** The function type */
58 FUNCTION;
59
60 /** Max value for an uint32 in JavaScript */
61 public static final long MAX_UINT = 0xFFFF_FFFFL;
62
63 /** JavaScript compliant conversion function from Object to boolean */
64 public static final Call TO_BOOLEAN = staticCall(JSType.class, "toBoolean", boolean.class, Object.class);
65
66 /** JavaScript compliant conversion function from number to boolean */
67 public static final Call TO_BOOLEAN_D = staticCall(JSType.class, "toBoolean", boolean.class, double.class);
68
69 /** JavaScript compliant conversion function from Object to integer */
70 public static final Call TO_INTEGER = staticCall(JSType.class, "toInteger", int.class, Object.class);
71
72 /** JavaScript compliant conversion function from Object to long */
73 public static final Call TO_LONG = staticCall(JSType.class, "toLong", long.class, Object.class);
74
75 /** JavaScript compliant conversion function from Object to number */
76 public static final Call TO_NUMBER = staticCall(JSType.class, "toNumber", double.class, Object.class);
77
78 /** JavaScript compliant conversion function from Object to int32 */
79 public static final Call TO_INT32 = staticCall(JSType.class, "toInt32", int.class, Object.class);
80
81 /** JavaScript compliant conversion function from double to int32 */
82 public static final Call TO_INT32_D = staticCall(JSType.class, "toInt32", int.class, double.class);
83
84 /** JavaScript compliant conversion function from Object to uint32 */
85 public static final Call TO_UINT32 = staticCall(JSType.class, "toUint32", long.class, Object.class);
86
87 /** JavaScript compliant conversion function from number to uint32 */
88 public static final Call TO_UINT32_D = staticCall(JSType.class, "toUint32", long.class, double.class);
89
90 /** JavaScript compliant conversion function from Object to int64 */
91 public static final Call TO_INT64 = staticCall(JSType.class, "toInt64", long.class, Object.class);
92
93 /** JavaScript compliant conversion function from number to int64 */
94 public static final Call TO_INT64_D = staticCall(JSType.class, "toInt64", long.class, double.class);
95
96 /** JavaScript compliant conversion function from Object to String */
97 public static final Call TO_STRING = staticCall(JSType.class, "toString", String.class, Object.class);
98
99 /** JavaScript compliant conversion function from number to String */
100 public static final Call TO_STRING_D = staticCall(JSType.class, "toString", String.class, double.class);
101
102 /** JavaScript compliant conversion function from Object to primitive */
103 public static final Call TO_PRIMITIVE = staticCall(JSType.class, "toPrimitive", Object.class, Object.class);
104
105 private static final double INT32_LIMIT = 4294967296.0;
106
107 /**
108 * The external type name as returned by ECMAScript "typeof" operator
109 *
110 * @return type name for this type
111 */
112 public final String typeName() {
113 // For NULL, "object" has to be returned!
114 return ((this == NULL) ? OBJECT : this).name().toLowerCase();
115 }
116
117 /**
118 * Return the JSType for a given object
119 *
120 * @param obj an object
121 *
122 * @return the JSType for the object
123 */
124 public static JSType of(final Object obj) {
125 if (obj == ScriptRuntime.UNDEFINED) {
126 return JSType.UNDEFINED;
127 }
128
129 if (obj == null) {
130 return JSType.NULL;
131 }
132
133 if (obj instanceof Boolean) {
134 return JSType.BOOLEAN;
135 }
136
137 if (obj instanceof Number) {
138 return JSType.NUMBER;
139 }
140
141 if (obj instanceof String || obj instanceof ConsString) {
142 return JSType.STRING;
143 }
144
145 if (obj instanceof ScriptObject) {
146 return (obj instanceof ScriptFunction) ? JSType.FUNCTION : JSType.OBJECT;
147 }
148
149 if (obj instanceof StaticClass) {
150 return JSType.FUNCTION;
151 }
152
153 return JSType.OBJECT;
154 }
155
156 /**
157 * Returns true if double number can be represented as an int
158 *
159 * @param number a long to inspect
160 *
161 * @return true for int representable longs
162 */
163 public static boolean isRepresentableAsInt(final long number) {
164 return (int)number == number;
165 }
166
167 /**
168 * Returns true if double number can be represented as an int
169 *
170 * @param number a double to inspect
171 *
172 * @return true for int representable doubles
173 */
174 public static boolean isRepresentableAsInt(final double number) {
175 return (int)number == number;
176 }
177
178 /**
179 * Returns true if double number can be represented as a long
180 *
181 * @param number a double to inspect
182 * @return true for long representable doubles
183 */
184 public static boolean isRepresentableAsLong(final double number) {
185 return (long)number == number;
186 }
187
188 /**
189 * Get the smallest integer representation of a number. Returns an Integer
190 * for something that is int representable, and Long for something that
191 * is long representable. If the number needs to be a double, this is an
192 * identity function
193 *
194 * @param number number to check
195 *
196 * @return Number instanceof the narrowest possible integer representation for number
197 */
198 public static Number narrowestIntegerRepresentation(final double number) {
199 if (isRepresentableAsInt(number)) {
200 return (int)number;
201 } else if (isRepresentableAsLong(number)) {
202 return (long)number;
203 } else {
204 return number;
205 }
206 }
207
208 /**
209 * Check whether an object is primitive
210 *
211 * @param obj an object
212 *
213 * @return true if object is primitive (includes null and undefined)
214 */
215 public static boolean isPrimitive(final Object obj) {
216 return obj == null ||
217 obj == ScriptRuntime.UNDEFINED ||
218 obj instanceof Boolean ||
219 obj instanceof Number ||
220 obj instanceof String ||
221 obj instanceof ConsString;
222 }
223
224 /**
225 * Primitive converter for an object
226 *
227 * @param obj an object
228 *
229 * @return primitive form of the object
230 */
231 public static Object toPrimitive(final Object obj) {
232 return toPrimitive(obj, null);
233 }
234
235 /**
236 * Primitive converter for an object including type hint
237 * See ECMA 9.1 ToPrimitive
238 *
239 * @param obj an object
240 * @param hint a type hint
241 *
242 * @return the primitive form of the object
243 */
244 public static Object toPrimitive(final Object obj, final Class<?> hint) {
245 if (!(obj instanceof ScriptObject)) {
246 return obj;
247 }
248
249 final ScriptObject sobj = (ScriptObject)obj;
250 final Object result = sobj.getDefaultValue(hint);
251
252 if (!isPrimitive(result)) {
253 throw typeError("bad.default.value", result.toString());
254 }
255
256 return result;
257 }
258
259 /**
260 * JavaScript compliant conversion of number to boolean
261 *
262 * @param num a number
263 *
264 * @return a boolean
265 */
266 public static boolean toBoolean(final double num) {
267 return num != 0 && !Double.isNaN(num);
268 }
269
270 /**
271 * JavaScript compliant conversion of Object to boolean
272 * See ECMA 9.2 ToBoolean
273 *
274 * @param obj an object
275 *
276 * @return a boolean
277 */
278 public static boolean toBoolean(final Object obj) {
279 if (obj instanceof Boolean) {
280 return (Boolean)obj;
281 }
282
283 if (nullOrUndefined(obj)) {
284 return false;
285 }
286
287 if (obj instanceof Number) {
288 final double num = ((Number)obj).doubleValue();
289 return num != 0 && !Double.isNaN(num);
290 }
291
292 if (obj instanceof String || obj instanceof ConsString) {
293 return ((CharSequence)obj).length() > 0;
294 }
295
296 return true;
297 }
298
299
300 /**
301 * JavaScript compliant converter of Object to String
302 * See ECMA 9.8 ToString
303 *
304 * @param obj an object
305 *
306 * @return a string
307 */
308 public static String toString(final Object obj) {
309 return toStringImpl(obj, false);
310 }
311
312 /**
313 * If obj is an instance of {@link ConsString} cast to CharSequence, else return
314 * result of {@link #toString(Object)}.
315 *
316 * @param obj an object
317 * @return an instance of String or ConsString
318 */
319 public static CharSequence toCharSequence(final Object obj) {
320 if (obj instanceof ConsString) {
321 return (CharSequence) obj;
322 }
323 return toString(obj);
324 }
325
326 /**
327 * Check whether a string is representable as a JavaScript number
328 *
329 * @param str a string
330 *
331 * @return true if string can be represented as a number
332 */
333 public static boolean isNumber(final String str) {
334 try {
335 Double.parseDouble(str);
336 return true;
337 } catch (final NumberFormatException e) {
338 return false;
339 }
340 }
341
342 /**
343 * JavaScript compliant conversion of integer to String
344 *
345 * @param num an integer
346 *
347 * @return a string
348 */
349 public static String toString(final int num) {
350 return Integer.toString(num);
351 }
352
353 /**
354 * JavaScript compliant conversion of number to String
355 * See ECMA 9.8.1
356 *
357 * @param num a number
358 *
359 * @return a string
360 */
361 public static String toString(final double num) {
362 if (isRepresentableAsInt(num)) {
363 return Integer.toString((int)num);
364 }
365
366 if (num == Double.POSITIVE_INFINITY) {
367 return "Infinity";
368 }
369
370 if (num == Double.NEGATIVE_INFINITY) {
371 return "-Infinity";
372 }
373
374 if (Double.isNaN(num)) {
375 return "NaN";
376 }
377
378 return NumberToString.stringFor(num);
379 }
380
381 /**
382 * JavaScript compliant conversion of number to String
383 *
384 * @param num a number
385 * @param radix a radix for the conversion
386 *
387 * @return a string
388 */
389 public static String toString(final double num, final int radix) {
390 assert radix >= 2 && radix <= 36 : "invalid radix";
391
392 if (isRepresentableAsInt(num)) {
393 return Integer.toString((int)num, radix);
394 }
395
396 if (num == Double.POSITIVE_INFINITY) {
397 return "Infinity";
398 }
399
400 if (num == Double.NEGATIVE_INFINITY) {
401 return "-Infinity";
402 }
403
404 if (Double.isNaN(num)) {
405 return "NaN";
406 }
407
408 if (num == 0.0) {
409 return "0";
410 }
411
412 final String chars = "0123456789abcdefghijklmnopqrstuvwxyz";
413 final StringBuilder sb = new StringBuilder();
414
415 final boolean negative = num < 0.0;
416 final double signedNum = negative ? -num : num;
417
418 double intPart = Math.floor(signedNum);
419 double decPart = signedNum - intPart;
420
421 // encode integer part from least significant digit, then reverse
422 do {
423 sb.append(chars.charAt((int) (intPart % radix)));
424 intPart /= radix;
425 } while (intPart >= 1.0);
426
427 if (negative) {
428 sb.append('-');
429 }
430 sb.reverse();
431
432 // encode decimal part
433 if (decPart > 0.0) {
434 final int dot = sb.length();
435 sb.append('.');
436 do {
437 decPart *= radix;
438 final double d = Math.floor(decPart);
439 sb.append(chars.charAt((int)d));
440 decPart -= d;
441 } while (decPart > 0.0 && sb.length() - dot < 1100);
442 // somewhat arbitrarily use same limit as V8
443 }
444
445 return sb.toString();
446 }
447
448 /**
449 * JavaScript compliant conversion of Object to number
450 * See ECMA 9.3 ToNumber
451 *
452 * @param obj an object
453 *
454 * @return a number
455 */
456 public static double toNumber(final Object obj) {
457 if (obj instanceof Number) {
458 return ((Number)obj).doubleValue();
459 }
460 return toNumberGeneric(obj);
461 }
462
463 /**
464 * Digit representation for a character
465 *
466 * @param ch a character
467 * @param radix radix
468 *
469 * @return the digit for this character
470 */
471 public static int digit(final char ch, final int radix) {
472 return digit(ch, radix, false);
473 }
474
475 /**
476 * Digit representation for a character
477 *
478 * @param ch a character
479 * @param radix radix
480 * @param onlyIsoLatin1 iso latin conversion only
481 *
482 * @return the digit for this character
483 */
484 public static int digit(final char ch, final int radix, final boolean onlyIsoLatin1) {
485 final char maxInRadix = (char)('a' + (radix - 1) - 10);
486 final char c = Character.toLowerCase(ch);
487
488 if (c >= 'a' && c <= maxInRadix) {
489 return Character.digit(ch, radix);
490 }
491
492 if (Character.isDigit(ch)) {
493 if (!onlyIsoLatin1 || ch >= '0' && ch <= '9') {
494 return Character.digit(ch, radix);
495 }
496 }
497
498 return -1;
499 }
500
501 /**
502 * JavaScript compliant String to number conversion
503 *
504 * @param str a string
505 *
506 * @return a number
507 */
508 public static double toNumber(final String str) {
509 int end = str.length();
510 if (end == 0) {
511 return 0.0; // Empty string
512 }
513
514 int start = 0;
515 char f = str.charAt(0);
516
517 while (Lexer.isJSWhitespace(f)) {
518 if (++start == end) {
519 return 0.0d; // All whitespace string
520 }
521 f = str.charAt(start);
522 }
523
524 // Guaranteed to terminate even without start >= end check, as the previous loop found at least one
525 // non-whitespace character.
526 while (Lexer.isJSWhitespace(str.charAt(end - 1))) {
527 end--;
528 }
529
530 final boolean negative;
531 if (f == '-') {
532 if(++start == end) {
533 return Double.NaN; // Single-char "-" string
534 }
535 f = str.charAt(start);
536 negative = true;
537 } else {
538 if (f == '+') {
539 if (++start == end) {
540 return Double.NaN; // Single-char "+" string
541 }
542 f = str.charAt(start);
543 }
544 negative = false;
545 }
546
547 final double value;
548 if (start + 1 < end && f == '0' && Character.toLowerCase(str.charAt(start + 1)) == 'x') {
549 //decode hex string
550 value = parseRadix(str.toCharArray(), start + 2, end, 16);
551 } else {
552 // Fast (no NumberFormatException) path to NaN for non-numeric strings. We allow those starting with "I" or
553 // "N" to allow for parsing "NaN" and "Infinity" correctly.
554 if ((f < '0' || f > '9') && f != '.' && f != 'I' && f != 'N') {
555 return Double.NaN;
556 }
557 try {
558 value = Double.parseDouble(str.substring(start, end));
559 } catch (final NumberFormatException e) {
560 return Double.NaN;
561 }
562 }
563
564 return negative ? -value : value;
565 }
566
567 /**
568 * JavaScript compliant Object to integer conversion. See ECMA 9.4 ToInteger
569 *
570 * <p>Note that this returns {@link java.lang.Integer#MAX_VALUE} or {@link java.lang.Integer#MIN_VALUE}
571 * for double values that exceed the int range, including positive and negative Infinity. It is the
572 * caller's responsibility to handle such values correctly.</p>
573 *
574 * @param obj an object
575 * @return an integer
576 */
577 public static int toInteger(final Object obj) {
578 return (int)toNumber(obj);
579 }
580
581 /**
582 * JavaScript compliant Object to long conversion. See ECMA 9.4 ToInteger
583 *
584 * <p>Note that this returns {@link java.lang.Long#MAX_VALUE} or {@link java.lang.Long#MIN_VALUE}
585 * for double values that exceed the long range, including positive and negative Infinity. It is the
586 * caller's responsibility to handle such values correctly.</p>
587 *
588 * @param obj an object
589 * @return a long
590 */
591 public static long toLong(final Object obj) {
592 return (long)toNumber(obj);
593 }
594
595 /**
596 * JavaScript compliant Object to int32 conversion
597 * See ECMA 9.5 ToInt32
598 *
599 * @param obj an object
600 * @return an int32
601 */
602 public static int toInt32(final Object obj) {
603 return toInt32(toNumber(obj));
604 }
605
606 /**
607 * JavaScript compliant long to int32 conversion
608 *
609 * @param num a long
610 * @return an int32
611 */
612 public static int toInt32(final long num) {
613 return (int)num;
614 }
615
616 /**
617 * JavaScript compliant number to int32 conversion
618 *
619 * @param num a number
620 * @return an int32
621 */
622 public static int toInt32(final double num) {
623 return (int)doubleToInt32(num);
624 }
625
626 /**
627 * JavaScript compliant Object to int64 conversion
628 *
629 * @param obj an object
630 * @return an int64
631 */
632 public static long toInt64(final Object obj) {
633 return toInt64(toNumber(obj));
634 }
635
636 /**
637 * JavaScript compliant number to int64 conversion
638 *
639 * @param num a number
640 * @return an int64
641 */
642 public static long toInt64(final double num) {
643 if (Double.isInfinite(num)) {
644 return 0L;
645 }
646 return (long)num;
647 }
648
649 /**
650 * JavaScript compliant Object to uint32 conversion
651 *
652 * @param obj an object
653 * @return a uint32
654 */
655 public static long toUint32(final Object obj) {
656 return toUint32(toNumber(obj));
657 }
658
659 /**
660 * JavaScript compliant number to uint32 conversion
661 *
662 * @param num a number
663 * @return a uint32
664 */
665 public static long toUint32(final double num) {
666 return doubleToInt32(num) & MAX_UINT;
667 }
668
669 /**
670 * JavaScript compliant Object to uint16 conversion
671 * ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
672 *
673 * @param obj an object
674 * @return a uint16
675 */
676 public static int toUint16(final Object obj) {
677 return toUint16(toNumber(obj));
678 }
679
680 /**
681 * JavaScript compliant number to uint16 conversion
682 *
683 * @param num a number
684 * @return a uint16
685 */
686 public static int toUint16(final int num) {
687 return num & 0xffff;
688 }
689
690 /**
691 * JavaScript compliant number to uint16 conversion
692 *
693 * @param num a number
694 * @return a uint16
695 */
696 public static int toUint16(final long num) {
697 return ((int)num) & 0xffff;
698 }
699
700 /**
701 * JavaScript compliant number to uint16 conversion
702 *
703 * @param num a number
704 * @return a uint16
705 */
706 public static int toUint16(final double num) {
707 return ((int)doubleToInt32(num)) & 0xffff;
708 }
709
710 private static long doubleToInt32(final double num) {
711 final int exponent = Math.getExponent(num);
712 if (exponent < 31) {
713 return (long) num; // Fits into 32 bits
714 }
715 if (exponent >= 84) {
716 // Either infinite or NaN or so large that shift / modulo will produce 0
717 // (52 bit mantissa + 32 bit target width).
718 return 0;
719 }
720 // This is rather slow and could probably be sped up using bit-fiddling.
721 final double d = (num >= 0) ? Math.floor(num) : Math.ceil(num);
722 return (long)(d % INT32_LIMIT);
723 }
724
725 /**
726 * Check whether a number is finite
727 *
728 * @param num a number
729 * @return true if finite
730 */
731 public static boolean isFinite(final double num) {
732 return !Double.isInfinite(num) && !Double.isNaN(num);
733 }
734
735 /**
736 * Convert a primitive to a double
737 *
738 * @param num a double
739 * @return a boxed double
740 */
741 public static Double toDouble(final double num) {
742 return num;
743 }
744
745 /**
746 * Convert a primitive to a double
747 *
748 * @param num a long
749 * @return a boxed double
750 */
751 public static Double toDouble(final long num) {
752 return (double)num;
753 }
754
755 /**
756 * Convert a primitive to a double
757 *
758 * @param num an int
759 * @return a boxed double
760 */
761 public static Double toDouble(final int num) {
762 return (double)num;
763 }
764
765 /**
766 * Convert a boolean to an Object
767 *
768 * @param bool a boolean
769 * @return a boxed boolean, its Object representation
770 */
771 public static Object toObject(final boolean bool) {
772 return bool;
773 }
774
775 /**
776 * Convert a number to an Object
777 *
778 * @param num an integer
779 * @return the boxed number
780 */
781 public static Object toObject(final int num) {
782 return num;
783 }
784
785 /**
786 * Convert a number to an Object
787 *
788 * @param num a long
789 * @return the boxed number
790 */
791 public static Object toObject(final long num) {
792 return num;
793 }
794
795 /**
796 * Convert a number to an Object
797 *
798 * @param num a double
799 * @return the boxed number
800 */
801 public static Object toObject(final double num) {
802 return num;
803 }
804
805 /**
806 * Identity converter for objects.
807 *
808 * @param obj an object
809 * @return the boxed number
810 */
811 public static Object toObject(final Object obj) {
812 return obj;
813 }
814
815 /**
816 * Object conversion. This is used to convert objects and numbers to their corresponding
817 * NativeObject type
818 * See ECMA 9.9 ToObject
819 *
820 * @param obj the object to convert
821 *
822 * @return the wrapped object
823 */
824 public static Object toScriptObject(final Object obj) {
825 return toScriptObject(Context.getGlobalTrusted(), obj);
826 }
827
828 /**
829 * Object conversion. This is used to convert objects and numbers to their corresponding
830 * NativeObject type
831 * See ECMA 9.9 ToObject
832 *
833 * @param global the global object
834 * @param obj the object to convert
835 *
836 * @return the wrapped object
837 */
838 public static Object toScriptObject(final ScriptObject global, final Object obj) {
839 if (nullOrUndefined(obj)) {
840 throw typeError(global, "not.an.object", ScriptRuntime.safeToString(obj));
841 }
842
843 if (obj instanceof ScriptObject) {
844 return obj;
845 }
846
847 return ((GlobalObject)global).wrapAsObject(obj);
848 }
849
850 /**
851 * Check if an object is null or undefined
852 *
853 * @param obj object to check
854 *
855 * @return true if null or undefined
856 */
857 public static boolean nullOrUndefined(final Object obj) {
858 return obj == null || obj == ScriptRuntime.UNDEFINED;
859 }
860
861 static String toStringImpl(final Object obj, final boolean safe) {
862 if (obj instanceof String) {
863 return (String)obj;
864 }
865
866 if (obj instanceof Number) {
867 return toString(((Number)obj).doubleValue());
868 }
869
870 if (obj == ScriptRuntime.UNDEFINED) {
871 return "undefined";
872 }
873
874 if (obj == null) {
875 return "null";
876 }
877
878 if (obj instanceof ScriptObject) {
879 if (safe) {
880 final ScriptObject sobj = (ScriptObject)obj;
881 final GlobalObject gobj = (GlobalObject)Context.getGlobalTrusted();
882 return gobj.isError(sobj) ?
883 ECMAException.safeToString(sobj) :
884 sobj.safeToString();
885 }
886
887 return toString(toPrimitive(obj, String.class));
888 }
889
890 if (obj instanceof StaticClass) {
891 return "[JavaClass " + ((StaticClass)obj).getRepresentedClass().getName() + "]";
892 }
893
894 return obj.toString();
895 }
896
897 // trim from left for JS whitespaces.
898 static String trimLeft(final String str) {
899 int start = 0;
900
901 while (start < str.length() && Lexer.isJSWhitespace(str.charAt(start))) {
902 start++;
903 }
904
905 return str.substring(start);
906 }
907
908 private static double parseRadix(final char chars[], final int start, final int length, final int radix) {
909 int pos = 0;
910
911 for (int i = start; i < length ; i++) {
912 if (digit(chars[i], radix) == -1) {
913 break;
914 }
915 pos++;
916 }
917
918 if (pos == 0) {
919 return Double.NaN;
920 }
921
922 double value = 0.0;
923 for (int i = start; i < start + pos; i++) {
924 value *= radix;
925 value += digit(chars[i], radix);
926 }
927
928 return value;
929 }
930
931 private static double toNumberGeneric(final Object obj) {
932 if (obj == null) {
933 return +0.0;
934 }
935
936 if (obj instanceof String) {
937 return toNumber((String)obj);
938 }
939
940 if (obj instanceof ConsString) {
941 return toNumber(obj.toString());
942 }
943
944 if (obj instanceof Boolean) {
945 return (Boolean)obj ? 1 : +0.0;
946 }
947
948 if (obj instanceof ScriptObject) {
949 return toNumber(toPrimitive(obj, Number.class));
950 }
951
952 return Double.NaN;
953 }
954
955 }
--- EOF ---