1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/builtins/builtins_string_iterator.h" 17#include "ecmascript/ecma_string_table.h" 18#include "ecmascript/js_iterator.h" 19#include "ecmascript/js_string_iterator.h" 20 21namespace panda::ecmascript::builtins { 22JSTaggedValue BuiltinsStringIterator::Next(EcmaRuntimeCallInfo *argv) 23{ 24 ASSERT(argv); 25 BUILTINS_API_TRACE(argv->GetThread(), StringIterator, Next); 26 JSThread *thread = argv->GetThread(); 27 [[maybe_unused]] EcmaHandleScope handleScope(thread); 28 // 1. Let O be the this value. 29 JSHandle<JSTaggedValue> thisValue = GetThis(argv); 30 return NextInternal(thread, thisValue); 31} 32 33JSTaggedValue BuiltinsStringIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisValue) 34{ 35 // 2. If Type(O) is not Object, throw a TypeError exception. 36 // 3. If O does not have all of the internal slots of an String Iterator Instance (21.1.5.3), 37 // throw a TypeError exception. 38 if (!thisValue->IsStringIterator()) { 39 THROW_TYPE_ERROR_AND_RETURN(thread, "is not StringIterator", JSTaggedValue::Exception()); 40 } 41 // 4. Let s be the value of the [[IteratedString]] internal slot of O. 42 JSHandle<JSTaggedValue> string(thread, thisValue.GetObject<JSStringIterator>()->GetIteratedString()); 43 // 5. If s is undefined, return CreateIterResultObject(undefined, true). 44 if (string->IsUndefined()) { 45 return JSIterator::CreateIterResultObject(thread, string, true).GetTaggedValue(); 46 } 47 // 6. Let position be the value of the [[StringIteratorNextIndex]] internal slot of O. 48 uint32_t position = thisValue.GetObject<JSStringIterator>()->GetStringIteratorNextIndex(); 49 50 // 7. Let len be the number of elements in s. 51 uint32_t len = EcmaStringAccessor(string.GetObject<EcmaString>()).GetLength(); 52 // If position ≥ len, then 53 // a. Set the value of the [[IteratedString]] internal slot of O to 54 // b. Return CreateIterResultObject(undefined, true). 55 if (position >= len) { 56 thisValue.GetObject<JSStringIterator>()->SetIteratedString(thread, JSTaggedValue::Undefined()); 57 JSHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 58 return JSIterator::CreateIterResultObject(thread, result, true).GetTaggedValue(); 59 } 60 61 // 9. Let first be the code unit value at index position in s. 62 uint16_t first = EcmaStringAccessor(string.GetObject<EcmaString>()).Get<false>(position); 63 JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined()); 64 uint32_t resultSize = 1; 65 // 10. If first < 0xD800 or first > 0xDBFF or position+1 = len, let resultString be the string consisting of the 66 // single code unit first. 67 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 68 if (position + 1 == len || first < base::utf_helper::DECODE_LEAD_LOW || 69 first > base::utf_helper::DECODE_LEAD_HIGH) { 70 if (EcmaStringAccessor::CanBeCompressed(&first, 1)) { 71 JSHandle<SingleCharTable> singleCharTable(thread, thread->GetSingleCharTable()); 72 result.Update(singleCharTable->GetStringFromSingleCharTable(first)); 73 } else { 74 std::vector<uint16_t> resultString {first, 0x0}; 75 result.Update(factory->NewFromUtf16(resultString.data(), 1).GetTaggedValue()); 76 } 77 } else { 78 // 11. Else, 79 // a. Let second be the code unit value at index position+1 in the String S. 80 // b. If second < 0xDC00 or second > 0xDFFF, let resultString be the string consisting of the single code unit 81 // first. 82 // c. Else, let resultString be the string consisting of the code unit first followed by the code unit second. 83 uint16_t second = EcmaStringAccessor(string.GetObject<EcmaString>()).Get<false>(position + 1); 84 if (second < base::utf_helper::DECODE_TRAIL_LOW || second > base::utf_helper::DECODE_TRAIL_HIGH) { 85 std::vector<uint16_t> resultString {first, 0x0}; 86 result.Update(factory->NewFromUtf16NotCompress(resultString.data(), 1).GetTaggedValue()); 87 } else { 88 std::vector<uint16_t> resultString {first, second, 0x0}; 89 result.Update( 90 factory->NewFromUtf16NotCompress(resultString.data(), 2).GetTaggedValue()); // 2: two bytes 91 resultSize = 2; // 2: 2 means that two bytes represent a character string 92 } 93 } 94 // 12. Let resultSize be the number of code units in resultString. 95 // 13. Set the value of the [[StringIteratorNextIndex]] internal slot of O to position+ resultSize. 96 thisValue.GetObject<JSStringIterator>()->SetStringIteratorNextIndex(position + resultSize); 97 98 // 14. Return CreateIterResultObject(resultString, false). 99 return JSIterator::CreateIterResultObject(thread, result, false).GetTaggedValue(); 100} 101} // namespace panda::ecmascript::builtins 102