/**
* 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.objects.text;
import static com.github.anba.es6draft.runtime.AbstractOperations.*;
import static com.github.anba.es6draft.runtime.internal.Errors.newRangeError;
import static com.github.anba.es6draft.runtime.internal.Properties.createProperties;
import static com.github.anba.es6draft.runtime.objects.SymbolPrototype.SymbolDescriptiveString;
import static com.github.anba.es6draft.runtime.types.builtins.StringObject.StringCreate;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.Initializable;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.internal.Properties.Attributes;
import com.github.anba.es6draft.runtime.internal.Properties.Function;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.Properties.Value;
import com.github.anba.es6draft.runtime.internal.Strings;
import com.github.anba.es6draft.runtime.types.Constructor;
import com.github.anba.es6draft.runtime.types.Intrinsics;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.Type;
import com.github.anba.es6draft.runtime.types.builtins.BuiltinConstructor;
import com.github.anba.es6draft.runtime.types.builtins.StringObject;
/**
* <h1>21 Text Processing</h1><br>
* <h2>21.1 String Objects</h2>
* <ul>
* <li>21.1.1 The String Constructor
* <li>21.1.2 Properties of the String Constructor
* </ul>
*/
public final class StringConstructor extends BuiltinConstructor implements Initializable {
/**
* Constructs a new String constructor function.
*
* @param realm
* the realm object
*/
public StringConstructor(Realm realm) {
super(realm, "String", 1);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
}
@Override
public StringConstructor clone() {
return new StringConstructor(getRealm());
}
/**
* 21.1.1.1 String ( value )
*/
@Override
public CharSequence call(ExecutionContext callerContext, Object thisValue, Object... args) {
ExecutionContext calleeContext = calleeContext();
/* step 1 */
if (args.length == 0) {
return "";
}
/* steps 2-3 */
Object value = args[0];
if (Type.isSymbol(value)) {
return SymbolDescriptiveString(Type.symbolValue(value));
}
/* steps 4-5 */
return ToString(calleeContext, value);
}
/**
* 21.1.1.1 String ( value )
*/
@Override
public StringObject construct(ExecutionContext callerContext, Constructor newTarget,
Object... args) {
ExecutionContext calleeContext = calleeContext();
/* steps 1-3 */
CharSequence s = args.length == 0 ? "" : ToString(calleeContext, args[0]);
/* step 4 (not applicable) */
/* step 5 */
return StringCreate(calleeContext, s,
GetPrototypeFromConstructor(calleeContext, newTarget, Intrinsics.StringPrototype));
}
/**
* 21.1.2 Properties of the String Constructor
*/
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.FunctionPrototype;
@Value(name = "length", attributes = @Attributes(writable = false, enumerable = false,
configurable = true))
public static final int length = 1;
@Value(name = "name", attributes = @Attributes(writable = false, enumerable = false,
configurable = true))
public static final String name = "String";
/**
* 21.1.2.3 String.prototype
*/
@Value(name = "prototype", attributes = @Attributes(writable = false, enumerable = false,
configurable = false))
public static final Intrinsics prototype = Intrinsics.StringPrototype;
/**
* 21.1.2.1 String.fromCharCode ( ...codeUnits)
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param codeUnits
* the unicode character units
* @return the result string
*/
@Function(name = "fromCharCode", arity = 1)
public static Object fromCharCode(ExecutionContext cx, Object thisValue,
Object... codeUnits) {
/* steps 1-2 */
int length = codeUnits.length;
// Optimize:
if (length == 1) {
return String.valueOf((char) ToUint16(cx, codeUnits[0]));
}
/* step 3 */
char elements[] = new char[length];
/* steps 4-5 */
for (int nextIndex = 0; nextIndex < length; ++nextIndex) {
/* steps 5.a-c */
char nextCU = ToUint16(cx, codeUnits[nextIndex]);
/* steps 5.d-e */
elements[nextIndex] = nextCU;
}
/* step 6 */
return new String(elements);
}
/**
* 21.1.2.2 String.fromCodePoint ( ...codePoints)
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param codePoints
* the unicode code points
* @return the result string
*/
@Function(name = "fromCodePoint", arity = 1)
public static Object fromCodePoint(ExecutionContext cx, Object thisValue,
Object... codePoints) {
/* steps 1-2 */
int length = codePoints.length;
// Optimize:
if (length == 1) {
/* steps 5.a-c */
double nextCP = ToNumber(cx, codePoints[0]);
int cp = (int) nextCP;
/* steps 5.d-e */
if (cp < 0 || cp > 0x10FFFF || nextCP != (double) cp) {
throw newRangeError(cx, Messages.Key.InvalidCodePoint);
}
/* steps 5.f, 6 */
return Strings.fromCodePoint(cp);
}
/* step 3 */
int elements[] = new int[length];
/* steps 4-5 */
for (int nextIndex = 0; nextIndex < length; ++nextIndex) {
/* steps 5.a-c */
double nextCP = ToNumber(cx, codePoints[nextIndex]);
int cp = (int) nextCP;
/* steps 5.d-e */
if (cp < 0 || cp > 0x10FFFF || nextCP != (double) cp) {
throw newRangeError(cx, Messages.Key.InvalidCodePoint);
}
/* step 5.f */
elements[nextIndex] = cp;
}
/* step 6 */
return new String(elements, 0, length);
}
/**
* 21.1.2.4 String.raw ( template , ...substitutions )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param template
* the call site object
* @param substitutions
* the string substitutions
* @return the interpolated string
*/
@Function(name = "raw", arity = 1)
public static Object raw(ExecutionContext cx, Object thisValue, Object template,
Object... substitutions) {
/* step 1 (not applicable) */
/* step 2 */
long numberOfSubstitutions = substitutions.length;
/* steps 3-4 */
ScriptObject cooked = ToObject(cx, template);
/* steps 5-6 */
ScriptObject raw = ToObject(cx, Get(cx, cooked, "raw"));
/* steps 7-8 */
long literalSegments = ToLength(cx, Get(cx, raw, "length"));
/* step 9 */
if (literalSegments <= 0) {
return "";
}
/* step 10 */
StringBuilder stringElements = new StringBuilder();
/* steps 11-12 */
for (long nextIndex = 0;; ++nextIndex) {
/* steps 12.a-c */
CharSequence nextSeg = ToString(cx, Get(cx, raw, nextIndex));
/* step 12.d */
stringElements.append(nextSeg);
/* step 12.e */
if (nextIndex + 1 == literalSegments) {
return stringElements.toString();
}
/* steps 12.f-j */
if (nextIndex < numberOfSubstitutions) {
CharSequence nextSub = ToString(cx, substitutions[(int) nextIndex]);
stringElements.append(nextSub);
}
}
}
}
}