123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668 |
- /*
- * Copyright (c) 2020-2021, Andreas Kling <andreas@ladybird.org>
- * Copyright (c) 2020-2023, Linus Groh <linusg@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #include <AK/Checked.h>
- #include <AK/Function.h>
- #include <AK/StringBuilder.h>
- #include <AK/Utf16View.h>
- #include <LibGC/Heap.h>
- #include <LibJS/Runtime/AbstractOperations.h>
- #include <LibJS/Runtime/Array.h>
- #include <LibJS/Runtime/Completion.h>
- #include <LibJS/Runtime/Error.h>
- #include <LibJS/Runtime/GlobalObject.h>
- #include <LibJS/Runtime/Intl/AbstractOperations.h>
- #include <LibJS/Runtime/Intl/Collator.h>
- #include <LibJS/Runtime/Intl/CollatorCompareFunction.h>
- #include <LibJS/Runtime/Intl/CollatorConstructor.h>
- #include <LibJS/Runtime/PrimitiveString.h>
- #include <LibJS/Runtime/RegExpObject.h>
- #include <LibJS/Runtime/StringIterator.h>
- #include <LibJS/Runtime/StringObject.h>
- #include <LibJS/Runtime/StringPrototype.h>
- #include <LibJS/Runtime/Utf16String.h>
- #include <LibJS/Runtime/Value.h>
- #include <LibJS/Runtime/ValueInlines.h>
- #include <LibUnicode/CharacterTypes.h>
- #include <LibUnicode/Locale.h>
- #include <LibUnicode/Normalize.h>
- #include <string.h>
- namespace JS {
- GC_DEFINE_ALLOCATOR(StringPrototype);
- static ThrowCompletionOr<String> utf8_string_from(VM& vm)
- {
- auto this_value = TRY(require_object_coercible(vm, vm.this_value()));
- return TRY(this_value.to_string(vm));
- }
- static ThrowCompletionOr<Utf16String> utf16_string_from(VM& vm)
- {
- auto this_value = TRY(require_object_coercible(vm, vm.this_value()));
- return TRY(this_value.to_utf16_string(vm));
- }
- // 22.1.3.21.1 SplitMatch ( S, q, R ), https://tc39.es/ecma262/#sec-splitmatch
- // FIXME: This no longer exists in the spec!
- static Optional<size_t> split_match(Utf16View const& haystack, size_t start, Utf16View const& needle)
- {
- auto r = needle.length_in_code_units();
- auto s = haystack.length_in_code_units();
- if (start + r > s)
- return {};
- for (size_t i = 0; i < r; ++i) {
- if (haystack.code_unit_at(start + i) != needle.code_unit_at(i))
- return {};
- }
- return start + r;
- }
- // 6.1.4.1 StringIndexOf ( string, searchValue, fromIndex ), https://tc39.es/ecma262/#sec-stringindexof
- Optional<size_t> string_index_of(Utf16View const& string, Utf16View const& search_value, size_t from_index)
- {
- // 1. Let len be the length of string.
- size_t string_length = string.length_in_code_units();
- // 3. Let searchLen be the length of searchValue.
- size_t search_length = search_value.length_in_code_units();
- // 2. If searchValue is the empty String and fromIndex ≤ len, return fromIndex.
- if ((search_length == 0) && (from_index <= string_length))
- return from_index;
- // OPTIMIZATION: If the needle is longer than the haystack, don't bother searching :^)
- if (search_length > string_length)
- return {};
- // 4. For each integer i such that fromIndex ≤ i ≤ len - searchLen, in ascending order, do
- for (size_t i = from_index; i <= string_length - search_length; ++i) {
- // a. Let candidate be the substring of string from i to i + searchLen.
- auto candidate = string.substring_view(i, search_length);
- // b. If candidate is searchValue, return i.
- if (candidate == search_value)
- return i;
- }
- // 5. Return -1.
- return {};
- }
- // 7.2.9 Static Semantics: IsStringWellFormedUnicode ( string )
- static bool is_string_well_formed_unicode(Utf16View string)
- {
- // OPTIMIZATION: simdutf can do this much faster.
- return string.validate();
- }
- // 11.1.4 CodePointAt ( string, position ), https://tc39.es/ecma262/#sec-codepointat
- CodePoint code_point_at(Utf16View const& string, size_t position)
- {
- // 1. Let size be the length of string.
- // 2. Assert: position ≥ 0 and position < size.
- VERIFY(position < string.length_in_code_units());
- // 3. Let first be the code unit at index position within string.
- auto first = string.code_unit_at(position);
- // 4. Let cp be the code point whose numeric value is that of first.
- auto code_point = static_cast<u32>(first);
- // 5. If first is not a leading surrogate or trailing surrogate, then
- if (!is_unicode_surrogate(first)) {
- // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }.
- return { false, code_point, 1 };
- }
- // 6. If first is a trailing surrogate or position + 1 = size, then
- if (Utf16View::is_low_surrogate(first) || (position + 1 == string.length_in_code_units())) {
- // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.
- return { true, code_point, 1 };
- }
- // 7. Let second be the code unit at index position + 1 within string.
- auto second = string.code_unit_at(position + 1);
- // 8. If second is not a trailing surrogate, then
- if (!Utf16View::is_low_surrogate(second)) {
- // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.
- return { true, code_point, 1 };
- }
- // 9. Set cp to UTF16SurrogatePairToCodePoint(first, second).
- code_point = Utf16View::decode_surrogate_pair(first, second);
- // 10. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }.
- return { false, code_point, 2 };
- }
- StringPrototype::StringPrototype(Realm& realm)
- : StringObject(*PrimitiveString::create(realm.vm(), String {}), realm.intrinsics().object_prototype())
- {
- }
- void StringPrototype::initialize(Realm& realm)
- {
- auto& vm = this->vm();
- Base::initialize(realm);
- u8 attr = Attribute::Writable | Attribute::Configurable;
- // 22.1.3 Properties of the String Prototype Object, https://tc39.es/ecma262/#sec-properties-of-the-string-prototype-object
- define_native_function(realm, vm.names.at, at, 1, attr);
- define_native_function(realm, vm.names.charAt, char_at, 1, attr);
- define_native_function(realm, vm.names.charCodeAt, char_code_at, 1, attr);
- define_native_function(realm, vm.names.codePointAt, code_point_at, 1, attr);
- define_native_function(realm, vm.names.concat, concat, 1, attr);
- define_native_function(realm, vm.names.endsWith, ends_with, 1, attr);
- define_native_function(realm, vm.names.includes, includes, 1, attr);
- define_native_function(realm, vm.names.indexOf, index_of, 1, attr);
- define_native_function(realm, vm.names.isWellFormed, is_well_formed, 0, attr);
- define_native_function(realm, vm.names.lastIndexOf, last_index_of, 1, attr);
- define_native_function(realm, vm.names.localeCompare, locale_compare, 1, attr);
- define_native_function(realm, vm.names.match, match, 1, attr);
- define_native_function(realm, vm.names.matchAll, match_all, 1, attr);
- define_native_function(realm, vm.names.normalize, normalize, 0, attr);
- define_native_function(realm, vm.names.padEnd, pad_end, 1, attr);
- define_native_function(realm, vm.names.padStart, pad_start, 1, attr);
- define_native_function(realm, vm.names.repeat, repeat, 1, attr);
- define_native_function(realm, vm.names.replace, replace, 2, attr);
- define_native_function(realm, vm.names.replaceAll, replace_all, 2, attr);
- define_native_function(realm, vm.names.search, search, 1, attr);
- define_native_function(realm, vm.names.slice, slice, 2, attr);
- define_native_function(realm, vm.names.split, split, 2, attr);
- define_native_function(realm, vm.names.startsWith, starts_with, 1, attr);
- define_native_function(realm, vm.names.substring, substring, 2, attr);
- define_native_function(realm, vm.names.toLocaleLowerCase, to_locale_lowercase, 0, attr);
- define_native_function(realm, vm.names.toLocaleUpperCase, to_locale_uppercase, 0, attr);
- define_native_function(realm, vm.names.toLowerCase, to_lowercase, 0, attr);
- define_native_function(realm, vm.names.toString, to_string, 0, attr);
- define_native_function(realm, vm.names.toUpperCase, to_uppercase, 0, attr);
- define_native_function(realm, vm.names.toWellFormed, to_well_formed, 0, attr);
- define_native_function(realm, vm.names.trim, trim, 0, attr);
- define_native_function(realm, vm.names.trimEnd, trim_end, 0, attr);
- define_native_function(realm, vm.names.trimStart, trim_start, 0, attr);
- define_native_function(realm, vm.names.valueOf, value_of, 0, attr);
- define_native_function(realm, vm.well_known_symbol_iterator(), symbol_iterator, 0, attr);
- // B.2.2 Additional Properties of the String.prototype Object, https://tc39.es/ecma262/#sec-additional-properties-of-the-string.prototype-object
- define_native_function(realm, vm.names.substr, substr, 2, attr);
- define_native_function(realm, vm.names.anchor, anchor, 1, attr);
- define_native_function(realm, vm.names.big, big, 0, attr);
- define_native_function(realm, vm.names.blink, blink, 0, attr);
- define_native_function(realm, vm.names.bold, bold, 0, attr);
- define_native_function(realm, vm.names.fixed, fixed, 0, attr);
- define_native_function(realm, vm.names.fontcolor, fontcolor, 1, attr);
- define_native_function(realm, vm.names.fontsize, fontsize, 1, attr);
- define_native_function(realm, vm.names.italics, italics, 0, attr);
- define_native_function(realm, vm.names.link, link, 1, attr);
- define_native_function(realm, vm.names.small, small, 0, attr);
- define_native_function(realm, vm.names.strike, strike, 0, attr);
- define_native_function(realm, vm.names.sub, sub, 0, attr);
- define_native_function(realm, vm.names.sup, sup, 0, attr);
- define_direct_property(vm.names.trimLeft, get_without_side_effects(vm.names.trimStart), attr);
- define_direct_property(vm.names.trimRight, get_without_side_effects(vm.names.trimEnd), attr);
- }
- // thisStringValue ( value ), https://tc39.es/ecma262/#thisstringvalue
- static ThrowCompletionOr<GC::Ref<PrimitiveString>> this_string_value(VM& vm, Value value)
- {
- // 1. If value is a String, return value.
- if (value.is_string())
- return value.as_string();
- // 2. If value is an Object and value has a [[StringData]] internal slot, then
- if (value.is_object() && is<StringObject>(value.as_object())) {
- // a. Let s be value.[[StringData]].
- // b. Assert: s is a String.
- // c. Return s.
- return static_cast<StringObject&>(value.as_object()).primitive_string();
- }
- // 3. Throw a TypeError exception.
- return vm.throw_completion<TypeError>(ErrorType::NotAnObjectOfType, "String");
- }
- // 22.1.3.1 String.prototype.at ( index ), https://tc39.es/ecma262/#sec-string.prototype.at
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::at)
- {
- // 1. Let O be ? ToObject(this value).
- auto string = TRY(utf16_string_from(vm));
- // 2. Let len be ? LengthOfArrayLike(O).
- auto length = string.length_in_code_units();
- // 3. Let relativeIndex be ? ToIntegerOrInfinity(index).
- auto relative_index = TRY(vm.argument(0).to_integer_or_infinity(vm));
- if (Value(relative_index).is_infinity())
- return js_undefined();
- Checked<size_t> index { 0 };
- // 4. If relativeIndex ≥ 0, then
- if (relative_index >= 0) {
- // a. Let k be relativeIndex.
- index += relative_index;
- }
- // 5. Else,
- else {
- // a. Let k be len + relativeIndex.
- index += length;
- index -= -relative_index;
- }
- // 6. If k < 0 or k ≥ len, return undefined.
- if (index.has_overflow() || index.value() >= length)
- return js_undefined();
- // 7. Return ? Get(O, ! ToString(𝔽(k))).
- return PrimitiveString::create(vm, Utf16String::create(string.substring_view(index.value(), 1)));
- }
- // 22.1.3.2 String.prototype.charAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charat
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_at)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let position be ? ToIntegerOrInfinity(pos).
- auto position = TRY(vm.argument(0).to_integer_or_infinity(vm));
- // 4. Let size be the length of S.
- // 5. If position < 0 or position ≥ size, return the empty String.
- if (position < 0 || position >= string.length_in_code_units())
- return PrimitiveString::create(vm, String {});
- // 6. Return the substring of S from position to position + 1.
- return PrimitiveString::create(vm, Utf16String::create(string.substring_view(position, 1)));
- }
- // 22.1.3.3 String.prototype.charCodeAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.charcodeat
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::char_code_at)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let position be ? ToIntegerOrInfinity(pos).
- auto position = TRY(vm.argument(0).to_integer_or_infinity(vm));
- // 4. Let size be the length of S.
- // 5. If position < 0 or position ≥ size, return NaN.
- if (position < 0 || position >= string.length_in_code_units())
- return js_nan();
- // 6. Return the Number value for the numeric value of the code unit at index position within the String S.
- return Value(string.code_unit_at(position));
- }
- // 22.1.3.4 String.prototype.codePointAt ( pos ), https://tc39.es/ecma262/#sec-string.prototype.codepointat
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::code_point_at)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let position be ? ToIntegerOrInfinity(pos).
- auto position = TRY(vm.argument(0).to_integer_or_infinity(vm));
- // 4. Let size be the length of S.
- // 5. If position < 0 or position ≥ size, return undefined.
- if (position < 0 || position >= string.length_in_code_units())
- return js_undefined();
- // 6. Let cp be CodePointAt(S, position).
- auto code_point = JS::code_point_at(string.view(), position);
- // 7. Return 𝔽(cp.[[CodePoint]]).
- return Value(code_point.code_point);
- }
- // 22.1.3.5 String.prototype.concat ( ...args ), https://tc39.es/ecma262/#sec-string.prototype.concat
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::concat)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. Let S be ? ToString(O).
- auto string = TRY(object.to_primitive_string(vm));
- // 3. Let R be S.
- auto result = string;
- // 4. For each element next of args, do
- for (size_t i = 0; i < vm.argument_count(); ++i) {
- // a. Let nextString be ? ToString(next).
- auto next_string = TRY(vm.argument(i).to_primitive_string(vm));
- // b. Set R to the string-concatenation of R and nextString.
- result = PrimitiveString::create(vm, *result, *next_string);
- }
- // 5. Return R.
- return result;
- }
- // 22.1.3.7 String.prototype.endsWith ( searchString [ , endPosition ] ), https://tc39.es/ecma262/#sec-string.prototype.endswith
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::ends_with)
- {
- auto search_string_value = vm.argument(0);
- auto end_position = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // Let isRegExp be ? IsRegExp(searchString).
- bool is_regexp = TRY(search_string_value.is_regexp(vm));
- // 4. If isRegExp is true, throw a TypeError exception.
- if (is_regexp)
- return vm.throw_completion<TypeError>(ErrorType::IsNotA, "searchString", "string, but a regular expression");
- // 5. Let searchStr be ? ToString(searchString).
- auto search_string = TRY(search_string_value.to_utf16_string(vm));
- // 6. Let len be the length of S.
- auto string_length = string.length_in_code_units();
- // 7. If endPosition is undefined, let pos be len; else let pos be ? ToIntegerOrInfinity(endPosition).
- size_t end = string_length;
- if (!end_position.is_undefined()) {
- auto position = TRY(end_position.to_integer_or_infinity(vm));
- // 8. Let end be the result of clamping pos between 0 and len.
- end = clamp(position, static_cast<double>(0), static_cast<double>(string_length));
- }
- // 9. Let searchLength be the length of searchStr.
- auto search_length = search_string.length_in_code_units();
- // 10. If searchLength = 0, return true.
- if (search_length == 0)
- return Value(true);
- // 12. If start < 0, return false.
- if (search_length > end)
- return Value(false);
- // 11. Let start be end - searchLength.
- size_t start = end - search_length;
- // 13. Let substring be the substring of S from start to end.
- auto substring_view = string.substring_view(start, end - start);
- // 14. If substring is searchStr, return true.
- // 15. Return false.
- return Value(substring_view == search_string.view());
- }
- // 22.1.3.8 String.prototype.includes ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.includes
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::includes)
- {
- auto search_string_value = vm.argument(0);
- auto position = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let isRegExp be ? IsRegExp(searchString).
- bool is_regexp = TRY(search_string_value.is_regexp(vm));
- // 4. If isRegExp is true, throw a TypeError exception.
- if (is_regexp)
- return vm.throw_completion<TypeError>(ErrorType::IsNotA, "searchString", "string, but a regular expression");
- // 5. Let searchStr be ? ToString(searchString).
- auto search_string = TRY(search_string_value.to_utf16_string(vm));
- size_t start = 0;
- if (!position.is_undefined()) {
- // 6. Let pos be ? ToIntegerOrInfinity(position).
- // 7. Assert: If position is undefined, then pos is 0.
- auto pos = TRY(position.to_integer_or_infinity(vm));
- // 8. Let len be the length of S.
- // 9. Let start be the result of clamping pos between 0 and len.
- start = clamp(pos, static_cast<double>(0), static_cast<double>(string.length_in_code_units()));
- }
- // 10. Let index be StringIndexOf(S, searchStr, start).
- auto index = string_index_of(string.view(), search_string.view(), start);
- // 11. If index ≠ -1, return true.
- // 12. Return false.
- return Value(index.has_value());
- }
- // 22.1.3.9 String.prototype.indexOf ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.indexof
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::index_of)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let searchStr be ? ToString(searchString).
- auto search_string = TRY(vm.argument(0).to_utf16_string(vm));
- auto utf16_string_view = string.view();
- auto utf16_search_view = search_string.view();
- size_t start = 0;
- if (vm.argument_count() > 1) {
- // 4. Let pos be ? ToIntegerOrInfinity(position).
- // 5. Assert: If position is undefined, then pos is 0.
- auto position = TRY(vm.argument(1).to_integer_or_infinity(vm));
- // 6. Let len be the length of S.
- // 7. Let start be the result of clamping pos between 0 and len.
- start = clamp(position, static_cast<double>(0), static_cast<double>(utf16_string_view.length_in_code_units()));
- }
- // 8. Return 𝔽(StringIndexOf(S, searchStr, start)).
- auto index = string_index_of(utf16_string_view, utf16_search_view, start);
- return index.has_value() ? Value(*index) : Value(-1);
- }
- // 22.1.3.10 String.prototype.isWellFormed ( ), https://tc39.es/ecma262/#sec-string.prototype.iswellformed
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::is_well_formed)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Return IsStringWellFormedUnicode(S).
- return is_string_well_formed_unicode(string.view());
- }
- // 22.1.3.11 String.prototype.lastIndexOf ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.lastindexof
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::last_index_of)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let searchStr be ? ToString(searchString).
- auto search_string = TRY(vm.argument(0).to_utf16_string(vm));
- // 4. Let numPos be ? ToNumber(position).
- // 5. Assert: If position is undefined, then numPos is NaN.
- auto position = TRY(vm.argument(1).to_number(vm));
- // 6. If numPos is NaN, let pos be +∞; otherwise, let pos be ! ToIntegerOrInfinity(numPos).
- double pos = position.is_nan() ? static_cast<double>(INFINITY) : MUST(position.to_integer_or_infinity(vm));
- // 7. Let len be the length of S.
- auto string_length = string.length_in_code_units();
- // 8. Let searchLen be the length of searchStr.
- auto search_length = search_string.length_in_code_units();
- // 9. Let start be the result of clamping pos between 0 and len - searchLen.
- size_t start = clamp(pos, static_cast<double>(0), static_cast<double>(string_length));
- Optional<size_t> last_index;
- // 10. If searchStr is the empty String, return 𝔽(start).
- // 11. For each integer i such that 0 ≤ i ≤ start, in descending order, do
- for (size_t k = 0; (k <= start) && (k + search_length <= string_length); ++k) {
- bool is_match = true;
- // a. Let candidate be the substring of S from i to i + searchLen.
- for (size_t j = 0; j < search_length; ++j) {
- if (string.code_unit_at(k + j) != search_string.code_unit_at(j)) {
- is_match = false;
- break;
- }
- }
- // b. If candidate is searchStr, return 𝔽(i).
- if (is_match)
- last_index = k;
- }
- // 12. Return -1𝔽.
- return last_index.has_value() ? Value(*last_index) : Value(-1);
- }
- // 22.1.3.12 String.prototype.localeCompare ( that [ , reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-string.prototype.localecompare
- // 19.1.1 String.prototype.localeCompare ( that [ , locales [ , options ] ] ), https://tc39.es/ecma402/#sup-String.prototype.localeCompare
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::locale_compare)
- {
- auto& realm = *vm.current_realm();
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. Let S be ? ToString(O).
- auto string = TRY(object.to_string(vm));
- // 3. Let thatValue be ? ToString(that).
- auto that_value = TRY(vm.argument(0).to_string(vm));
- // 4. Let collator be ? Construct(%Collator%, « locales, options »).
- auto collator = TRY(construct(vm, realm.intrinsics().intl_collator_constructor(), vm.argument(1), vm.argument(2)));
- // 5. Return CompareStrings(collator, S, thatValue).
- return Intl::compare_strings(static_cast<Intl::Collator const&>(*collator), string, that_value);
- }
- // 22.1.3.13 String.prototype.match ( regexp ), https://tc39.es/ecma262/#sec-string.prototype.match
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto this_object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. If regexp is neither undefined nor null, then
- auto regexp = vm.argument(0);
- if (!regexp.is_nullish()) {
- // a. Let matcher be ? GetMethod(regexp, @@match).
- auto matcher = TRY(regexp.get_method(vm, vm.well_known_symbol_match()));
- // b. If matcher is not undefined, then
- if (matcher) {
- // i. Return ? Call(matcher, regexp, « O »).
- return TRY(call(vm, *matcher, regexp, this_object));
- }
- }
- // 3. Let S be ? ToString(O).
- auto string = TRY(this_object.to_utf16_string(vm));
- // 4. Let rx be ? RegExpCreate(regexp, undefined).
- auto rx = TRY(regexp_create(vm, regexp, js_undefined()));
- // 5. Return ? Invoke(rx, @@match, « S »).
- return TRY(Value(rx).invoke(vm, vm.well_known_symbol_match(), PrimitiveString::create(vm, move(string))));
- }
- // 22.1.3.14 String.prototype.matchAll ( regexp ), https://tc39.es/ecma262/#sec-string.prototype.matchall
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match_all)
- {
- auto regexp = vm.argument(0);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto this_object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. If regexp is neither undefined nor null, then
- if (!regexp.is_nullish()) {
- // a. Let isRegExp be ? IsRegExp(regexp).
- auto is_regexp = TRY(regexp.is_regexp(vm));
- // b. If isRegExp is true, then
- if (is_regexp) {
- // i. Let flags be ? Get(regexp, "flags").
- auto flags = TRY(regexp.as_object().get("flags"));
- // ii. Perform ? RequireObjectCoercible(flags).
- auto flags_object = TRY(require_object_coercible(vm, flags));
- // iii. If ? ToString(flags) does not contain "g", throw a TypeError exception.
- auto flags_string = TRY(flags_object.to_string(vm));
- if (!flags_string.contains('g'))
- return vm.throw_completion<TypeError>(ErrorType::StringNonGlobalRegExp);
- }
- // c. Let matcher be ? GetMethod(regexp, @@matchAll).
- auto matcher = TRY(regexp.get_method(vm, vm.well_known_symbol_match_all()));
- // d. If matcher is not undefined, then
- if (matcher) {
- // i. Return ? Call(matcher, regexp, « O »).
- return TRY(call(vm, *matcher, regexp, this_object));
- }
- }
- // 3. Let S be ? ToString(O).
- auto string = TRY(this_object.to_utf16_string(vm));
- // 4. Let rx be ? RegExpCreate(regexp, "g").
- auto rx = TRY(regexp_create(vm, regexp, PrimitiveString::create(vm, "g"_string)));
- // 5. Return ? Invoke(rx, @@matchAll, « S »).
- return TRY(Value(rx).invoke(vm, vm.well_known_symbol_match_all(), PrimitiveString::create(vm, move(string))));
- }
- // 22.1.3.15 String.prototype.normalize ( [ form ] ), https://tc39.es/ecma262/#sec-string.prototype.normalize
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::normalize)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf8_string_from(vm));
- String form;
- // 3. If form is undefined, let f be "NFC".
- if (auto form_value = vm.argument(0); form_value.is_undefined()) {
- form = "NFC"_string;
- }
- // 4. Else, let f be ? ToString(form).
- else {
- form = TRY(form_value.to_string(vm));
- }
- // 5. If f is not one of "NFC", "NFD", "NFKC", or "NFKD", throw a RangeError exception.
- if (!form.is_one_of("NFC"sv, "NFD"sv, "NFKC"sv, "NFKD"sv))
- return vm.throw_completion<RangeError>(ErrorType::InvalidNormalizationForm, form);
- // 6. Let ns be the String value that is the result of normalizing S into the normalization form named by f as specified in https://unicode.org/reports/tr15/.
- auto unicode_form = Unicode::normalization_form_from_string(form);
- auto ns = Unicode::normalize(string, unicode_form);
- // 7. Return ns.
- return PrimitiveString::create(vm, move(ns));
- }
- enum class PadPlacement {
- Start,
- End,
- };
- // 22.1.3.17.1 StringPad ( O, maxLength, fillString, placement ), https://tc39.es/ecma262/#sec-stringpad
- static ThrowCompletionOr<Value> pad_string(VM& vm, Utf16String string, Value max_length, Value fill_string, PadPlacement placement)
- {
- // 1. Let S be ? ToString(O).
- // 2. Let intMaxLength be ℝ(? ToLength(maxLength)).
- auto int_max_length = TRY(max_length.to_length(vm));
- // 3. Let stringLength be the length of S.
- auto string_length = string.length_in_code_units();
- // 4. If intMaxLength ≤ stringLength, return S.
- if (int_max_length <= string_length)
- return PrimitiveString::create(vm, move(string));
- // 5. If fillString is undefined, let filler be the String value consisting solely of the code unit 0x0020 (SPACE).
- auto filler = Utf16String::create(Utf16Data { 0x20 });
- if (!fill_string.is_undefined()) {
- // 6. Else, let filler be ? ToString(fillString).
- filler = TRY(fill_string.to_utf16_string(vm));
- // 7. If filler is the empty String, return S.
- if (filler.is_empty())
- return PrimitiveString::create(vm, move(string));
- }
- // 8. Let fillLen be intMaxLength - stringLength.
- auto fill_length = int_max_length - string_length;
- StringBuilder truncated_string_filler_builder;
- auto fill_code_units = filler.length_in_code_units();
- for (size_t i = 0; i < fill_length / fill_code_units; ++i)
- truncated_string_filler_builder.append(filler.view());
- // 9. Let truncatedStringFiller be the String value consisting of repeated concatenations of filler truncated to length fillLen.
- truncated_string_filler_builder.append(filler.substring_view(0, fill_length % fill_code_units));
- auto truncated_string_filler = MUST(truncated_string_filler_builder.to_string());
- // 10. If placement is start, return the string-concatenation of truncatedStringFiller and S.
- // 11. Else, return the string-concatenation of S and truncatedStringFiller.
- auto formatted = placement == PadPlacement::Start
- ? MUST(String::formatted("{}{}", truncated_string_filler, string.view()))
- : MUST(String::formatted("{}{}", string.view(), truncated_string_filler));
- return PrimitiveString::create(vm, move(formatted));
- }
- // 22.1.3.16 String.prototype.padEnd ( maxLength [ , fillString ] ), https://tc39.es/ecma262/#sec-string.prototype.padend
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::pad_end)
- {
- auto max_length = vm.argument(0);
- auto fill_string = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto string = TRY(utf16_string_from(vm));
- // 2. Return ? StringPad(O, maxLength, fillString, end).
- return pad_string(vm, move(string), max_length, fill_string, PadPlacement::End);
- }
- // 22.1.3.17 String.prototype.padStart ( maxLength [ , fillString ] ), https://tc39.es/ecma262/#sec-string.prototype.padstart
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::pad_start)
- {
- auto max_length = vm.argument(0);
- auto fill_string = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto string = TRY(utf16_string_from(vm));
- // 2. Return ? StringPad(O, maxLength, fillString, start).
- return pad_string(vm, move(string), max_length, fill_string, PadPlacement::Start);
- }
- // 22.1.3.18 String.prototype.repeat ( count ), https://tc39.es/ecma262/#sec-string.prototype.repeat
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::repeat)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf8_string_from(vm));
- // 3. Let n be ? ToIntegerOrInfinity(count).
- auto n = TRY(vm.argument(0).to_integer_or_infinity(vm));
- // 4. If n < 0 or n = +∞, throw a RangeError exception.
- if (n < 0)
- return vm.throw_completion<RangeError>(ErrorType::StringRepeatCountMustBe, "positive");
- if (Value(n).is_positive_infinity())
- return vm.throw_completion<RangeError>(ErrorType::StringRepeatCountMustBe, "finite");
- // 5. If n = 0, return the empty String.
- if (n == 0)
- return PrimitiveString::create(vm, String {});
- // OPTIMIZATION: If the string is empty, the result will be empty as well.
- if (string.is_empty())
- return PrimitiveString::create(vm, String {});
- auto repeated = String::repeated(string, n);
- if (repeated.is_error())
- return vm.throw_completion<RangeError>(ErrorType::StringRepeatCountMustNotOverflow);
- // 6. Return the String value that is made from n copies of S appended together.
- return PrimitiveString::create(vm, repeated.release_value());
- }
- // 22.1.3.19 String.prototype.replace ( searchValue, replaceValue ), https://tc39.es/ecma262/#sec-string.prototype.replace
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace)
- {
- auto search_value = vm.argument(0);
- auto replace_value = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto this_object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. If searchValue is neither undefined nor null, then
- if (!search_value.is_nullish()) {
- // a. Let replacer be ? GetMethod(searchValue, @@replace).
- auto replacer = TRY(search_value.get_method(vm, vm.well_known_symbol_replace()));
- // b. If replacer is not undefined, then
- if (replacer) {
- // i. Return ? Call(replacer, searchValue, « O, replaceValue »).
- return TRY(call(vm, *replacer, search_value, this_object, replace_value));
- }
- }
- // 3. Let string be ? ToString(O).
- auto string = TRY(this_object.to_utf16_string(vm));
- // 4. Let searchString be ? ToString(searchValue).
- auto search_string = TRY(search_value.to_utf16_string(vm));
- // 5. Let functionalReplace be IsCallable(replaceValue).
- // 6. If functionalReplace is false, then
- if (!replace_value.is_function()) {
- // a. Set replaceValue to ? ToString(replaceValue).
- auto replace_string = TRY(replace_value.to_utf16_string(vm));
- replace_value = PrimitiveString::create(vm, move(replace_string));
- }
- // 7. Let searchLength be the length of searchString.
- auto search_length = search_string.length_in_code_units();
- // 8. Let position be StringIndexOf(string, searchString, 0).
- auto position = string_index_of(string.view(), search_string.view(), 0);
- // 9. If position = -1, return string.
- if (!position.has_value())
- return PrimitiveString::create(vm, move(string));
- // 10. Let preceding be the substring of string from 0 to position.
- auto preceding = string.substring_view(0, *position);
- String replacement;
- // 11. Let following be the substring of string from position + searchLength.
- auto following = string.substring_view(*position + search_length);
- // 12. If functionalReplace is true, then
- if (replace_value.is_function()) {
- // a. Let replacement be ? ToString(? Call(replaceValue, undefined, « searchString, 𝔽(position), string »)).
- auto result = TRY(call(vm, replace_value.as_function(), js_undefined(), PrimitiveString::create(vm, search_string), Value(*position), PrimitiveString::create(vm, string)));
- replacement = TRY(result.to_string(vm));
- }
- // 13. Else,
- else {
- // a. Assert: replaceValue is a String.
- VERIFY(replace_value.is_string());
- // b. Let captures be a new empty List.
- Span<Value> captures;
- // c. Let replacement be ! GetSubstitution(searchString, string, position, captures, undefined, replaceValue).
- replacement = TRY(get_substitution(vm, search_string.view(), string.view(), *position, captures, js_undefined(), replace_value));
- }
- // 14. Return the string-concatenation of preceding, replacement, and following.
- StringBuilder builder;
- builder.append(preceding);
- builder.append(replacement);
- builder.append(following);
- return PrimitiveString::create(vm, MUST(builder.to_string()));
- }
- // 22.1.3.20 String.prototype.replaceAll ( searchValue, replaceValue ), https://tc39.es/ecma262/#sec-string.prototype.replaceall
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace_all)
- {
- auto search_value = vm.argument(0);
- auto replace_value = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto this_object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. If searchValue is neither undefined nor null, then
- if (!search_value.is_nullish()) {
- // a. Let isRegExp be ? IsRegExp(searchValue).
- bool is_regexp = TRY(search_value.is_regexp(vm));
- // b. If isRegExp is true, then
- if (is_regexp) {
- // i. Let flags be ? Get(searchValue, "flags").
- auto flags = TRY(search_value.as_object().get(vm.names.flags));
- // ii. Perform ? RequireObjectCoercible(flags).
- auto flags_object = TRY(require_object_coercible(vm, flags));
- // iii. If ? ToString(flags) does not contain "g", throw a TypeError exception.
- if (!TRY(flags_object.to_string(vm)).contains('g'))
- return vm.throw_completion<TypeError>(ErrorType::StringNonGlobalRegExp);
- }
- // c. Let replacer be ? GetMethod(searchValue, @@replace).
- auto replacer = TRY(search_value.get_method(vm, vm.well_known_symbol_replace()));
- // d. If replacer is not undefined, then
- if (replacer) {
- // i. Return ? Call(replacer, searchValue, « O, replaceValue »).
- return TRY(call(vm, *replacer, search_value, this_object, replace_value));
- }
- }
- // 3. Let string be ? ToString(O).
- auto string = TRY(this_object.to_utf16_string(vm));
- // 4. Let searchString be ? ToString(searchValue).
- auto search_string = TRY(search_value.to_utf16_string(vm));
- // 5. Let functionalReplace be IsCallable(replaceValue).
- // 6. If functionalReplace is false, then
- if (!replace_value.is_function()) {
- // a. Set replaceValue to ? ToString(replaceValue).
- auto replace_string = TRY(replace_value.to_utf16_string(vm));
- replace_value = PrimitiveString::create(vm, move(replace_string));
- }
- // 7. Let searchLength be the length of searchString.
- auto search_length = search_string.length_in_code_units();
- // 8. Let advanceBy be max(1, searchLength).
- size_t advance_by = max(1u, search_length);
- // 9. Let matchPositions be a new empty List.
- Vector<size_t> match_positions;
- // 10. Let position be StringIndexOf(string, searchString, 0).
- auto position = string_index_of(string.view(), search_string.view(), 0);
- // 11. Repeat, while position ≠ -1,
- while (position.has_value()) {
- // a. Append position to matchPositions.
- match_positions.append(*position);
- // b. Set position to StringIndexOf(string, searchString, position + advanceBy).
- position = string_index_of(string.view(), search_string.view(), *position + advance_by);
- }
- // 12. Let endOfLastMatch be 0.
- size_t end_of_last_match = 0;
- // 13. Let result be the empty String.
- StringBuilder result;
- // 14. For each element p of matchPositions, do
- for (auto position : match_positions) {
- // a. Let preserved be the substring of string from endOfLastMatch to p.
- auto preserved = string.substring_view(end_of_last_match, position - end_of_last_match);
- String replacement;
- // b. If functionalReplace is true, then
- if (replace_value.is_function()) {
- // i. Let replacement be ? ToString(? Call(replaceValue, undefined, « searchString, 𝔽(p), string »)).
- replacement = TRY(TRY(call(vm, replace_value.as_function(), js_undefined(), PrimitiveString::create(vm, search_string), Value(position), PrimitiveString::create(vm, string))).to_string(vm));
- }
- // c. Else,
- else {
- // i. Assert: replaceValue is a String.
- // ii. Let captures be a new empty List.
- // iii. Let replacement be ! GetSubstitution(searchString, string, p, captures, undefined, replaceValue).
- replacement = TRY(get_substitution(vm, search_string.view(), string.view(), position, {}, js_undefined(), replace_value));
- }
- // d. Set result to the string-concatenation of result, preserved, and replacement.
- result.append(preserved);
- result.append(replacement);
- // e. Set endOfLastMatch to p + searchLength.
- end_of_last_match = position + search_length;
- }
- auto string_length = string.length_in_code_units();
- // 15. If endOfLastMatch < the length of string, then
- if (end_of_last_match < string_length) {
- // a. Set result to the string-concatenation of result and the substring of string from endOfLastMatch.
- result.append(string.substring_view(end_of_last_match));
- }
- // 16. Return result.
- return PrimitiveString::create(vm, MUST(result.to_string()));
- }
- // 22.1.3.21 String.prototype.search ( regexp ), https://tc39.es/ecma262/#sec-string.prototype.search
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::search)
- {
- auto regexp = vm.argument(0);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto this_object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. If regexp is neither undefined nor null, then
- if (!regexp.is_nullish()) {
- // a. Let searcher be ? GetMethod(regexp, @@search).
- auto searcher = TRY(regexp.get_method(vm, vm.well_known_symbol_search()));
- // b. If searcher is not undefined, then
- if (searcher) {
- // i. Return ? Call(searcher, regexp, « O »).
- return TRY(call(vm, *searcher, regexp, this_object));
- }
- }
- // 3. Let string be ? ToString(O).
- auto string = TRY(this_object.to_utf16_string(vm));
- // 4. Let rx be ? RegExpCreate(regexp, undefined).
- auto rx = TRY(regexp_create(vm, regexp, js_undefined()));
- // 5. Return ? Invoke(rx, @@search, « string »).
- return TRY(Value(rx).invoke(vm, vm.well_known_symbol_search(), PrimitiveString::create(vm, move(string))));
- }
- // 22.1.3.22 String.prototype.slice ( start, end ), https://tc39.es/ecma262/#sec-string.prototype.slice
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::slice)
- {
- auto start = vm.argument(0);
- auto end = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let len be the length of S.
- auto string_length = static_cast<double>(string.length_in_code_units());
- // 4. Let intStart be ? ToIntegerOrInfinity(start).
- auto int_start = TRY(start.to_integer_or_infinity(vm));
- // 5. If intStart = -∞, let from be 0.
- if (Value(int_start).is_negative_infinity())
- int_start = 0;
- // 6. Else if intStart < 0, let from be max(len + intStart, 0).
- else if (int_start < 0)
- int_start = max(string_length + int_start, 0);
- // 7. Else, let from be min(intStart, len).
- else
- int_start = min(int_start, string_length);
- // 8. If end is undefined, let intEnd be len; else let intEnd be ? ToIntegerOrInfinity(end).
- auto int_end = string_length;
- if (!end.is_undefined()) {
- int_end = TRY(end.to_integer_or_infinity(vm));
- // 9. If intEnd = -∞, let to be 0.
- if (Value(int_end).is_negative_infinity())
- int_end = 0;
- // 10. Else if intEnd < 0, let to be max(len + intEnd, 0).
- else if (int_end < 0)
- int_end = max(string_length + int_end, 0);
- // 11. Else, let to be min(intEnd, len).
- else
- int_end = min(int_end, string_length);
- }
- // 12. If from ≥ to, return the empty String.
- if (int_start >= int_end)
- return PrimitiveString::create(vm, String {});
- // 13. Return the substring of S from from to to.
- return PrimitiveString::create(vm, Utf16String::create(string.substring_view(int_start, int_end - int_start)));
- }
- // 22.1.3.23 String.prototype.split ( separator, limit ), https://tc39.es/ecma262/#sec-string.prototype.split
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
- {
- auto& realm = *vm.current_realm();
- auto separator_argument = vm.argument(0);
- auto limit_argument = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. If separator is neither undefined nor null, then
- if (!separator_argument.is_nullish()) {
- // a. Let splitter be ? GetMethod(separator, @@split).
- auto splitter = TRY(separator_argument.get_method(vm, vm.well_known_symbol_split()));
- // b. If splitter is not undefined, then
- if (splitter) {
- // i. Return ? Call(splitter, separator, « O, limit »).
- return TRY(call(vm, *splitter, separator_argument, object, limit_argument));
- }
- }
- // 3. Let S be ? ToString(O).
- auto string = TRY(object.to_utf16_string(vm));
- // 11. Let substrings be a new empty List.
- auto array = MUST(Array::create(realm, 0));
- size_t array_length = 0;
- // 4. If limit is undefined, let lim be 232 - 1; else let lim be ℝ(? ToUint32(limit)).
- auto limit = NumericLimits<u32>::max();
- if (!limit_argument.is_undefined())
- limit = TRY(limit_argument.to_u32(vm));
- // 5. Let R be ? ToString(separator).
- auto separator = TRY(separator_argument.to_utf16_string(vm));
- // 6. If lim = 0, then
- if (limit == 0) {
- // a. Return CreateArrayFromList(« »).
- return array;
- }
- auto string_length = string.length_in_code_units();
- // 7. If separator is undefined, then
- if (separator_argument.is_undefined()) {
- // a. Return CreateArrayFromList(« S »).
- MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, move(string))));
- return array;
- }
- // 8. Let separatorLength be the length of R.
- auto separator_length = separator.length_in_code_units();
- // 10. If S is the empty String, return CreateArrayFromList(« S »).
- if (string_length == 0) {
- if (separator_length > 0)
- MUST(array->create_data_property_or_throw(0, PrimitiveString::create(vm, move(string))));
- return array;
- }
- // 12. Let i be 0.
- size_t start = 0;
- // 13. Let j be StringIndexOf(S, R, 0).
- auto position = start;
- // 14. Repeat, while j ≠ -1,
- while (position != string_length) {
- // a. Let T be the substring of S from i to j.
- auto match = split_match(string.view(), position, separator.view());
- if (!match.has_value() || match.value() == start) {
- ++position;
- continue;
- }
- auto segment = string.substring_view(start, position - start);
- // b. Append T to substrings.
- MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(segment))));
- ++array_length;
- // c. If the number of elements in substrings is lim, return CreateArrayFromList(substrings).
- if (array_length == limit)
- return array;
- // d. Set i to j + separatorLength.
- start = match.value();
- // e. Set j to StringIndexOf(S, R, i).
- position = start;
- }
- // 15. Let T be the substring of S from i.
- auto rest = string.substring_view(start);
- // 16. Append T to substrings.
- MUST(array->create_data_property_or_throw(array_length, PrimitiveString::create(vm, Utf16String::create(rest))));
- // 17. Return CreateArrayFromList(substrings).
- return array;
- }
- // 22.1.3.24 String.prototype.startsWith ( searchString [ , position ] ), https://tc39.es/ecma262/#sec-string.prototype.startswith
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::starts_with)
- {
- auto search_string_value = vm.argument(0);
- auto position = vm.argument(1);
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let isRegExp be ? IsRegExp(searchString).
- bool is_regexp = TRY(search_string_value.is_regexp(vm));
- // 4. If isRegExp is true, throw a TypeError exception.
- if (is_regexp)
- return vm.throw_completion<TypeError>(ErrorType::IsNotA, "searchString", "string, but a regular expression");
- // 5. Let searchStr be ? ToString(searchString).
- auto search_string = TRY(search_string_value.to_utf16_string(vm));
- // 6. Let len be the length of S.
- auto string_length = string.length_in_code_units();
- size_t start = 0;
- // 7. If position is undefined, let pos be 0; else let pos be ? ToIntegerOrInfinity(position).
- if (!position.is_undefined()) {
- auto pos = TRY(position.to_integer_or_infinity(vm));
- // 8. Let start be the result of clamping pos between 0 and len.
- start = clamp(pos, static_cast<double>(0), static_cast<double>(string_length));
- }
- // 9. Let searchLength be the length of searchStr.
- auto search_length = search_string.length_in_code_units();
- // 10. If searchLength = 0, return true.
- if (search_length == 0)
- return Value(true);
- // 11. Let end be start + searchLength.
- size_t end = start + search_length;
- // 12. If end > len, return false.
- if (end > string_length)
- return Value(false);
- // 13. Let substring be the substring of S from start to end.
- auto substring_view = string.substring_view(start, end - start);
- // 14. If substring is searchStr, return true.
- // 15. Return false.
- return Value(substring_view == search_string.view());
- }
- // 22.1.3.25 String.prototype.substring ( start, end ), https://tc39.es/ecma262/#sec-string.prototype.substring
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substring)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let len be the length of S.
- auto string_length = static_cast<double>(string.length_in_code_units());
- // 4. Let intStart be ? ToIntegerOrInfinity(start).
- auto start = TRY(vm.argument(0).to_integer_or_infinity(vm));
- // 5. If end is undefined, let intEnd be len; else let intEnd be ? ToIntegerOrInfinity(end).
- auto end = string_length;
- if (!vm.argument(1).is_undefined())
- end = TRY(vm.argument(1).to_integer_or_infinity(vm));
- // 6. Let finalStart be the result of clamping intStart between 0 and len.
- size_t final_start = clamp(start, static_cast<double>(0), string_length);
- // 7. Let finalEnd be the result of clamping intEnd between 0 and len.
- size_t final_end = clamp(end, static_cast<double>(0), string_length);
- // 8. Let from be min(finalStart, finalEnd).
- size_t from = min(final_start, final_end);
- // 9. Let to be max(finalStart, finalEnd).
- size_t to = max(final_start, final_end);
- // 10. Return the substring of S from from to to.
- return PrimitiveString::create(vm, Utf16String::create(string.substring_view(from, to - from)));
- }
- enum class TargetCase {
- Lower,
- Upper,
- };
- // 19.1.2.1 TransformCase ( S, locales, targetCase ), https://tc39.es/ecma402/#sec-transform-case
- static ThrowCompletionOr<String> transform_case(VM& vm, String const& string, Value locales, TargetCase target_case)
- {
- // 1. Let requestedLocales be ? CanonicalizeLocaleList(locales).
- auto requested_locales = TRY(Intl::canonicalize_locale_list(vm, locales));
- String requested_locale;
- // 2. If requestedLocales is not an empty List, then
- if (!requested_locales.is_empty()) {
- // a. Let requestedLocale be requestedLocales[0].
- requested_locale = requested_locales[0];
- }
- // 3. Else,
- else {
- // a. Let requestedLocale be ! DefaultLocale().
- requested_locale = String::from_utf8_without_validation(Unicode::default_locale().bytes());
- }
- // 4. Let availableLocales be an Available Locales List which includes the language tags for which the Unicode Character Database contains language-sensitive case mappings. If the implementation supports additional locale-sensitive case mappings, availableLocales should also include their corresponding language tags.
- // 5. Let match be LookupMatchingLocaleByPrefix(availableLocales, « requestedLocale »).
- auto match = Intl::lookup_matching_locale_by_prefix({ { requested_locale } });
- // 6. If match is not undefined, let locale be match.[[locale]]; else let locale be "und".
- StringView locale = match.has_value() ? match->locale : "und"sv;
- // 7. Let codePoints be StringToCodePoints(S).
- String new_code_points;
- switch (target_case) {
- // 8. If targetCase is lower, then
- case TargetCase::Lower:
- // a. Let newCodePoints be a List whose elements are the result of a lowercase transformation of codePoints according to an implementation-derived algorithm using locale or the Unicode Default Case Conversion algorithm.
- new_code_points = MUST(string.to_lowercase(locale));
- break;
- // 9. Else,
- case TargetCase::Upper:
- // a. Assert: targetCase is upper.
- // b. Let newCodePoints be a List whose elements are the result of an uppercase transformation of codePoints according to an implementation-derived algorithm using locale or the Unicode Default Case Conversion algorithm.
- new_code_points = MUST(string.to_uppercase(locale));
- break;
- default:
- VERIFY_NOT_REACHED();
- }
- // 10. Return CodePointsToString(newCodePoints).
- return new_code_points;
- }
- // 22.1.3.26 String.prototype.toLocaleLowerCase ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-string.prototype.tolocalelowercase
- // 19.1.2 String.prototype.toLocaleLowerCase ( [ locales ] ), https://tc39.es/ecma402/#sup-string.prototype.tolocalelowercase
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_locale_lowercase)
- {
- auto locales = vm.argument(0);
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf8_string_from(vm));
- // 3. Return ? TransformCase(S, locales, lower).
- return PrimitiveString::create(vm, TRY(transform_case(vm, string, locales, TargetCase::Lower)));
- }
- // 22.1.3.27 String.prototype.toLocaleUpperCase ( [ reserved1 [ , reserved2 ] ] ), https://tc39.es/ecma262/#sec-string.prototype.tolocaleuppercase
- // 19.1.3 String.prototype.toLocaleUpperCase ( [ locales ] ), https://tc39.es/ecma402/#sup-string.prototype.tolocaleuppercase
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_locale_uppercase)
- {
- auto locales = vm.argument(0);
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf8_string_from(vm));
- // 3. Return ? TransformCase(S, locales, upper).
- return PrimitiveString::create(vm, TRY(transform_case(vm, string, locales, TargetCase::Upper)));
- }
- // 22.1.3.28 String.prototype.toLowerCase ( ), https://tc39.es/ecma262/#sec-string.prototype.tolowercase
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_lowercase)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- // 3. Let sText be StringToCodePoints(S).
- auto string = TRY(utf8_string_from(vm));
- // 4. Let lowerText be the result of toLowercase(sText), according to the Unicode Default Case Conversion algorithm.
- auto lowercase = MUST(string.to_lowercase());
- // 5. Let L be CodePointsToString(lowerText).
- // 6. Return L.
- return PrimitiveString::create(vm, move(lowercase));
- }
- // 22.1.3.29 String.prototype.toString ( ), https://tc39.es/ecma262/#sec-string.prototype.tostring
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_string)
- {
- // 1. Return ? thisStringValue(this value).
- return TRY(this_string_value(vm, vm.this_value()));
- }
- // 22.1.3.30 String.prototype.toUpperCase ( ), https://tc39.es/ecma262/#sec-string.prototype.touppercase
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_uppercase)
- {
- // This method interprets a String value as a sequence of UTF-16 encoded code points, as described in 6.1.4.
- // It behaves in exactly the same way as String.prototype.toLowerCase, except that the String is mapped using the toUppercase algorithm of the Unicode Default Case Conversion.
- auto string = TRY(utf8_string_from(vm));
- auto uppercase = MUST(string.to_uppercase());
- return PrimitiveString::create(vm, move(uppercase));
- }
- // 22.1.3.31 String.prototype.toWellFormed ( ), https://tc39.es/ecma262/#sec-string.prototype.towellformed
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::to_well_formed)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // NOTE: Rest of steps in to_well_formed below
- return PrimitiveString::create(vm, to_well_formed_string(string));
- }
- // https://tc39.es/ecma262/#sec-string.prototype.towellformed
- String to_well_formed_string(Utf16String const& string)
- {
- // 3. Let strLen be the length of S.
- auto length = string.length_in_code_units();
- // 4. Let k be 0.
- size_t k = 0;
- // 5. Let result be the empty String.
- StringBuilder result;
- // 6. Repeat, while k < strLen,
- while (k < length) {
- // a. Let cp be CodePointAt(S, k).
- auto code_point = JS::code_point_at(string.view(), k);
- // b. If cp.[[IsUnpairedSurrogate]] is true, then
- if (code_point.is_unpaired_surrogate) {
- // i. Set result to the string-concatenation of result and 0xFFFD (REPLACEMENT CHARACTER).
- result.append_code_point(0xfffd);
- }
- // c. Else,
- else {
- // i. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp.[[CodePoint]]).
- result.append_code_point(code_point.code_point);
- }
- // d. Set k to k + cp.[[CodeUnitCount]].
- k += code_point.code_unit_count;
- }
- // 7. Return result.
- return MUST(result.to_string());
- }
- // 22.1.3.32.1 TrimString ( string, where ), https://tc39.es/ecma262/#sec-trimstring
- ThrowCompletionOr<String> trim_string(VM& vm, Value input_value, TrimMode where)
- {
- // 1. Let str be ? RequireObjectCoercible(string).
- auto input_string = TRY(require_object_coercible(vm, input_value));
- // 2. Let S be ? ToString(str).
- auto string = TRY(input_string.to_string(vm));
- // 3. If where is start, let T be the String value that is a copy of S with leading white space removed.
- // 4. Else if where is end, let T be the String value that is a copy of S with trailing white space removed.
- // 5. Else,
- // a. Assert: where is start+end.
- // b. Let T be the String value that is a copy of S with both leading and trailing white space removed.
- auto trimmed_string = Utf8View(string).trim(whitespace_characters, where).as_string();
- // 6. Return T.
- return MUST(String::from_utf8(trimmed_string));
- }
- // 22.1.3.32 String.prototype.trim ( ), https://tc39.es/ecma262/#sec-string.prototype.trim
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim)
- {
- // 1. Let S be the this value.
- // 2. Return ? TrimString(S, start+end).
- return PrimitiveString::create(vm, TRY(trim_string(vm, vm.this_value(), TrimMode::Both)));
- }
- // 22.1.3.33 String.prototype.trimEnd ( ), https://tc39.es/ecma262/#sec-string.prototype.trimend
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim_end)
- {
- // 1. Let S be the this value.
- // 2. Return ? TrimString(S, end).
- return PrimitiveString::create(vm, TRY(trim_string(vm, vm.this_value(), TrimMode::Right)));
- }
- // 22.1.3.34 String.prototype.trimStart ( ), https://tc39.es/ecma262/#sec-string.prototype.trimstart
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::trim_start)
- {
- // 1. Let S be the this value.
- // 2. Return ? TrimString(S, start).
- return PrimitiveString::create(vm, TRY(trim_string(vm, vm.this_value(), TrimMode::Left)));
- }
- // 22.1.3.35 String.prototype.valueOf ( ), https://tc39.es/ecma262/#sec-string.prototype.valueof
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::value_of)
- {
- return TRY(this_string_value(vm, vm.this_value()));
- }
- // 22.1.3.36 String.prototype [ @@iterator ] ( ), https://tc39.es/ecma262/#sec-string.prototype-@@iterator
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::symbol_iterator)
- {
- auto& realm = *vm.current_realm();
- // 1. Let O be ? RequireObjectCoercible(this value).
- auto this_object = TRY(require_object_coercible(vm, vm.this_value()));
- // 2. Let s be ? ToString(O).
- auto string = TRY(this_object.to_string(vm));
- // 3. Let closure be a new Abstract Closure with no parameters that captures s and performs the following steps when called:
- // ...
- // 4. Return CreateIteratorFromClosure(closure, "%StringIteratorPrototype%", %StringIteratorPrototype%).
- return StringIterator::create(realm, string);
- }
- // B.2.2.1 String.prototype.substr ( start, length ), https://tc39.es/ecma262/#sec-string.prototype.substr
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::substr)
- {
- // 1. Let O be ? RequireObjectCoercible(this value).
- // 2. Let S be ? ToString(O).
- auto string = TRY(utf16_string_from(vm));
- // 3. Let size be the length of S.
- auto size = string.length_in_code_units();
- // 4. Let intStart be ? ToIntegerOrInfinity(start).
- auto int_start = TRY(vm.argument(0).to_integer_or_infinity(vm));
- // 5. If intStart is -∞, set intStart to 0.
- if (Value(int_start).is_negative_infinity())
- int_start = 0;
- // 6. Else if intStart < 0, set intStart to max(size + intStart, 0).
- else if (int_start < 0)
- int_start = max(size + int_start, 0);
- // 7. Else, set intStart to min(intStart, size).
- else
- int_start = min(int_start, size);
- // 8. If length is undefined, let intLength be size; otherwise let intLength be ? ToIntegerOrInfinity(length).
- auto length = vm.argument(1);
- auto int_length = length.is_undefined() ? size : TRY(length.to_integer_or_infinity(vm));
- // 9. Set intLength to the result of clamping intLength between 0 and size.
- int_length = clamp(int_length, 0, size);
- // 10. Let intEnd be min(intStart + intLength, size).
- auto int_end = min((i32)(int_start + int_length), size);
- if (int_start >= int_end)
- return PrimitiveString::create(vm, String {});
- // 11. Return the substring of S from intStart to intEnd.
- return PrimitiveString::create(vm, Utf16String::create(string.substring_view(int_start, int_end - int_start)));
- }
- // B.2.2.2.1 CreateHTML ( string, tag, attribute, value ), https://tc39.es/ecma262/#sec-createhtml
- static ThrowCompletionOr<Value> create_html(VM& vm, Value string, StringView tag, StringView attribute, Value value)
- {
- // 1. Let str be ? RequireObjectCoercible(string).
- TRY(require_object_coercible(vm, string));
- // 2. Let S be ? ToString(str).
- auto str = TRY(string.to_string(vm));
- // 3. Let p1 be the string-concatenation of "<" and tag.
- StringBuilder builder;
- builder.append('<');
- builder.append(tag);
- // 4. If attribute is not the empty String, then
- if (!attribute.is_empty()) {
- // a. Let V be ? ToString(value).
- auto value_string = TRY(value.to_string(vm));
- // b. Let escapedV be the String value that is the same as V except that each occurrence of the code unit 0x0022 (QUOTATION MARK) in V has been replaced with the six code unit sequence """.
- auto escaped_value_string = MUST(value_string.replace("\""sv, """sv, ReplaceMode::All));
- // c. Set p1 to the string-concatenation of:
- // - p1
- // - the code unit 0x0020 (SPACE)
- builder.append(' ');
- // - attribute
- builder.append(attribute);
- // - the code unit 0x003D (EQUALS SIGN)
- // - the code unit 0x0022 (QUOTATION MARK)
- builder.append("=\""sv);
- // - escapedV
- builder.append(escaped_value_string);
- // - the code unit 0x0022 (QUOTATION MARK)
- builder.append('"');
- }
- // 5. Let p2 be the string-concatenation of p1 and ">".
- builder.append('>');
- // 6. Let p3 be the string-concatenation of p2 and S.
- builder.append(str);
- // 7. Let p4 be the string-concatenation of p3, "</", tag, and ">".
- builder.append("</"sv);
- builder.append(tag);
- builder.append('>');
- // 8. Return p4.
- return PrimitiveString::create(vm, MUST(builder.to_string()));
- }
- // B.2.2.2 String.prototype.anchor ( name ), https://tc39.es/ecma262/#sec-string.prototype.anchor
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::anchor)
- {
- auto name = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "a", "name", name).
- return create_html(vm, vm.this_value(), "a"sv, "name"sv, name);
- }
- // B.2.2.3 String.prototype.big ( ), https://tc39.es/ecma262/#sec-string.prototype.big
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::big)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "big", "", "").
- return create_html(vm, vm.this_value(), "big"sv, {}, Value());
- }
- // B.2.2.4 String.prototype.blink ( ), https://tc39.es/ecma262/#sec-string.prototype.blink
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::blink)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "blink", "", "").
- return create_html(vm, vm.this_value(), "blink"sv, {}, Value());
- }
- // B.2.2.5 String.prototype.bold ( ), https://tc39.es/ecma262/#sec-string.prototype.bold
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::bold)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "b", "", "").
- return create_html(vm, vm.this_value(), "b"sv, {}, Value());
- }
- // B.2.2.6 String.prototype.fixed ( ), https://tc39.es/ecma262/#sec-string.prototype.fixed
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::fixed)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "tt", "", "").
- return create_html(vm, vm.this_value(), "tt"sv, {}, Value());
- }
- // B.2.2.7 String.prototype.fontcolor ( color ), https://tc39.es/ecma262/#sec-string.prototype.fontcolor
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::fontcolor)
- {
- auto color = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "font", "color", color).
- return create_html(vm, vm.this_value(), "font"sv, "color"sv, color);
- }
- // B.2.2.8 String.prototype.fontsize ( size ), https://tc39.es/ecma262/#sec-string.prototype.fontsize
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::fontsize)
- {
- auto size = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "font", "size", size).
- return create_html(vm, vm.this_value(), "font"sv, "size"sv, size);
- }
- // B.2.2.9 String.prototype.italics ( ), https://tc39.es/ecma262/#sec-string.prototype.italics
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::italics)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "i", "", "").
- return create_html(vm, vm.this_value(), "i"sv, {}, Value());
- }
- // B.2.2.10 String.prototype.link ( url ), https://tc39.es/ecma262/#sec-string.prototype.link
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::link)
- {
- auto url = vm.argument(0);
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "a", "href", url).
- return create_html(vm, vm.this_value(), "a"sv, "href"sv, url);
- }
- // B.2.2.11 String.prototype.small ( ), https://tc39.es/ecma262/#sec-string.prototype.small
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::small)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "small", "", "").
- return create_html(vm, vm.this_value(), "small"sv, {}, Value());
- }
- // B.2.2.12 String.prototype.strike ( ), https://tc39.es/ecma262/#sec-string.prototype.strike
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::strike)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "strike", "", "").
- return create_html(vm, vm.this_value(), "strike"sv, {}, Value());
- }
- // B.2.2.13 String.prototype.sub ( ), https://tc39.es/ecma262/#sec-string.prototype.sub
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::sub)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "sub", "", "").
- return create_html(vm, vm.this_value(), "sub"sv, {}, Value());
- }
- // B.2.2.14 String.prototype.sup ( ), https://tc39.es/ecma262/#sec-string.prototype.sup
- JS_DEFINE_NATIVE_FUNCTION(StringPrototype::sup)
- {
- // 1. Let S be the this value.
- // 2. Return ? CreateHTML(S, "sup", "", "").
- return create_html(vm, vm.this_value(), "sup"sv, {}, Value());
- }
- }
|