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