/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.types.builtins; import java.util.List; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.internal.CompoundList; import com.github.anba.es6draft.runtime.internal.StringPropertyKeyList; import com.github.anba.es6draft.runtime.internal.Strings; import com.github.anba.es6draft.runtime.types.Intrinsics; import com.github.anba.es6draft.runtime.types.Property; import com.github.anba.es6draft.runtime.types.ScriptObject; /** * <h1>9 Ordinary and Exotic Objects Behaviours</h1><br> * <h2>9.4 Built-in Exotic Object Internal Methods and Data Fields</h2> * <ul> * <li>9.4.3 String Exotic Objects * </ul> */ public class StringObject extends OrdinaryObject { /** [[StringData]] */ private final CharSequence stringData; /** * Constructs a new String object. * * @param realm * the realm object * @param stringData * the string data */ public StringObject(Realm realm, CharSequence stringData) { super(realm); this.stringData = stringData; } /** * Constructs a new String object. * * @param realm * the realm object * @param stringData * the string data * @param prototype * the prototype object */ public StringObject(Realm realm, CharSequence stringData, ScriptObject prototype) { super(realm); // StringCreate - step 4 this.stringData = stringData; // StringCreate - step 9 setPrototype(prototype); // StringCreate - steps 11-13 infallibleDefineOwnProperty("length", new Property(stringData.length(), false, false, false)); } /** * [[StringData]] * * @return the string data */ public CharSequence getStringData() { return stringData; } @Override public String className() { return "String"; } @Override public boolean hasSpecialIndexedProperties() { return true; } /** * [[HasOwnProperty]] (P) */ @Override protected boolean hasOwnProperty(ExecutionContext cx, long propertyKey) { return propertyKey < getStringData().length() || super.hasOwnProperty(cx, propertyKey); } /** * 9.4.3.1 [[GetOwnProperty]] ( P ) */ @Override protected Property getProperty(ExecutionContext cx, long propertyKey) { /* step 1 (not applicable) */ /* step 2 */ Property desc = ordinaryGetOwnProperty(propertyKey); /* step 3 */ if (desc != null) { return desc; } /* step 4 */ return StringGetIndexProperty(this, propertyKey); } /** * 9.4.3.1.1 StringGetIndexProperty (S, P) * * @param s * the string object * @param propertyKey * the property key * @return the property descriptor or {@code null} */ private static Property StringGetIndexProperty(StringObject s, long propertyKey) { /* steps 1-6 (not applicable) */ assert propertyKey >= 0; /* step 7 */ CharSequence str = s.getStringData(); /* step 8 */ int len = str.length(); /* step 9 */ if (len <= propertyKey) { return null; } /* step 10 */ String resultStr = String.valueOf(str.charAt((int) propertyKey)); /* step 11 */ return new Property(resultStr, false, true, false); } /** * 9.4.3.2 [[HasProperty]](P) */ @Override protected boolean has(ExecutionContext cx, long propertyKey) { /* steps 1-3 */ return propertyKey < getStringData().length() || super.has(cx, propertyKey); } /** * 9.4.3.3 [[OwnPropertyKeys]] () */ @Override protected List<Object> getOwnPropertyKeys(ExecutionContext cx) { /* step 1 (moved) */ /* steps 2-4 */ StringPropertyKeyList stringIndices = new StringPropertyKeyList(getStringData().length()); /* steps 5-7 */ List<Object> ownPropertyKeys = super.getOwnPropertyKeys(cx); /* steps 1, 8 */ return new CompoundList<>(stringIndices, ownPropertyKeys); } @Override protected List<String> getEnumerableKeys(ExecutionContext cx) { StringPropertyKeyList stringIndices = new StringPropertyKeyList(getStringData().length()); return new CompoundList<>(stringIndices, super.getEnumerableKeys(cx)); } @Override protected Enumerability isEnumerableOwnProperty(String key) { int index = Strings.toStringIndex(key); if (0 <= index && index < getStringData().length()) { return Enumerability.Enumerable; } return super.isEnumerableOwnProperty(key); } /** * 9.4.3.4 StringCreate(value, prototype) * * @param cx * the execution context * @param stringData * the string value * @return the new string object */ public static StringObject StringCreate(ExecutionContext cx, CharSequence stringData) { /* steps 1-14 */ return new StringObject(cx.getRealm(), stringData, cx.getIntrinsic(Intrinsics.StringPrototype)); } /** * 9.4.3.4 StringCreate(value, prototype) * * @param cx * the execution context * @param stringData * the string value * @param prototype * the prototype object * @return the new string object */ public static StringObject StringCreate(ExecutionContext cx, CharSequence stringData, ScriptObject prototype) { /* steps 1-2 (not applicable) */ /* steps 3-14 */ return new StringObject(cx.getRealm(), stringData, prototype); } }