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