14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/builtins/builtins_string_iterator.h"
174514f5e3Sopenharmony_ci#include "ecmascript/ecma_string_table.h"
184514f5e3Sopenharmony_ci#include "ecmascript/js_iterator.h"
194514f5e3Sopenharmony_ci#include "ecmascript/js_string_iterator.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript::builtins {
224514f5e3Sopenharmony_ciJSTaggedValue BuiltinsStringIterator::Next(EcmaRuntimeCallInfo *argv)
234514f5e3Sopenharmony_ci{
244514f5e3Sopenharmony_ci    ASSERT(argv);
254514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), StringIterator, Next);
264514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
274514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
284514f5e3Sopenharmony_ci    // 1. Let O be the this value.
294514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> thisValue = GetThis(argv);
304514f5e3Sopenharmony_ci    return NextInternal(thread, thisValue);
314514f5e3Sopenharmony_ci}
324514f5e3Sopenharmony_ci
334514f5e3Sopenharmony_ciJSTaggedValue BuiltinsStringIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisValue)
344514f5e3Sopenharmony_ci{
354514f5e3Sopenharmony_ci    // 2. If Type(O) is not Object, throw a TypeError exception.
364514f5e3Sopenharmony_ci    // 3. If O does not have all of the internal slots of an String Iterator Instance (21.1.5.3),
374514f5e3Sopenharmony_ci    // throw a TypeError exception.
384514f5e3Sopenharmony_ci    if (!thisValue->IsStringIterator()) {
394514f5e3Sopenharmony_ci        THROW_TYPE_ERROR_AND_RETURN(thread, "is not StringIterator", JSTaggedValue::Exception());
404514f5e3Sopenharmony_ci    }
414514f5e3Sopenharmony_ci    // 4. Let s be the value of the [[IteratedString]] internal slot of O.
424514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> string(thread, thisValue.GetObject<JSStringIterator>()->GetIteratedString());
434514f5e3Sopenharmony_ci    // 5. If s is undefined, return CreateIterResultObject(undefined, true).
444514f5e3Sopenharmony_ci    if (string->IsUndefined()) {
454514f5e3Sopenharmony_ci        return JSIterator::CreateIterResultObject(thread, string, true).GetTaggedValue();
464514f5e3Sopenharmony_ci    }
474514f5e3Sopenharmony_ci    // 6. Let position be the value of the [[StringIteratorNextIndex]] internal slot of O.
484514f5e3Sopenharmony_ci    uint32_t position = thisValue.GetObject<JSStringIterator>()->GetStringIteratorNextIndex();
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ci    // 7. Let len be the number of elements in s.
514514f5e3Sopenharmony_ci    uint32_t len = EcmaStringAccessor(string.GetObject<EcmaString>()).GetLength();
524514f5e3Sopenharmony_ci    // If position ≥ len, then
534514f5e3Sopenharmony_ci    // a. Set the value of the [[IteratedString]] internal slot of O to
544514f5e3Sopenharmony_ci    // b. Return CreateIterResultObject(undefined, true).
554514f5e3Sopenharmony_ci    if (position >= len) {
564514f5e3Sopenharmony_ci        thisValue.GetObject<JSStringIterator>()->SetIteratedString(thread, JSTaggedValue::Undefined());
574514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
584514f5e3Sopenharmony_ci        return JSIterator::CreateIterResultObject(thread, result, true).GetTaggedValue();
594514f5e3Sopenharmony_ci    }
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ci    // 9. Let first be the code unit value at index position in s.
624514f5e3Sopenharmony_ci    uint16_t first = EcmaStringAccessor(string.GetObject<EcmaString>()).Get<false>(position);
634514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
644514f5e3Sopenharmony_ci    uint32_t resultSize = 1;
654514f5e3Sopenharmony_ci    // 10. If first < 0xD800 or first > 0xDBFF or position+1 = len, let resultString be the string consisting of the
664514f5e3Sopenharmony_ci    // single code unit first.
674514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
684514f5e3Sopenharmony_ci    if (position + 1 == len || first < base::utf_helper::DECODE_LEAD_LOW ||
694514f5e3Sopenharmony_ci        first > base::utf_helper::DECODE_LEAD_HIGH) {
704514f5e3Sopenharmony_ci        if (EcmaStringAccessor::CanBeCompressed(&first, 1)) {
714514f5e3Sopenharmony_ci            JSHandle<SingleCharTable> singleCharTable(thread, thread->GetSingleCharTable());
724514f5e3Sopenharmony_ci            result.Update(singleCharTable->GetStringFromSingleCharTable(first));
734514f5e3Sopenharmony_ci        } else {
744514f5e3Sopenharmony_ci            std::vector<uint16_t> resultString {first, 0x0};
754514f5e3Sopenharmony_ci            result.Update(factory->NewFromUtf16(resultString.data(), 1).GetTaggedValue());
764514f5e3Sopenharmony_ci        }
774514f5e3Sopenharmony_ci    } else {
784514f5e3Sopenharmony_ci        // 11. Else,
794514f5e3Sopenharmony_ci        // a. Let second be the code unit value at index position+1 in the String S.
804514f5e3Sopenharmony_ci        // b. If second < 0xDC00 or second > 0xDFFF, let resultString be the string consisting of the single code unit
814514f5e3Sopenharmony_ci        // first.
824514f5e3Sopenharmony_ci        // c. Else, let resultString be the string consisting of the code unit first followed by the code unit second.
834514f5e3Sopenharmony_ci        uint16_t second = EcmaStringAccessor(string.GetObject<EcmaString>()).Get<false>(position + 1);
844514f5e3Sopenharmony_ci        if (second < base::utf_helper::DECODE_TRAIL_LOW || second > base::utf_helper::DECODE_TRAIL_HIGH) {
854514f5e3Sopenharmony_ci            std::vector<uint16_t> resultString {first, 0x0};
864514f5e3Sopenharmony_ci            result.Update(factory->NewFromUtf16NotCompress(resultString.data(), 1).GetTaggedValue());
874514f5e3Sopenharmony_ci        } else {
884514f5e3Sopenharmony_ci            std::vector<uint16_t> resultString {first, second, 0x0};
894514f5e3Sopenharmony_ci            result.Update(
904514f5e3Sopenharmony_ci                factory->NewFromUtf16NotCompress(resultString.data(), 2).GetTaggedValue());  // 2: two bytes
914514f5e3Sopenharmony_ci            resultSize = 2;  // 2: 2 means that two bytes represent a character string
924514f5e3Sopenharmony_ci        }
934514f5e3Sopenharmony_ci    }
944514f5e3Sopenharmony_ci    // 12. Let resultSize be the number of code units in resultString.
954514f5e3Sopenharmony_ci    // 13. Set the value of the [[StringIteratorNextIndex]] internal slot of O to position+ resultSize.
964514f5e3Sopenharmony_ci    thisValue.GetObject<JSStringIterator>()->SetStringIteratorNextIndex(position + resultSize);
974514f5e3Sopenharmony_ci
984514f5e3Sopenharmony_ci    // 14. Return CreateIterResultObject(resultString, false).
994514f5e3Sopenharmony_ci    return JSIterator::CreateIterResultObject(thread, result, false).GetTaggedValue();
1004514f5e3Sopenharmony_ci}
1014514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::builtins
102