#include "Escargot.h" #include "GlobalObject.h" #include "Context.h" #include "StringObject.h" #include "ErrorObject.h" #include "RegExpObject.h" #include "ArrayObject.h" namespace Escargot { static Value builtinStringConstructor(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { if (isNewExpression) { Object* thisObject = thisValue.toObject(state); StringObject* stringObject = thisObject->asStringObject(); if (argc == 0) { stringObject->setPrimitiveValue(state, String::emptyString); } else { stringObject->setPrimitiveValue(state, argv[0].toString(state)); } return stringObject; } else { // called as function if (argc == 0) return String::emptyString; Value value = argv[0]; return value.toString(state); } } static Value builtinStringToString(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { if (thisValue.isObject() && thisValue.asObject()->isStringObject()) { return thisValue.asObject()->asStringObject()->primitiveValue(); } if (thisValue.isString()) return thisValue.toString(state); ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, state.context()->staticStrings().String.string(), true, state.context()->staticStrings().toString.string(), errorMessage_GlobalObject_ThisNotString); RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringIndexOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, indexOf); String* searchStr = argv[0].toString(state); Value val; if (argc > 1) { val = argv[1]; } size_t pos; if (val.isUndefined()) { pos = 0; } else { pos = val.toInteger(state); } size_t len = str->length(); size_t start = std::min(std::max(pos, (size_t)0), len); size_t result = str->find(searchStr, start); if (result == SIZE_MAX) return Value(-1); else return Value(result); } static Value builtinStringLastIndexOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { // Let S be ToString(O). RESOLVE_THIS_BINDING_TO_STRING(S, String, indexOf); String* searchStr = argv[0].toString(state); double numPos; if (argc > 0) { numPos = argv[1].toNumber(state); } else { numPos = Value().toNumber(state); } double pos; // If numPos is NaN, let pos be +∞; otherwise, let pos be ToInteger(numPos). if (std::isnan(numPos)) pos = std::numeric_limits::infinity(); else pos = numPos; double len = S->length(); double start = std::min(std::max(pos, 0.0), len); size_t result = S->rfind(searchStr, start); if (result == SIZE_MAX) { return Value(-1); } return Value(result); } static Value builtinStringLocaleCompare(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { state.throwException(new ASCIIString(errorMessage_NotImplemented)); RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringSubstring(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, indexOf); if (argc == 0) { return str; } else { int len = str->length(); double doubleStart = argv[0].toNumber(state); Value end = argv[1]; double doubleEnd = (argc < 2 || end.isUndefined()) ? len : end.toNumber(state); doubleStart = (std::isnan(doubleStart)) ? 0 : doubleStart; doubleEnd = (std::isnan(doubleEnd)) ? 0 : doubleEnd; double finalStart = (int)trunc(std::min(std::max(doubleStart, 0.0), (double)len)); double finalEnd = (int)trunc(std::min(std::max(doubleEnd, 0.0), (double)len)); size_t from = std::min(finalStart, finalEnd); size_t to = std::max(finalStart, finalEnd); ASSERT(from <= to); if (to - from == 1) { char16_t c = str->charAt(from); if (c < ESCARGOT_ASCII_TABLE_MAX) { return state.context()->staticStrings().asciiTable[c].string(); } } return str->subString(from, to); } } static Value builtinStringMatch(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, match); Value argument = argv[0]; RegExpObject* regexp; if (argument.isPointerValue() && argument.asPointerValue()->isRegExpObject()) { regexp = argument.asPointerValue()->asRegExpObject(); } else { regexp = new RegExpObject(state, argument.toString(state), String::emptyString); } (void)regexp->lastIndex().toInteger(state); bool isGlobal = regexp->option() & RegExpObject::Option::Global; if (isGlobal) { regexp->setLastIndex(Value(0)); } RegexMatchResult result; bool testResult = regexp->matchNonGlobally(state, str, result, false, 0); if (!testResult) { regexp->setLastIndex(Value(0)); return Value(Value::Null); } // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/match // if global flag is on, match method returns an Array containing all matched substrings if (isGlobal) { return regexp->createMatchedArray(state, str, result); } else { return regexp->createRegExpMatchedArray(state, result, str); } } static Value builtinStringReplace(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(string, String, replace); Value searchValue = argv[0]; Value replaceValue = argv[1]; String* replaceString = nullptr; bool replaceValueIsFunction = replaceValue.isFunction(); if (!replaceValueIsFunction) replaceString = replaceValue.toString(state); RegexMatchResult result; if (searchValue.isPointerValue() && searchValue.asPointerValue()->isRegExpObject()) { RegExpObject* regexp = searchValue.asPointerValue()->asRegExpObject(); bool isGlobal = regexp->option() & RegExpObject::Option::Global; if (isGlobal) { regexp->setLastIndex(Value(0)); } bool testResult = regexp->matchNonGlobally(state, string, result, false, 0); if (testResult) { if (isGlobal) { regexp->createRegexMatchResult(state, string, result); } } else { regexp->setLastIndex(Value(0)); } } else { String* searchString = searchValue.toString(state); size_t idx = string->find(searchString); if (idx != (size_t)-1) { Vector> piece; RegexMatchResult::RegexMatchResultPiece p; p.m_start = idx; p.m_end = idx + searchString->length(); piece.push_back(std::move(p)); result.m_matchResults.push_back(std::move(piece)); } } if (result.m_matchResults.size() == 0) { return string; } if (replaceValueIsFunction) { uint32_t matchCount = result.m_matchResults.size(); Value callee = replaceValue; StringBuilder builer; builer.appendSubString(string, 0, result.m_matchResults[0][0].m_start); for (uint32_t i = 0; i < matchCount; i++) { int subLen = result.m_matchResults[i].size(); Value* arguments; // #define ALLOCA(bytes, typenameWithoutPointer, ec) (typenameWithoutPointer*)alloca(bytes) arguments = ALLOCA(sizeof(Value) * (subLen + 2), Value, state); for (unsigned j = 0; j < (unsigned)subLen; j++) { if (result.m_matchResults[i][j].m_start == std::numeric_limits::max()) arguments[j] = Value(); else { StringBuilder argStrBuilder; argStrBuilder.appendSubString(string, result.m_matchResults[i][j].m_start, result.m_matchResults[i][j].m_end); arguments[j] = argStrBuilder.finalize(); } } arguments[subLen] = Value((int)result.m_matchResults[i][0].m_start); arguments[subLen + 1] = string; // 21.1.3.14 (11) it should be called with this as undefined String* res = FunctionObject::call(callee, state, Value(), subLen + 2, arguments).toString(state); builer.appendSubString(res, 0, res->length()); if (i < matchCount - 1) { builer.appendSubString(string, result.m_matchResults[i][0].m_end, result.m_matchResults[i + 1][0].m_start); } } builer.appendSubString(string, result.m_matchResults[matchCount - 1][0].m_end, string->length()); return builer.finalize(); } else { ASSERT(replaceString); bool hasDollar = false; for (size_t i = 0; i < replaceString->length(); i++) { if (replaceString->charAt(i) == '$') { hasDollar = true; break; } } StringBuilder builder; if (!hasDollar) { // flat replace int32_t matchCount = result.m_matchResults.size(); builder.appendSubString(string, 0, result.m_matchResults[0][0].m_start); for (int32_t i = 0; i < matchCount; i++) { String* res = replaceString; builder.appendString(res); if (i < matchCount - 1) { builder.appendSubString(string, result.m_matchResults[i][0].m_end, result.m_matchResults[i + 1][0].m_start); } } builder.appendSubString(string, result.m_matchResults[matchCount - 1][0].m_end, string->length()); } else { // dollar replace int32_t matchCount = result.m_matchResults.size(); builder.appendSubString(string, 0, result.m_matchResults[0][0].m_start); for (int32_t i = 0; i < matchCount; i++) { for (unsigned j = 0; j < replaceString->length(); j++) { if (replaceString->charAt(j) == '$' && (j + 1) < replaceString->length()) { char16_t c = replaceString->charAt(j + 1); if (c == '$') { builder.appendChar(replaceString->charAt(j)); } else if (c == '&') { builder.appendSubString(string, result.m_matchResults[i][0].m_start, result.m_matchResults[i][0].m_end); } else if (c == '\'') { builder.appendSubString(string, result.m_matchResults[i][0].m_end, string->length()); } else if (c == '`') { builder.appendSubString(string, 0, result.m_matchResults[i][0].m_start); } else if ('0' <= c && c <= '9') { size_t idx = c - '0'; int peek = replaceString->charAt(j + 2) - '0'; bool usePeek = false; if (0 <= peek && peek <= 9) { idx *= 10; idx += peek; usePeek = true; } if (idx < result.m_matchResults[i].size() && idx != 0) { builder.appendSubString(string, result.m_matchResults[i][idx].m_start, result.m_matchResults[i][idx].m_end); if (usePeek) j++; } else { idx = c - '0'; if (idx < result.m_matchResults[i].size() && idx != 0) { builder.appendSubString(string, result.m_matchResults[i][idx].m_start, result.m_matchResults[i][idx].m_end); } else { builder.appendChar('$'); builder.appendChar(c); } } } else { builder.appendChar('$'); builder.appendChar(c); } j++; } else { builder.appendChar(replaceString->charAt(j)); } } if (i < matchCount - 1) { builder.appendSubString(string, result.m_matchResults[i][0].m_end, result.m_matchResults[i + 1][0].m_start); } } builder.appendSubString(string, result.m_matchResults[matchCount - 1][0].m_end, string->length()); } return builder.finalize(); } RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringSearch(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { state.throwException(new ASCIIString(errorMessage_NotImplemented)); RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringSplit(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { // 1, 2, 3 RESOLVE_THIS_BINDING_TO_STRING(S, String, split); ArrayObject* A = new ArrayObject(state); // 4, 5 size_t lengthA = 0; size_t lim; if (argv[1].isUndefined()) { lim = Value::InvalidIndexValue - 1; } else { lim = argv[1].toUint32(state); } // 6, 7 size_t s = S->length(), p = 0; // 8 Value separator = argv[0]; PointerValue* P; if (separator.isPointerValue() && separator.asPointerValue()->isRegExpObject()) { P = separator.asPointerValue()->asRegExpObject(); } else { P = separator.toString(state); } // 9 if (lim == 0) return A; // 10 if (separator.isUndefined()) { A->defineOwnProperty(state, ObjectPropertyName(state, Value(0)), ObjectPropertyDescriptor(S, ObjectPropertyDescriptor::AllPresent)); return A; } std::function splitMatchUsingStr; splitMatchUsingStr = [](String* S, int q, String* R) -> Value { int s = S->length(); int r = R->length(); if (q + r > s) return Value(false); for (int i = 0; i < r; i++) if (S->charAt(q + i) != R->charAt(i)) return Value(false); return Value(q + r); }; // 11 if (s == 0) { bool ret = true; if (P->isRegExpObject()) { RegexMatchResult result; ret = P->asRegExpObject()->matchNonGlobally(state, S, result, false, 0); } else { Value z = splitMatchUsingStr(S, 0, P->asString()); if (z.isBoolean()) { ret = z.asBoolean(); } } if (ret) return A; A->defineOwnProperty(state, ObjectPropertyName(state, Value(0)), ObjectPropertyDescriptor(S, ObjectPropertyDescriptor::AllPresent)); return A; } // 12 size_t q = p; // 13 if (P->isRegExpObject()) { RegExpObject* R = P->asRegExpObject(); while (q != s) { RegexMatchResult result; bool ret = R->matchNonGlobally(state, S, result, false, (size_t)q); if (!ret) { break; } if ((size_t)result.m_matchResults[0][0].m_end == p) { q++; } else { if (result.m_matchResults[0][0].m_start >= S->length()) break; String* T = S->subString(p, result.m_matchResults[0][0].m_start); A->defineOwnProperty(state, ObjectPropertyName(state, Value(lengthA++)), ObjectPropertyDescriptor(T, ObjectPropertyDescriptor::AllPresent)); if (lengthA == lim) return A; p = result.m_matchResults[0][0].m_end; R->pushBackToRegExpMatchedArray(state, A, lengthA, lim, result, S); if (lengthA == lim) return A; q = p; } } } else { String* R = P->asString(); while (q != s) { Value e = splitMatchUsingStr(S, q, R); if (e == Value(false)) q++; else { if ((size_t)e.asInt32() == p) q++; else { if (q >= S->length()) break; String* T = S->subString(p, q); A->defineOwnProperty(state, ObjectPropertyName(state, Value(lengthA++)), ObjectPropertyDescriptor(T, ObjectPropertyDescriptor::AllPresent)); if (lengthA == lim) return A; p = e.asInt32(); q = p; } } } } // 14, 15, 16 String* T = S->subString(p, s); A->defineOwnProperty(state, ObjectPropertyName(state, Value(lengthA)), ObjectPropertyDescriptor(T, ObjectPropertyDescriptor::AllPresent)); return A; } static Value builtinStringCharCodeAt(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, indexOf); int position = argv[0].toInteger(state); Value ret; if (position < 0 || position >= (int)str->length()) ret = Value(std::numeric_limits::quiet_NaN()); else ret = Value(str->charAt(position)); return ret; } static Value builtinStringCharAt(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, charAt); int64_t position; if (argc == 0) { position = 0; } else if (argc > 0) { position = argv[0].toInteger(state); } else { return Value(String::emptyString); } if (LIKELY(0 <= position && position < (int64_t)str->length())) { char16_t c = str->charAt(position); if (LIKELY(c < ESCARGOT_ASCII_TABLE_MAX)) { return state.context()->staticStrings().asciiTable[c].string(); } else { return String::fromCharCode(c); } } else { return String::emptyString; } } static Value builtinStringFromCharCode(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { if (argc == 1) { char16_t c = argv[0].toUint32(state) & 0xFFFF; if (c < ESCARGOT_ASCII_TABLE_MAX) return state.context()->staticStrings().asciiTable[c].string(); return String::fromCharCode(c); } else { StringBuilder builder; for (size_t i = 0; i < argc; i++) { builder.appendChar((char16_t)argv[i].toInteger(state)); } return builder.finalize(); } return Value(); } static Value builtinStringConcat(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, concat); for (size_t i = 0; i < argc; i++) { String* appendStr = argv[i].toString(state); str = RopeString::createRopeString(str, appendStr); } return Value(str); } static Value builtinStringSlice(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, slice); size_t len = str->length(); double start = argv[0].toInteger(state); double end = (argv[1].isUndefined()) ? len : argv[1].toInteger(state); int from = (start < 0) ? std::max(len + start, 0.0) : std::min(start, (double)len); int to = (end < 0) ? std::max(len + end, 0.0) : std::min(end, (double)len); int span = std::max(to - from, 0); return str->subString(from, from + span); } static Value builtinStringToLowerCase(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, toLowerCase); if (str->hasASCIIContent()) { ASCIIStringData newStr; size_t len = str->length(); newStr.resizeWithUninitializedValues(len); const char* buf = str->characters8(); for (size_t i = 0; i < str->length(); i++) { newStr[i] = u_tolower(buf[i]); } return new ASCIIString(std::move(newStr)); } else { size_t len = str->length(); UTF16StringData newStr(str->characters16(), len); char16_t* buf = newStr.data(); for (size_t i = 0; i < len;) { char32_t c; size_t iBefore = i; U16_NEXT(buf, i, len, c); c = u_tolower(c); if (c <= 0x10000) { char16_t c2 = (char16_t)c; buf[iBefore] = c2; } else { buf[iBefore] = (char16_t)(0xD800 + ((c - 0x10000) >> 10)); buf[iBefore + 1] = (char16_t)(0xDC00 + ((c - 0x10000) & 1023)); } } return new UTF16String(std::move(newStr)); } } static Value builtinStringToUpperCase(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { RESOLVE_THIS_BINDING_TO_STRING(str, String, toUpperCase); if (str->hasASCIIContent()) { ASCIIStringData newStr; size_t len = str->length(); newStr.resizeWithUninitializedValues(len); const char* buf = str->characters8(); for (size_t i = 0; i < str->length(); i++) { newStr[i] = u_toupper(buf[i]); } return new ASCIIString(std::move(newStr)); } else { size_t len = str->length(); UTF16StringData newStr(str->characters16(), len); char16_t* buf = newStr.data(); for (size_t i = 0; i < len;) { char32_t c; size_t iBefore = i; U16_NEXT(buf, i, len, c); c = u_toupper(c); if (c <= 0x10000) { char16_t c2 = (char16_t)c; buf[iBefore] = c2; } else { buf[iBefore] = (char16_t)(0xD800 + ((c - 0x10000) >> 10)); buf[iBefore + 1] = (char16_t)(0xDC00 + ((c - 0x10000) & 1023)); } } return new UTF16String(std::move(newStr)); } } static Value builtinStringToLocaleLowerCase(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { state.throwException(new ASCIIString(errorMessage_NotImplemented)); RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringToLocaleUpperCase(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { state.throwException(new ASCIIString(errorMessage_NotImplemented)); RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringTrim(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { state.throwException(new ASCIIString(errorMessage_NotImplemented)); RELEASE_ASSERT_NOT_REACHED(); } static Value builtinStringValueOf(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { if (thisValue.isString()) { return Value(thisValue); } else if (thisValue.isObject() && thisValue.asObject()->isStringObject()) { return Value(thisValue.asPointerValue()->asStringObject()->primitiveValue()); } ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_GlobalObject_ThisNotString); RELEASE_ASSERT_NOT_REACHED(); } void GlobalObject::installString(ExecutionState& state) { const StaticStrings* strings = &state.context()->staticStrings(); m_string = new FunctionObject(state, NativeFunctionInfo(strings->String, builtinStringConstructor, 1, [](ExecutionState& state, size_t argc, Value* argv) -> Object* { return new StringObject(state); }), FunctionObject::__ForBuiltin__); m_string->markThisObjectDontNeedStructureTransitionTable(state); m_string->setPrototype(state, m_functionPrototype); m_stringPrototype = m_objectPrototype; m_stringPrototype = new StringObject(state, String::emptyString); m_stringPrototype->setPrototype(state, m_objectPrototype); m_string->setFunctionPrototype(state, m_stringPrototype); m_stringPrototype->defineOwnProperty(state, ObjectPropertyName(strings->constructor), ObjectPropertyDescriptor(m_string, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->toString), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->toString, builtinStringToString, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); // $21.1.3.4 String.prototype.concat m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->concat), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->concat, builtinStringConcat, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); // $21.1.3.8 String.prototype.indexOf m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->indexOf), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->indexOf, builtinStringIndexOf, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->lastIndexOf), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->lastIndexOf, builtinStringLastIndexOf, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->localeCompare), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->localeCompare, builtinStringLocaleCompare, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); // $21.1.3.16 String.prototype.slice m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->slice), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->slice, builtinStringSlice, 2, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); // $21.1.3.19 String.prototype.substring m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->substring), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->indexOf, builtinStringSubstring, 2, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->match), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->match, builtinStringMatch, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->replace), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->replace, builtinStringReplace, 2, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->search), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->search, builtinStringSearch, 2, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->split), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->split, builtinStringSplit, 2, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->charCodeAt), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->charCodeAt, builtinStringCharCodeAt, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->charAt), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->charAt, builtinStringCharAt, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->toLowerCase), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->toLowerCase, builtinStringToLowerCase, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->toUpperCase), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->toUpperCase, builtinStringToUpperCase, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->toLocaleLowerCase), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->toLocaleLowerCase, builtinStringToLocaleLowerCase, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->toLocaleUpperCase), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->toLocaleUpperCase, builtinStringToLocaleUpperCase, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->trim), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->trim, builtinStringTrim, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); // $21.1.3.26 String.prototype.valueOf m_stringPrototype->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->valueOf), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->valueOf, builtinStringValueOf, 0, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_string->defineOwnPropertyThrowsException(state, ObjectPropertyName(strings->fromCharCode), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(strings->fromCharCode, builtinStringFromCharCode, 1, nullptr, NativeFunctionInfo::Strict)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); m_string->setFunctionPrototype(state, m_stringPrototype); defineOwnProperty(state, ObjectPropertyName(strings->String), ObjectPropertyDescriptor(m_string, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); } }