src/jdk/nashorn/internal/objects/NativeString.java

Fri, 22 Feb 2013 12:22:16 +0100

author
lagergren
date
Fri, 22 Feb 2013 12:22:16 +0100
changeset 112
267cc4c85160
parent 90
5a820fb11814
child 114
508da3c7fc3a
permissions
-rw-r--r--

8007002: Replace implicit exception throwing methods with explicit throws - simplify control flow and remove useless code
Reviewed-by: attila, hannesw

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.objects;
jlaskey@3 27
jlaskey@3 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
jlaskey@3 29 import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
jlaskey@3 30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
jlaskey@3 31 import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndexNoThrow;
jlaskey@3 32 import static jdk.nashorn.internal.runtime.linker.Lookup.MH;
jlaskey@3 33
jlaskey@3 34 import java.lang.invoke.MethodHandle;
jlaskey@3 35 import java.lang.invoke.MethodHandles;
jlaskey@3 36 import java.text.Collator;
jlaskey@3 37 import java.util.ArrayList;
jlaskey@3 38 import java.util.Arrays;
hannesw@48 39 import java.util.LinkedList;
jlaskey@3 40 import java.util.List;
jlaskey@3 41 import java.util.regex.Pattern;
attila@90 42 import jdk.internal.dynalink.CallSiteDescriptor;
attila@90 43 import jdk.internal.dynalink.linker.GuardedInvocation;
attila@90 44 import jdk.internal.dynalink.linker.LinkRequest;
jlaskey@3 45 import jdk.nashorn.internal.objects.annotations.Attribute;
jlaskey@3 46 import jdk.nashorn.internal.objects.annotations.Constructor;
jlaskey@3 47 import jdk.nashorn.internal.objects.annotations.Function;
jlaskey@3 48 import jdk.nashorn.internal.objects.annotations.Getter;
jlaskey@3 49 import jdk.nashorn.internal.objects.annotations.ScriptClass;
jlaskey@3 50 import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
jlaskey@3 51 import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
jlaskey@3 52 import jdk.nashorn.internal.objects.annotations.Where;
jlaskey@3 53 import jdk.nashorn.internal.runtime.ConsString;
jlaskey@3 54 import jdk.nashorn.internal.runtime.JSType;
jlaskey@3 55 import jdk.nashorn.internal.runtime.ScriptFunction;
jlaskey@3 56 import jdk.nashorn.internal.runtime.ScriptObject;
jlaskey@3 57 import jdk.nashorn.internal.runtime.ScriptRuntime;
jlaskey@3 58 import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
sundar@37 59 import jdk.nashorn.internal.runtime.linker.MethodHandleFactory;
jlaskey@3 60 import jdk.nashorn.internal.runtime.linker.NashornGuards;
jlaskey@3 61 import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
jlaskey@3 62
jlaskey@3 63
jlaskey@3 64 /**
jlaskey@3 65 * ECMA 15.5 String Objects.
jlaskey@3 66 */
jlaskey@3 67 @ScriptClass("String")
jlaskey@3 68 public final class NativeString extends ScriptObject {
jlaskey@3 69
jlaskey@3 70 private final CharSequence value;
jlaskey@3 71
hannesw@42 72 static final MethodHandle WRAPFILTER = findWrapFilter();
jlaskey@3 73
jlaskey@3 74 NativeString(final CharSequence value) {
jlaskey@3 75 this(value, Global.instance().getStringPrototype());
jlaskey@3 76 }
jlaskey@3 77
jlaskey@3 78 private NativeString(final CharSequence value, final ScriptObject proto) {
jlaskey@3 79 assert value instanceof String || value instanceof ConsString;
jlaskey@3 80 this.value = value;
jlaskey@3 81 this.setProto(proto);
jlaskey@3 82 }
jlaskey@3 83
jlaskey@3 84 @Override
jlaskey@3 85 public String safeToString() {
jlaskey@3 86 return "[String " + toString() + "]";
jlaskey@3 87 }
jlaskey@3 88
jlaskey@3 89 @Override
jlaskey@3 90 public String toString() {
jlaskey@3 91 return getStringValue();
jlaskey@3 92 }
jlaskey@3 93
jlaskey@3 94 @Override
jlaskey@3 95 public boolean equals(final Object other) {
jlaskey@3 96 if (other instanceof NativeString) {
jlaskey@3 97 return getStringValue().equals(((NativeString) other).getStringValue());
jlaskey@3 98 }
jlaskey@3 99
jlaskey@3 100 return false;
jlaskey@3 101 }
jlaskey@3 102
jlaskey@3 103 @Override
jlaskey@3 104 public int hashCode() {
jlaskey@3 105 return getStringValue().hashCode();
jlaskey@3 106 }
jlaskey@3 107
jlaskey@3 108 private String getStringValue() {
jlaskey@3 109 return value instanceof String ? (String) value : value.toString();
jlaskey@3 110 }
jlaskey@3 111
jlaskey@3 112 private CharSequence getValue() {
jlaskey@3 113 return value;
jlaskey@3 114 }
jlaskey@3 115
jlaskey@3 116 @Override
jlaskey@3 117 public String getClassName() {
jlaskey@3 118 return "String";
jlaskey@3 119 }
jlaskey@3 120
jlaskey@3 121 @Override
jlaskey@3 122 public Object getLength() {
jlaskey@3 123 return value.length();
jlaskey@3 124 }
jlaskey@3 125
hannesw@51 126 // This is to provide array-like access to string characters without creating a NativeString wrapper.
hannesw@51 127 @Override
hannesw@51 128 protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
hannesw@51 129 final Object self = request.getReceiver();
hannesw@51 130 final Class<?> returnType = desc.getMethodType().returnType();
hannesw@51 131
hannesw@51 132 if (returnType == Object.class && (self instanceof String || self instanceof ConsString)) {
hannesw@51 133 try {
hannesw@51 134 MethodHandle mh = MethodHandles.lookup().findStatic(NativeString.class, "get", desc.getMethodType());
hannesw@51 135 return new GuardedInvocation(mh, NashornGuards.getInstanceOf2Guard(String.class, ConsString.class));
hannesw@51 136 } catch (final NoSuchMethodException | IllegalAccessException e) {
hannesw@51 137 // Shouldn't happen. Fall back to super
hannesw@51 138 }
hannesw@51 139 }
hannesw@51 140 return super.findGetIndexMethod(desc, request);
hannesw@51 141 }
hannesw@51 142
hannesw@51 143 @SuppressWarnings("unused")
hannesw@51 144 private static Object get(final Object self, final Object key) {
hannesw@51 145 final CharSequence cs = JSType.toCharSequence(self);
hannesw@51 146 final int index = getArrayIndexNoThrow(key);
hannesw@51 147 if (index >= 0 && index < cs.length()) {
hannesw@51 148 return String.valueOf(cs.charAt(index));
hannesw@51 149 }
hannesw@51 150 return ((ScriptObject) Global.toObject(self)).get(key);
hannesw@51 151 }
hannesw@51 152
hannesw@51 153 @SuppressWarnings("unused")
hannesw@51 154 private static Object get(final Object self, final double key) {
hannesw@51 155 if (isRepresentableAsInt(key)) {
hannesw@51 156 return get(self, (int)key);
hannesw@51 157 }
hannesw@51 158 return ((ScriptObject) Global.toObject(self)).get(key);
hannesw@51 159 }
hannesw@51 160
hannesw@51 161 @SuppressWarnings("unused")
hannesw@51 162 private static Object get(final Object self, final long key) {
hannesw@51 163 final CharSequence cs = JSType.toCharSequence(self);
hannesw@51 164 if (key >= 0 && key < cs.length()) {
hannesw@51 165 return String.valueOf(cs.charAt((int)key));
hannesw@51 166 }
hannesw@51 167 return ((ScriptObject) Global.toObject(self)).get(key);
hannesw@51 168 }
hannesw@51 169
hannesw@51 170 @SuppressWarnings("unused")
hannesw@51 171 private static Object get(final Object self, final int key) {
hannesw@51 172 final CharSequence cs = JSType.toCharSequence(self);
hannesw@51 173 if (key >= 0 && key < cs.length()) {
hannesw@51 174 return String.valueOf(cs.charAt(key));
hannesw@51 175 }
hannesw@51 176 return ((ScriptObject) Global.toObject(self)).get(key);
hannesw@51 177 }
hannesw@51 178
jlaskey@3 179 // String characters can be accessed with array-like indexing..
jlaskey@3 180 @Override
jlaskey@3 181 public Object get(final Object key) {
jlaskey@3 182 final int index = getArrayIndexNoThrow(key);
jlaskey@3 183 if (index >= 0 && index < value.length()) {
jlaskey@3 184 return String.valueOf(value.charAt(index));
jlaskey@3 185 }
jlaskey@3 186 return super.get(key);
jlaskey@3 187 }
jlaskey@3 188
jlaskey@3 189 @Override
jlaskey@3 190 public Object get(final double key) {
jlaskey@3 191 if (isRepresentableAsInt(key)) {
jlaskey@3 192 return get((int)key);
jlaskey@3 193 }
jlaskey@3 194 return super.get(key);
jlaskey@3 195 }
jlaskey@3 196
jlaskey@3 197 @Override
jlaskey@3 198 public Object get(final long key) {
jlaskey@3 199 if (key >= 0 && key < value.length()) {
jlaskey@3 200 return String.valueOf(value.charAt((int)key));
jlaskey@3 201 }
jlaskey@3 202 return super.get(key);
jlaskey@3 203 }
jlaskey@3 204
jlaskey@3 205 @Override
jlaskey@3 206 public Object get(final int key) {
jlaskey@3 207 if (key >= 0 && key < value.length()) {
jlaskey@3 208 return String.valueOf(value.charAt(key));
jlaskey@3 209 }
jlaskey@3 210 return super.get(key);
jlaskey@3 211 }
jlaskey@3 212
jlaskey@3 213 @Override
jlaskey@3 214 public int getInt(final Object key) {
jlaskey@3 215 return JSType.toInt32(get(key));
jlaskey@3 216 }
jlaskey@3 217
jlaskey@3 218 @Override
jlaskey@3 219 public int getInt(final double key) {
jlaskey@3 220 return JSType.toInt32(get(key));
jlaskey@3 221 }
jlaskey@3 222
jlaskey@3 223 @Override
jlaskey@3 224 public int getInt(final long key) {
jlaskey@3 225 return JSType.toInt32(get(key));
jlaskey@3 226 }
jlaskey@3 227
jlaskey@3 228 @Override
jlaskey@3 229 public int getInt(final int key) {
jlaskey@3 230 return JSType.toInt32(get(key));
jlaskey@3 231 }
jlaskey@3 232
jlaskey@3 233 @Override
jlaskey@3 234 public long getLong(final Object key) {
jlaskey@3 235 return JSType.toUint32(get(key));
jlaskey@3 236 }
jlaskey@3 237
jlaskey@3 238 @Override
jlaskey@3 239 public long getLong(final double key) {
jlaskey@3 240 return JSType.toUint32(get(key));
jlaskey@3 241 }
jlaskey@3 242
jlaskey@3 243 @Override
jlaskey@3 244 public long getLong(final long key) {
jlaskey@3 245 return JSType.toUint32(get(key));
jlaskey@3 246 }
jlaskey@3 247
jlaskey@3 248 @Override
jlaskey@3 249 public long getLong(final int key) {
jlaskey@3 250 return JSType.toUint32(get(key));
jlaskey@3 251 }
jlaskey@3 252
jlaskey@3 253 @Override
jlaskey@3 254 public double getDouble(final Object key) {
jlaskey@3 255 return JSType.toNumber(get(key));
jlaskey@3 256 }
jlaskey@3 257
jlaskey@3 258 @Override
jlaskey@3 259 public double getDouble(final double key) {
jlaskey@3 260 return JSType.toNumber(get(key));
jlaskey@3 261 }
jlaskey@3 262
jlaskey@3 263 @Override
jlaskey@3 264 public double getDouble(final long key) {
jlaskey@3 265 return JSType.toNumber(get(key));
jlaskey@3 266 }
jlaskey@3 267
jlaskey@3 268 @Override
jlaskey@3 269 public double getDouble(final int key) {
jlaskey@3 270 return JSType.toNumber(get(key));
jlaskey@3 271 }
jlaskey@3 272
jlaskey@3 273 @Override
jlaskey@3 274 public boolean has(final Object key) {
jlaskey@3 275 final int index = getArrayIndexNoThrow(key);
jlaskey@3 276 return isValid(index) || super.has(key);
jlaskey@3 277 }
jlaskey@3 278
jlaskey@3 279 @Override
jlaskey@3 280 public boolean has(final int key) {
jlaskey@3 281 return isValid(key) || super.has(key);
jlaskey@3 282 }
jlaskey@3 283
jlaskey@3 284 @Override
jlaskey@3 285 public boolean has(final long key) {
jlaskey@3 286 final int index = getArrayIndexNoThrow(key);
jlaskey@3 287 return isValid(index) || super.has(key);
jlaskey@3 288 }
jlaskey@3 289
jlaskey@3 290 @Override
jlaskey@3 291 public boolean has(final double key) {
jlaskey@3 292 final int index = getArrayIndexNoThrow(key);
jlaskey@3 293 return isValid(index) || super.has(key);
jlaskey@3 294 }
jlaskey@3 295
jlaskey@3 296 @Override
jlaskey@3 297 public boolean hasOwnProperty(final Object key) {
jlaskey@3 298 final int index = getArrayIndexNoThrow(key);
jlaskey@3 299 return isValid(index) || super.hasOwnProperty(key);
jlaskey@3 300 }
jlaskey@3 301
jlaskey@3 302 @Override
jlaskey@3 303 public boolean hasOwnProperty(final int key) {
jlaskey@3 304 return isValid(key) || super.hasOwnProperty(key);
jlaskey@3 305 }
jlaskey@3 306
jlaskey@3 307 @Override
jlaskey@3 308 public boolean hasOwnProperty(final long key) {
jlaskey@3 309 final int index = getArrayIndexNoThrow(key);
jlaskey@3 310 return isValid(index) || super.hasOwnProperty(key);
jlaskey@3 311 }
jlaskey@3 312
jlaskey@3 313 @Override
jlaskey@3 314 public boolean hasOwnProperty(final double key) {
jlaskey@3 315 final int index = getArrayIndexNoThrow(key);
jlaskey@3 316 return isValid(index) || super.hasOwnProperty(key);
jlaskey@3 317 }
jlaskey@3 318
jlaskey@3 319 @Override
jlaskey@3 320 public boolean delete(final int key, final boolean strict) {
jlaskey@3 321 return checkDeleteIndex(key, strict)? false : super.delete(key, strict);
jlaskey@3 322 }
jlaskey@3 323
jlaskey@3 324 @Override
jlaskey@3 325 public boolean delete(final long key, final boolean strict) {
jlaskey@3 326 final int index = getArrayIndexNoThrow(key);
jlaskey@3 327 return checkDeleteIndex(index, strict)? false : super.delete(key, strict);
jlaskey@3 328 }
jlaskey@3 329
jlaskey@3 330 @Override
jlaskey@3 331 public boolean delete(final double key, final boolean strict) {
jlaskey@3 332 final int index = getArrayIndexNoThrow(key);
jlaskey@3 333 return checkDeleteIndex(index, strict)? false : super.delete(key, strict);
jlaskey@3 334 }
jlaskey@3 335
jlaskey@3 336 @Override
jlaskey@3 337 public boolean delete(final Object key, final boolean strict) {
jlaskey@3 338 final int index = getArrayIndexNoThrow(key);
jlaskey@3 339 return checkDeleteIndex(index, strict)? false : super.delete(key, strict);
jlaskey@3 340 }
jlaskey@3 341
jlaskey@3 342 private boolean checkDeleteIndex(final int index, final boolean strict) {
jlaskey@3 343 if (isValid(index)) {
jlaskey@3 344 if (strict) {
lagergren@112 345 throw typeError("cant.delete.property", Integer.toString(index), ScriptRuntime.safeToString(this));
jlaskey@3 346 }
jlaskey@3 347 return true;
jlaskey@3 348 }
jlaskey@3 349
jlaskey@3 350 return false;
jlaskey@3 351 }
jlaskey@3 352
jlaskey@3 353 @Override
jlaskey@3 354 public Object getOwnPropertyDescriptor(final String key) {
jlaskey@3 355 final int index = ArrayIndex.getArrayIndexNoThrow(key);
jlaskey@3 356 if (index >= 0 && index < value.length()) {
jlaskey@3 357 final Global global = Global.instance();
jlaskey@3 358 return global.newDataDescriptor(String.valueOf(value.charAt(index)), false, true, false);
jlaskey@3 359 }
jlaskey@3 360
jlaskey@3 361 return super.getOwnPropertyDescriptor(key);
jlaskey@3 362 }
jlaskey@3 363
jlaskey@3 364 /**
jlaskey@3 365 * return a List of own keys associated with the object.
jlaskey@3 366 * @param all True if to include non-enumerable keys.
jlaskey@3 367 * @return Array of keys.
jlaskey@3 368 */
jlaskey@3 369 @Override
jlaskey@3 370 public String[] getOwnKeys(final boolean all) {
jlaskey@3 371 final List<Object> keys = new ArrayList<>();
jlaskey@3 372
jlaskey@3 373 // add string index keys
jlaskey@3 374 for (int i = 0; i < value.length(); i++) {
jlaskey@3 375 keys.add(JSType.toString(i));
jlaskey@3 376 }
jlaskey@3 377
jlaskey@3 378 // add super class properties
jlaskey@3 379 keys.addAll(Arrays.asList(super.getOwnKeys(all)));
jlaskey@3 380 return keys.toArray(new String[keys.size()]);
jlaskey@3 381 }
jlaskey@3 382
jlaskey@3 383 /**
jlaskey@3 384 * ECMA 15.5.3 String.length
jlaskey@3 385 * @param self self reference
jlaskey@3 386 * @return value of length property for string
jlaskey@3 387 */
jlaskey@3 388 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
jlaskey@3 389 public static Object length(final Object self) {
jlaskey@3 390 return getCharSequence(self).length();
jlaskey@3 391 }
jlaskey@3 392
jlaskey@3 393 /**
jlaskey@3 394 * ECMA 15.5.3.2 String.fromCharCode ( [ char0 [ , char1 [ , ... ] ] ] )
jlaskey@3 395 * @param self self reference
jlaskey@3 396 * @param args array of arguments to be interpreted as char
jlaskey@3 397 * @return string with arguments translated to charcodes
jlaskey@3 398 */
jlaskey@3 399 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1, where = Where.CONSTRUCTOR)
jlaskey@3 400 public static Object fromCharCode(final Object self, final Object... args) {
jlaskey@3 401 final char[] buf = new char[args.length];
jlaskey@3 402 int index = 0;
jlaskey@3 403 for (final Object arg : args) {
jlaskey@3 404 buf[index++] = (char)JSType.toUint16(arg);
jlaskey@3 405 }
jlaskey@3 406 return new String(buf);
jlaskey@3 407 }
jlaskey@3 408
jlaskey@3 409 /**
jlaskey@3 410 * ECMA 15.5.3.2 - specialization for one char
jlaskey@3 411 * @param self self reference
jlaskey@3 412 * @param value one argument to be interpreted as char
jlaskey@3 413 * @return string with one charcode
jlaskey@3 414 */
jlaskey@3 415 @SpecializedFunction
jlaskey@3 416 public static Object fromCharCode(final Object self, final Object value) {
jlaskey@3 417 try {
jlaskey@3 418 return "" + (char)JSType.toUint16(((Number)value).doubleValue());
jlaskey@3 419 } catch (final ClassCastException e) {
jlaskey@3 420 return fromCharCode(self, new Object[] { value });
jlaskey@3 421 }
jlaskey@3 422 }
jlaskey@3 423
jlaskey@3 424 /**
jlaskey@3 425 * ECMA 15.5.3.2 - specialization for one char of int type
jlaskey@3 426 * @param self self reference
jlaskey@3 427 * @param value one argument to be interpreted as char
jlaskey@3 428 * @return string with one charcode
jlaskey@3 429 */
jlaskey@3 430 @SpecializedFunction
jlaskey@3 431 public static Object fromCharCode(final Object self, final int value) {
jlaskey@3 432 return "" + (char)(value & 0xffff);
jlaskey@3 433 }
jlaskey@3 434
jlaskey@3 435 /**
jlaskey@3 436 * ECMA 15.5.3.2 - specialization for one char of long type
jlaskey@3 437 * @param self self reference
jlaskey@3 438 * @param value one argument to be interpreted as char
jlaskey@3 439 * @return string with one charcode
jlaskey@3 440 */
jlaskey@3 441 @SpecializedFunction
jlaskey@3 442 public static Object fromCharCode(final Object self, final long value) {
jlaskey@3 443 return "" + (char)((int)value & 0xffff);
jlaskey@3 444 }
jlaskey@3 445
jlaskey@3 446 /**
jlaskey@3 447 * ECMA 15.5.3.2 - specialization for one char of double type
jlaskey@3 448 * @param self self reference
jlaskey@3 449 * @param value one argument to be interpreted as char
jlaskey@3 450 * @return string with one charcode
jlaskey@3 451 */
jlaskey@3 452 @SpecializedFunction
jlaskey@3 453 public static Object fromCharCode(final Object self, final double value) {
jlaskey@3 454 return "" + (char)JSType.toUint16(value);
jlaskey@3 455 }
jlaskey@3 456
jlaskey@3 457 /**
jlaskey@3 458 * ECMA 15.5.4.2 String.prototype.toString ( )
jlaskey@3 459 * @param self self reference
jlaskey@3 460 * @return self as string
jlaskey@3 461 */
jlaskey@3 462 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 463 public static Object toString(final Object self) {
jlaskey@3 464 return getString(self);
jlaskey@3 465 }
jlaskey@3 466
jlaskey@3 467 /**
jlaskey@3 468 * ECMA 15.5.4.3 String.prototype.valueOf ( )
jlaskey@3 469 * @param self self reference
jlaskey@3 470 * @return self as string
jlaskey@3 471 */
jlaskey@3 472 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 473 public static Object valueOf(final Object self) {
jlaskey@3 474 return getString(self);
jlaskey@3 475 }
jlaskey@3 476
jlaskey@3 477 /**
jlaskey@3 478 * ECMA 15.5.4.4 String.prototype.charAt (pos)
jlaskey@3 479 * @param self self reference
jlaskey@3 480 * @param pos position in string
jlaskey@3 481 * @return string representing the char at the given position
jlaskey@3 482 */
jlaskey@3 483 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 484 public static Object charAt(final Object self, final Object pos) {
hannesw@48 485 return charAt(self, JSType.toInteger(pos));
hannesw@48 486 }
hannesw@48 487
hannesw@48 488 /**
hannesw@48 489 * ECMA 15.5.4.4 String.prototype.charAt (pos) - specialized version for double position
hannesw@48 490 * @param self self reference
hannesw@48 491 * @param pos position in string
hannesw@48 492 * @return string representing the char at the given position
hannesw@48 493 */
hannesw@48 494 @SpecializedFunction
hannesw@48 495 public static String charAt(final Object self, final double pos) {
hannesw@48 496 return charAt(self, (int)pos);
hannesw@48 497 }
hannesw@48 498
hannesw@48 499 /**
hannesw@48 500 * ECMA 15.5.4.4 String.prototype.charAt (pos) - specialized version for int position
hannesw@48 501 * @param self self reference
hannesw@48 502 * @param pos position in string
hannesw@48 503 * @return string representing the char at the given position
hannesw@48 504 */
hannesw@48 505 @SpecializedFunction
hannesw@48 506 public static String charAt(final Object self, final int pos) {
hannesw@48 507 final String str = checkObjectToString(self);
hannesw@48 508 return (pos < 0 || pos >= str.length()) ? "" : String.valueOf(str.charAt(pos));
jlaskey@3 509 }
jlaskey@3 510
jlaskey@3 511 /**
jlaskey@3 512 * ECMA 15.5.4.5 String.prototype.charCodeAt (pos)
jlaskey@3 513 * @param self self reference
jlaskey@3 514 * @param pos position in string
jlaskey@3 515 * @return number representing charcode at position
jlaskey@3 516 */
jlaskey@3 517 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 518 public static Object charCodeAt(final Object self, final Object pos) {
hannesw@48 519 return charCodeAt(self, JSType.toInteger(pos));
hannesw@48 520 }
jlaskey@3 521
hannesw@48 522 /**
hannesw@48 523 * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for double position
hannesw@48 524 * @param self self reference
hannesw@48 525 * @param pos position in string
hannesw@48 526 * @return number representing charcode at position
hannesw@48 527 */
hannesw@48 528 @SpecializedFunction
hannesw@48 529 public static double charCodeAt(final Object self, final double pos) {
hannesw@48 530 return charCodeAt(self, (int) pos);
hannesw@48 531 }
hannesw@48 532
hannesw@48 533 /**
hannesw@48 534 * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for int position
hannesw@48 535 * @param self self reference
hannesw@48 536 * @param pos position in string
hannesw@48 537 * @return number representing charcode at position
hannesw@48 538 */
hannesw@48 539 @SpecializedFunction
hannesw@48 540 public static double charCodeAt(final Object self, final int pos) {
hannesw@48 541 final String str = checkObjectToString(self);
hannesw@48 542 return (pos < 0 || pos >= str.length()) ? Double.NaN : str.charAt(pos);
jlaskey@3 543 }
jlaskey@3 544
jlaskey@3 545 /**
jlaskey@3 546 * ECMA 15.5.4.6 String.prototype.concat ( [ string1 [ , string2 [ , ... ] ] ] )
jlaskey@3 547 * @param self self reference
jlaskey@3 548 * @param args list of string to concatenate
jlaskey@3 549 * @return concatenated string
jlaskey@3 550 */
jlaskey@3 551 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
jlaskey@3 552 public static Object concat(final Object self, final Object... args) {
hannesw@48 553 CharSequence cs = checkObjectToString(self);
jlaskey@3 554 if (args != null) {
jlaskey@3 555 for (final Object obj : args) {
hannesw@48 556 cs = new ConsString(cs, JSType.toCharSequence(obj));
jlaskey@3 557 }
jlaskey@3 558 }
hannesw@48 559 return cs;
jlaskey@3 560 }
jlaskey@3 561
jlaskey@3 562 /**
jlaskey@3 563 * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position)
jlaskey@3 564 * @param self self reference
jlaskey@3 565 * @param search string to search for
jlaskey@3 566 * @param pos position to start search
jlaskey@3 567 * @return position of first match or -1
jlaskey@3 568 */
jlaskey@3 569 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
jlaskey@3 570 public static Object indexOf(final Object self, final Object search, final Object pos) {
hannesw@48 571 final String str = checkObjectToString(self);
hannesw@48 572 return str.indexOf(JSType.toString(search), JSType.toInteger(pos));
hannesw@48 573 }
hannesw@48 574
hannesw@48 575 /**
hannesw@48 576 * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for no position parameter
hannesw@48 577 * @param self self reference
hannesw@48 578 * @param search string to search for
hannesw@48 579 * @return position of first match or -1
hannesw@48 580 */
hannesw@48 581 @SpecializedFunction
hannesw@48 582 public static int indexOf(final Object self, final Object search) {
hannesw@48 583 return indexOf(self, search, 0);
hannesw@48 584 }
hannesw@48 585
hannesw@48 586 /**
hannesw@48 587 * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for double position parameter
hannesw@48 588 * @param self self reference
hannesw@48 589 * @param search string to search for
hannesw@48 590 * @param pos position to start search
hannesw@48 591 * @return position of first match or -1
hannesw@48 592 */
hannesw@48 593 @SpecializedFunction
hannesw@48 594 public static int indexOf(final Object self, final Object search, final double pos) {
hannesw@48 595 return indexOf(self, search, (int) pos);
hannesw@48 596 }
hannesw@48 597
hannesw@48 598 /**
hannesw@48 599 * ECMA 15.5.4.7 String.prototype.indexOf (searchString, position) specialized for int position parameter
hannesw@48 600 * @param self self reference
hannesw@48 601 * @param search string to search for
hannesw@48 602 * @param pos position to start search
hannesw@48 603 * @return position of first match or -1
hannesw@48 604 */
hannesw@48 605 @SpecializedFunction
hannesw@48 606 public static int indexOf(final Object self, final Object search, final int pos) {
hannesw@48 607 return checkObjectToString(self).indexOf(JSType.toString(search), pos);
jlaskey@3 608 }
jlaskey@3 609
jlaskey@3 610 /**
jlaskey@3 611 * ECMA 15.5.4.8 String.prototype.lastIndexOf (searchString, position)
jlaskey@3 612 * @param self self reference
jlaskey@3 613 * @param search string to search for
jlaskey@3 614 * @param pos position to start search
jlaskey@3 615 * @return last position of match or -1
jlaskey@3 616 */
jlaskey@3 617 @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
jlaskey@3 618 public static Object lastIndexOf(final Object self, final Object search, final Object pos) {
jlaskey@3 619
hannesw@48 620 final String str = checkObjectToString(self);
jlaskey@3 621 final String searchStr = JSType.toString(search);
jlaskey@3 622
jlaskey@3 623 int from;
jlaskey@3 624
jlaskey@3 625 if (pos == UNDEFINED) {
jlaskey@3 626 from = str.length();
jlaskey@3 627 } else {
jlaskey@3 628 final double numPos = JSType.toNumber(pos);
jlaskey@3 629 from = !Double.isNaN(numPos) ? (int)numPos : (int)Double.POSITIVE_INFINITY;
jlaskey@3 630 }
jlaskey@3 631
jlaskey@3 632 return str.lastIndexOf(searchStr, from);
jlaskey@3 633 }
jlaskey@3 634
jlaskey@3 635 /**
jlaskey@3 636 * ECMA 15.5.4.9 String.prototype.localeCompare (that)
jlaskey@3 637 * @param self self reference
jlaskey@3 638 * @param that comparison object
jlaskey@3 639 * @return result of locale sensitive comparison operation between {@code self} and {@code that}
jlaskey@3 640 */
jlaskey@3 641 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 642 public static Object localeCompare(final Object self, final Object that) {
jlaskey@3 643
hannesw@48 644 final String str = checkObjectToString(self);
jlaskey@3 645 final Collator collator = Collator.getInstance(Global.getThisContext().getLocale());
jlaskey@3 646
jlaskey@3 647 collator.setStrength(Collator.IDENTICAL);
jlaskey@3 648 collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
jlaskey@3 649
jlaskey@3 650 return (double)collator.compare(str, JSType.toString(that));
jlaskey@3 651 }
jlaskey@3 652
jlaskey@3 653 /**
jlaskey@3 654 * ECMA 15.5.4.10 String.prototype.match (regexp)
jlaskey@3 655 * @param self self reference
jlaskey@3 656 * @param regexp regexp expression
jlaskey@3 657 * @return array of regexp matches
jlaskey@3 658 */
jlaskey@3 659 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 660 public static Object match(final Object self, final Object regexp) {
jlaskey@3 661
hannesw@48 662 final String str = checkObjectToString(self);
jlaskey@3 663
jlaskey@3 664 NativeRegExp nativeRegExp;
jlaskey@3 665 if (regexp == UNDEFINED) {
jlaskey@3 666 nativeRegExp = new NativeRegExp("");
jlaskey@3 667 } else {
jlaskey@3 668 nativeRegExp = Global.toRegExp(regexp);
jlaskey@3 669 }
jlaskey@3 670
jlaskey@3 671 if (!nativeRegExp.getGlobal()) {
jlaskey@3 672 return nativeRegExp.exec(str);
jlaskey@3 673 }
jlaskey@3 674
jlaskey@3 675 nativeRegExp.setLastIndex(0);
jlaskey@3 676
jlaskey@3 677 int previousLastIndex = 0;
jlaskey@3 678 final List<Object> matches = new ArrayList<>();
jlaskey@3 679
jlaskey@3 680 Object result;
jlaskey@3 681 while ((result = nativeRegExp.exec(str)) != null) {
jlaskey@3 682 final int thisIndex = nativeRegExp.getLastIndex();
jlaskey@3 683 if (thisIndex == previousLastIndex) {
jlaskey@3 684 nativeRegExp.setLastIndex(thisIndex + 1);
jlaskey@3 685 previousLastIndex = thisIndex + 1;
jlaskey@3 686 } else {
jlaskey@3 687 previousLastIndex = thisIndex;
jlaskey@3 688 }
jlaskey@3 689 matches.add(((ScriptObject)result).get(0));
jlaskey@3 690 }
jlaskey@3 691
jlaskey@3 692 if (matches.isEmpty()) {
jlaskey@3 693 return null;
jlaskey@3 694 }
jlaskey@3 695
jlaskey@3 696 return new NativeArray(matches.toArray());
jlaskey@3 697 }
jlaskey@3 698
jlaskey@3 699 /**
jlaskey@3 700 * ECMA 15.5.4.11 String.prototype.replace (searchValue, replaceValue)
jlaskey@3 701 * @param self self reference
jlaskey@3 702 * @param string item to replace
jlaskey@3 703 * @param replacement item to replace it with
jlaskey@3 704 * @return string after replacement
jlaskey@3 705 */
jlaskey@3 706 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 707 public static Object replace(final Object self, final Object string, final Object replacement) {
jlaskey@3 708
hannesw@48 709 final String str = checkObjectToString(self);
jlaskey@3 710
jlaskey@3 711 final NativeRegExp nativeRegExp;
jlaskey@3 712 if (string instanceof NativeRegExp) {
jlaskey@3 713 nativeRegExp = (NativeRegExp) string;
jlaskey@3 714 } else {
jlaskey@3 715 nativeRegExp = new NativeRegExp(Pattern.compile(JSType.toString(string), Pattern.LITERAL));
jlaskey@3 716 }
jlaskey@3 717
jlaskey@3 718 if (replacement instanceof ScriptFunction) {
jlaskey@3 719 return nativeRegExp.replace(str, "", (ScriptFunction)replacement);
jlaskey@3 720 }
jlaskey@3 721
jlaskey@3 722 return nativeRegExp.replace(str, JSType.toString(replacement), null);
jlaskey@3 723 }
jlaskey@3 724
jlaskey@3 725 /**
jlaskey@3 726 * ECMA 15.5.4.12 String.prototype.search (regexp)
jlaskey@3 727 *
jlaskey@3 728 * @param self self reference
jlaskey@3 729 * @param string string to search for
jlaskey@3 730 * @return offset where match occurred
jlaskey@3 731 */
jlaskey@3 732 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 733 public static Object search(final Object self, final Object string) {
jlaskey@3 734
hannesw@48 735 final String str = checkObjectToString(self);
jlaskey@3 736 final NativeRegExp nativeRegExp = Global.toRegExp(string == UNDEFINED ? "" : string);
jlaskey@3 737
jlaskey@3 738 return nativeRegExp.search(str);
jlaskey@3 739 }
jlaskey@3 740
jlaskey@3 741 /**
jlaskey@3 742 * ECMA 15.5.4.13 String.prototype.slice (start, end)
jlaskey@3 743 *
jlaskey@3 744 * @param self self reference
jlaskey@3 745 * @param start start position for slice
jlaskey@3 746 * @param end end position for slice
jlaskey@3 747 * @return sliced out substring
jlaskey@3 748 */
jlaskey@3 749 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 750 public static Object slice(final Object self, final Object start, final Object end) {
jlaskey@3 751
hannesw@48 752 final String str = checkObjectToString(self);
hannesw@48 753 if (end == UNDEFINED) {
hannesw@48 754 return slice(str, JSType.toInteger(start));
hannesw@48 755 }
hannesw@48 756 return slice(str, JSType.toInteger(start), JSType.toInteger(end));
hannesw@48 757 }
jlaskey@3 758
hannesw@48 759 /**
hannesw@48 760 * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for single int parameter
hannesw@48 761 *
hannesw@48 762 * @param self self reference
hannesw@48 763 * @param start start position for slice
hannesw@48 764 * @return sliced out substring
hannesw@48 765 */
hannesw@48 766 @SpecializedFunction
hannesw@48 767 public static Object slice(final Object self, final int start) {
hannesw@48 768 final String str = checkObjectToString(self);
hannesw@48 769 final int from = (start < 0) ? Math.max(str.length() + start, 0) : Math.min(start, str.length());
jlaskey@3 770
hannesw@48 771 return str.substring(from);
hannesw@48 772 }
jlaskey@3 773
hannesw@48 774 /**
hannesw@48 775 * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for single double parameter
hannesw@48 776 *
hannesw@48 777 * @param self self reference
hannesw@48 778 * @param start start position for slice
hannesw@48 779 * @return sliced out substring
hannesw@48 780 */
hannesw@48 781 @SpecializedFunction
hannesw@48 782 public static Object slice(final Object self, final double start) {
hannesw@48 783 return slice(self, (int)start);
hannesw@48 784 }
jlaskey@3 785
hannesw@48 786 /**
hannesw@48 787 * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for two int parameters
hannesw@48 788 *
hannesw@48 789 * @param self self reference
hannesw@48 790 * @param start start position for slice
lagergren@57 791 * @param end end position for slice
hannesw@48 792 * @return sliced out substring
hannesw@48 793 */
hannesw@48 794 @SpecializedFunction
hannesw@48 795 public static Object slice(final Object self, final int start, final int end) {
jlaskey@3 796
hannesw@48 797 final String str = checkObjectToString(self);
hannesw@48 798 final int len = str.length();
hannesw@48 799
hannesw@48 800 final int from = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);
hannesw@48 801 final int to = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len);
hannesw@48 802
hannesw@48 803 return str.substring(Math.min(from, to), to);
hannesw@48 804 }
hannesw@48 805
hannesw@48 806 /**
hannesw@48 807 * ECMA 15.5.4.13 String.prototype.slice (start, end) specialized for two double parameters
hannesw@48 808 *
hannesw@48 809 * @param self self reference
hannesw@48 810 * @param start start position for slice
lagergren@57 811 * @param end end position for slice
hannesw@48 812 * @return sliced out substring
hannesw@48 813 */
hannesw@48 814 @SpecializedFunction
hannesw@48 815 public static Object slice(final Object self, final double start, final double end) {
hannesw@48 816 return slice(self, (int)start, (int)end);
jlaskey@3 817 }
jlaskey@3 818
jlaskey@3 819 /**
jlaskey@3 820 * ECMA 15.5.4.14 String.prototype.split (separator, limit)
jlaskey@3 821 *
jlaskey@3 822 * @param self self reference
jlaskey@3 823 * @param separator separator for split
jlaskey@3 824 * @param limit limit for splits
jlaskey@3 825 * @return array object in which splits have been placed
jlaskey@3 826 */
jlaskey@3 827 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 828 public static Object split(final Object self, final Object separator, final Object limit) {
jlaskey@3 829
hannesw@48 830 final String str = checkObjectToString(self);
jlaskey@3 831
jlaskey@3 832 if (separator == UNDEFINED) {
jlaskey@3 833 return new NativeArray(new Object[]{str});
jlaskey@3 834 }
jlaskey@3 835
jlaskey@3 836 final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit);
jlaskey@3 837
jlaskey@3 838 if (separator instanceof NativeRegExp) {
jlaskey@3 839 return ((NativeRegExp) separator).split(str, lim);
jlaskey@3 840 }
jlaskey@3 841
hannesw@48 842 // when separator is a string, it is treated as a literal search string to be used for splitting.
hannesw@48 843 return splitString(str, JSType.toString(separator), lim);
hannesw@48 844 }
hannesw@48 845
hannesw@48 846 private static Object splitString(String str, String separator, long limit) {
lagergren@57 847 if (separator.isEmpty()) {
lagergren@57 848 final Object[] array = new Object[str.length()];
hannesw@48 849 for (int i = 0; i < array.length; i++) {
hannesw@48 850 array[i] = String.valueOf(str.charAt(i));
hannesw@48 851 }
hannesw@48 852 return new NativeArray(array);
hannesw@48 853 }
hannesw@48 854
hannesw@48 855 final List<String> elements = new LinkedList<>();
hannesw@48 856 final int strLength = str.length();
hannesw@48 857 final int sepLength = separator.length();
hannesw@48 858 int pos = 0;
lagergren@57 859 int n = 0;
hannesw@48 860
lagergren@57 861 while (pos < strLength && n < limit) {
hannesw@48 862 int found = str.indexOf(separator, pos);
hannesw@48 863 if (found == -1) {
hannesw@48 864 break;
hannesw@48 865 }
hannesw@48 866 elements.add(str.substring(pos, found));
lagergren@57 867 n++;
hannesw@48 868 pos = found + sepLength;
hannesw@48 869 }
lagergren@57 870 if (pos <= strLength && n < limit) {
hannesw@48 871 elements.add(str.substring(pos));
hannesw@48 872 }
hannesw@48 873
hannesw@48 874 return new NativeArray(elements.toArray());
jlaskey@3 875 }
jlaskey@3 876
jlaskey@3 877 /**
jlaskey@3 878 * ECMA B.2.3 String.prototype.substr (start, length)
jlaskey@3 879 *
jlaskey@3 880 * @param self self reference
jlaskey@3 881 * @param start start position
jlaskey@3 882 * @param length length of section
jlaskey@3 883 * @return substring given start and length of section
jlaskey@3 884 */
jlaskey@3 885 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 886 public static Object substr(final Object self, final Object start, final Object length) {
jlaskey@3 887 final String str = JSType.toString(self);
jlaskey@3 888 final int strLength = str.length();
jlaskey@3 889
jlaskey@3 890 int intStart = JSType.toInteger(start);
jlaskey@3 891 if (intStart < 0) {
jlaskey@3 892 intStart = Math.max(intStart + strLength, 0);
jlaskey@3 893 }
jlaskey@3 894
jlaskey@3 895 final int intLen = Math.min(Math.max((length == UNDEFINED) ? Integer.MAX_VALUE : JSType.toInteger(length), 0), strLength - intStart);
jlaskey@3 896
jlaskey@3 897 return intLen <= 0 ? "" : str.substring(intStart, intStart + intLen);
jlaskey@3 898 }
jlaskey@3 899
jlaskey@3 900 /**
jlaskey@3 901 * ECMA 15.5.4.15 String.prototype.substring (start, end)
jlaskey@3 902 *
jlaskey@3 903 * @param self self reference
jlaskey@3 904 * @param start start position of substring
jlaskey@3 905 * @param end end position of substring
jlaskey@3 906 * @return substring given start and end indexes
jlaskey@3 907 */
jlaskey@3 908 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 909 public static Object substring(final Object self, final Object start, final Object end) {
jlaskey@3 910
hannesw@48 911 final String str = checkObjectToString(self);
hannesw@48 912 if (end == UNDEFINED) {
hannesw@48 913 return substring(str, JSType.toInteger(start));
hannesw@48 914 }
hannesw@48 915 return substring(str, JSType.toInteger(start), JSType.toInteger(end));
hannesw@48 916 }
jlaskey@3 917
hannesw@48 918 /**
hannesw@48 919 * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for int start parameter
hannesw@48 920 *
hannesw@48 921 * @param self self reference
hannesw@48 922 * @param start start position of substring
hannesw@48 923 * @return substring given start and end indexes
hannesw@48 924 */
hannesw@48 925 @SpecializedFunction
hannesw@48 926 public static String substring(final Object self, final int start) {
hannesw@48 927 final String str = checkObjectToString(self);
hannesw@48 928 if (start < 0) {
hannesw@48 929 return str;
hannesw@48 930 } else if (start >= str.length()) {
hannesw@48 931 return "";
hannesw@48 932 } else {
hannesw@48 933 return str.substring(start);
hannesw@48 934 }
hannesw@48 935 }
jlaskey@3 936
hannesw@48 937 /**
hannesw@48 938 * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for double start parameter
hannesw@48 939 *
hannesw@48 940 * @param self self reference
hannesw@48 941 * @param start start position of substring
hannesw@48 942 * @return substring given start and end indexes
hannesw@48 943 */
hannesw@48 944 @SpecializedFunction
hannesw@48 945 public static String substring(final Object self, final double start) {
hannesw@48 946 return substring(self, (int)start);
hannesw@48 947 }
hannesw@48 948
hannesw@48 949 /**
hannesw@48 950 * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for int start and end parameters
hannesw@48 951 *
hannesw@48 952 * @param self self reference
hannesw@48 953 * @param start start position of substring
hannesw@48 954 * @param end end position of substring
hannesw@48 955 * @return substring given start and end indexes
hannesw@48 956 */
hannesw@48 957 @SpecializedFunction
hannesw@48 958 public static String substring(final Object self, final int start, final int end) {
hannesw@48 959 final String str = checkObjectToString(self);
hannesw@48 960 final int len = str.length();
hannesw@48 961 final int validStart = start < 0 ? 0 : (start > len ? len : start);
hannesw@48 962 final int validEnd = end < 0 ? 0 : (end > len ? len : end);
hannesw@48 963
hannesw@48 964 if (validStart < validEnd) {
hannesw@48 965 return str.substring(validStart, validEnd);
jlaskey@3 966 }
lagergren@57 967 return str.substring(validEnd, validStart);
hannesw@48 968 }
hannesw@48 969
hannesw@48 970 /**
hannesw@48 971 * ECMA 15.5.4.15 String.prototype.substring (start, end) specialized for double start and end parameters
hannesw@48 972 *
hannesw@48 973 * @param self self reference
hannesw@48 974 * @param start start position of substring
hannesw@48 975 * @param end end position of substring
hannesw@48 976 * @return substring given start and end indexes
hannesw@48 977 */
hannesw@48 978 @SpecializedFunction
hannesw@48 979 public static String substring(final Object self, final double start, final double end) {
hannesw@48 980 return substring(self, (int)start, (int)end);
jlaskey@3 981 }
jlaskey@3 982
jlaskey@3 983 /**
jlaskey@3 984 * ECMA 15.5.4.16 String.prototype.toLowerCase ( )
jlaskey@3 985 * @param self self reference
jlaskey@3 986 * @return string to lower case
jlaskey@3 987 */
jlaskey@3 988 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 989 public static Object toLowerCase(final Object self) {
hannesw@48 990 return checkObjectToString(self).toLowerCase();
jlaskey@3 991 }
jlaskey@3 992
jlaskey@3 993 /**
jlaskey@3 994 * ECMA 15.5.4.17 String.prototype.toLocaleLowerCase ( )
jlaskey@3 995 * @param self self reference
jlaskey@3 996 * @return string to locale sensitive lower case
jlaskey@3 997 */
jlaskey@3 998 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 999 public static Object toLocaleLowerCase(final Object self) {
hannesw@48 1000 return checkObjectToString(self).toLowerCase(Global.getThisContext().getLocale());
jlaskey@3 1001 }
jlaskey@3 1002
jlaskey@3 1003 /**
jlaskey@3 1004 * ECMA 15.5.4.18 String.prototype.toUpperCase ( )
jlaskey@3 1005 * @param self self reference
jlaskey@3 1006 * @return string to upper case
jlaskey@3 1007 */
jlaskey@3 1008 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 1009 public static Object toUpperCase(final Object self) {
hannesw@48 1010 return checkObjectToString(self).toUpperCase();
jlaskey@3 1011 }
jlaskey@3 1012
jlaskey@3 1013 /**
jlaskey@3 1014 * ECMA 15.5.4.19 String.prototype.toLocaleUpperCase ( )
jlaskey@3 1015 * @param self self reference
jlaskey@3 1016 * @return string to locale sensitive upper case
jlaskey@3 1017 */
jlaskey@3 1018 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 1019 public static Object toLocaleUpperCase(final Object self) {
hannesw@48 1020 return checkObjectToString(self).toUpperCase(Global.getThisContext().getLocale());
jlaskey@3 1021 }
jlaskey@3 1022
jlaskey@3 1023 /**
jlaskey@3 1024 * ECMA 15.5.4.20 String.prototype.trim ( )
jlaskey@3 1025 * @param self self reference
jlaskey@3 1026 * @return string trimmed from whitespace
jlaskey@3 1027 */
jlaskey@3 1028 @Function(attributes = Attribute.NOT_ENUMERABLE)
jlaskey@3 1029 public static Object trim(final Object self) {
jlaskey@3 1030
hannesw@48 1031 final String str = checkObjectToString(self);
hannesw@48 1032 final int len = str.length();
jlaskey@3 1033 int start = 0;
hannesw@48 1034 int end = len - 1;
jlaskey@3 1035
sundar@82 1036 while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
jlaskey@3 1037 start++;
jlaskey@3 1038 }
sundar@82 1039 while (end > start && ScriptRuntime.isJSWhitespace(str.charAt(end))) {
jlaskey@3 1040 end--;
jlaskey@3 1041 }
jlaskey@3 1042
hannesw@48 1043 return start == 0 && end + 1 == len ? str : str.substring(start, end + 1);
jlaskey@3 1044 }
jlaskey@3 1045
jlaskey@3 1046 private static Object newObj(final Object self, final CharSequence str) {
jlaskey@3 1047 if (self instanceof ScriptObject) {
jlaskey@3 1048 return new NativeString(str, ((ScriptObject)self).getProto());
jlaskey@3 1049 }
jlaskey@3 1050 return new NativeString(str, Global.instance().getStringPrototype());
jlaskey@3 1051 }
jlaskey@3 1052
jlaskey@3 1053 /**
jlaskey@3 1054 * ECMA 15.5.2.1 new String ( [ value ] )
jlaskey@3 1055 *
jlaskey@3 1056 * Constructor
jlaskey@3 1057 *
jlaskey@3 1058 * @param newObj is this constructor invoked with the new operator
jlaskey@3 1059 * @param self self reference
jlaskey@3 1060 * @param args arguments (a value)
jlaskey@3 1061 *
jlaskey@3 1062 * @return new NativeString, empty string if no args, extraneous args ignored
jlaskey@3 1063 */
jlaskey@3 1064 @Constructor(arity = 1)
jlaskey@3 1065 public static Object constructor(final boolean newObj, final Object self, final Object... args) {
jlaskey@3 1066 final CharSequence str = (args.length > 0) ? JSType.toCharSequence(args[0]) : "";
jlaskey@3 1067 return newObj ? newObj(self, str) : str.toString();
jlaskey@3 1068 }
jlaskey@3 1069
jlaskey@3 1070 /**
jlaskey@3 1071 * ECMA 15.5.2.1 new String ( [ value ] ) - special version with no args
jlaskey@3 1072 *
jlaskey@3 1073 * Constructor
jlaskey@3 1074 *
jlaskey@3 1075 * @param newObj is this constructor invoked with the new operator
jlaskey@3 1076 * @param self self reference
jlaskey@3 1077 *
jlaskey@3 1078 * @return new NativeString ("")
jlaskey@3 1079 */
jlaskey@3 1080 @SpecializedConstructor
jlaskey@3 1081 public static Object constructor(final boolean newObj, final Object self) {
jlaskey@3 1082 return newObj ? newObj(self, "") : "";
jlaskey@3 1083 }
jlaskey@3 1084
hannesw@48 1085 /**
hannesw@48 1086 * ECMA 15.5.2.1 new String ( [ value ] ) - special version with one arg
hannesw@48 1087 *
hannesw@48 1088 * Constructor
hannesw@48 1089 *
hannesw@48 1090 * @param newObj is this constructor invoked with the new operator
hannesw@48 1091 * @param self self reference
hannesw@48 1092 * @param arg argument
hannesw@48 1093 *
hannesw@48 1094 * @return new NativeString (arg)
hannesw@48 1095 */
hannesw@48 1096 @SpecializedConstructor
hannesw@48 1097 public static Object constructor(final boolean newObj, final Object self, final Object arg) {
hannesw@59 1098 final CharSequence str = JSType.toCharSequence(arg);
hannesw@59 1099 return newObj ? newObj(self, str) : str.toString();
hannesw@48 1100 }
jlaskey@3 1101
jlaskey@3 1102 /**
jlaskey@3 1103 * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
jlaskey@3 1104 *
jlaskey@3 1105 * Constructor
jlaskey@3 1106 *
jlaskey@3 1107 * @param newObj is this constructor invoked with the new operator
jlaskey@3 1108 * @param self self reference
jlaskey@3 1109 * @param arg the arg
jlaskey@3 1110 *
jlaskey@3 1111 * @return new NativeString containing the string representation of the arg
jlaskey@3 1112 */
jlaskey@3 1113 @SpecializedConstructor
jlaskey@3 1114 public static Object constructor(final boolean newObj, final Object self, final int arg) {
hannesw@59 1115 final String str = JSType.toString(arg);
jlaskey@3 1116 return newObj ? newObj(self, str) : str;
jlaskey@3 1117 }
jlaskey@3 1118
jlaskey@3 1119 /**
jlaskey@3 1120 * Lookup the appropriate method for an invoke dynamic call.
jlaskey@3 1121 *
hannesw@51 1122 * @param request the link request
jlaskey@3 1123 * @param receiver receiver of call
jlaskey@3 1124 * @return Link to be invoked at call site.
jlaskey@3 1125 */
hannesw@51 1126 public static GuardedInvocation lookupPrimitive(final LinkRequest request, final Object receiver) {
jlaskey@3 1127 final MethodHandle guard = NashornGuards.getInstanceOf2Guard(String.class, ConsString.class);
hannesw@51 1128 return PrimitiveLookup.lookupPrimitive(request, guard, new NativeString((CharSequence)receiver), WRAPFILTER);
jlaskey@3 1129 }
jlaskey@3 1130
jlaskey@3 1131 @SuppressWarnings("unused")
jlaskey@3 1132 private static NativeString wrapFilter(final Object receiver) {
jlaskey@3 1133 return new NativeString((CharSequence)receiver);
jlaskey@3 1134 }
jlaskey@3 1135
jlaskey@3 1136 private static CharSequence getCharSequence(final Object self) {
jlaskey@3 1137 if (self instanceof String || self instanceof ConsString) {
jlaskey@3 1138 return (CharSequence)self;
jlaskey@3 1139 } else if (self instanceof NativeString) {
jlaskey@3 1140 return ((NativeString)self).getValue();
jlaskey@3 1141 } else if (self != null && self == Global.instance().getStringPrototype()) {
jlaskey@3 1142 return "";
jlaskey@3 1143 } else {
lagergren@112 1144 throw typeError("not.a.string", ScriptRuntime.safeToString(self));
jlaskey@3 1145 }
jlaskey@3 1146 }
jlaskey@3 1147
jlaskey@3 1148 private static String getString(final Object self) {
jlaskey@3 1149 if (self instanceof String) {
jlaskey@3 1150 return (String)self;
jlaskey@3 1151 } else if (self instanceof ConsString) {
jlaskey@3 1152 return self.toString();
jlaskey@3 1153 } else if (self instanceof NativeString) {
jlaskey@3 1154 return ((NativeString)self).getStringValue();
jlaskey@3 1155 } else if (self != null && self == Global.instance().getStringPrototype()) {
jlaskey@3 1156 return "";
jlaskey@3 1157 } else {
lagergren@112 1158 throw typeError( "not.a.string", ScriptRuntime.safeToString(self));
jlaskey@3 1159 }
jlaskey@3 1160 }
jlaskey@3 1161
hannesw@48 1162 /**
hannesw@48 1163 * Combines ECMA 9.10 CheckObjectCoercible and ECMA 9.8 ToString with a shortcut for strings.
hannesw@48 1164 *
hannesw@48 1165 * @param self the object
hannesw@48 1166 * @return the object as string
hannesw@48 1167 */
hannesw@48 1168 private static String checkObjectToString(final Object self) {
hannesw@48 1169 if (self instanceof String) {
hannesw@48 1170 return (String)self;
hannesw@48 1171 } else if (self instanceof ConsString) {
hannesw@48 1172 return self.toString();
hannesw@48 1173 } else {
hannesw@48 1174 Global.checkObjectCoercible(self);
hannesw@48 1175 return JSType.toString(self);
hannesw@48 1176 }
hannesw@48 1177 }
hannesw@48 1178
jlaskey@3 1179 private boolean isValid(final int key) {
jlaskey@3 1180 return key >= 0 && key < value.length();
jlaskey@3 1181 }
jlaskey@3 1182
jlaskey@3 1183 private static MethodHandle findWrapFilter() {
jlaskey@3 1184 try {
jlaskey@3 1185 return MethodHandles.lookup().findStatic(NativeString.class, "wrapFilter", MH.type(NativeString.class, Object.class));
jlaskey@3 1186 } catch (final NoSuchMethodException | IllegalAccessException e) {
sundar@37 1187 throw new MethodHandleFactory.LookupException(e);
jlaskey@3 1188 }
jlaskey@3 1189 }
jlaskey@3 1190 }

mercurial