• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 #include "ecmascript/ecma_string-inl.h"
19 #include "ecmascript/ecma_string_table.h"
20 #include "ecmascript/js_iterator.h"
21 #include "ecmascript/js_string_iterator.h"
22 
23 namespace panda::ecmascript::builtins {
Next(EcmaRuntimeCallInfo * argv)24 JSTaggedValue BuiltinsStringIterator::Next(EcmaRuntimeCallInfo *argv)
25 {
26     ASSERT(argv);
27     BUILTINS_API_TRACE(argv->GetThread(), StringIterator, Next);
28     JSThread *thread = argv->GetThread();
29     [[maybe_unused]] EcmaHandleScope handleScope(thread);
30     // 1. Let O be the this value.
31     JSHandle<JSTaggedValue> thisValue = GetThis(argv);
32     return NextInternal(thread, thisValue);
33 }
34 
NextInternal(JSThread * thread,JSHandle<JSTaggedValue> thisValue)35 JSTaggedValue BuiltinsStringIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisValue)
36 {
37     // 2. If Type(O) is not Object, throw a TypeError exception.
38     // 3. If O does not have all of the internal slots of an String Iterator Instance (21.1.5.3),
39     // throw a TypeError exception.
40     if (!thisValue->IsStringIterator()) {
41         THROW_TYPE_ERROR_AND_RETURN(thread, "is not StringIterator", JSTaggedValue::Exception());
42     }
43     // 4. Let s be the value of the [[IteratedString]] internal slot of O.
44     JSHandle<JSTaggedValue> string(thread, thisValue.GetObject<JSStringIterator>()->GetIteratedString(thread));
45     // 5. If s is undefined, return CreateIterResultObject(undefined, true).
46     if (string->IsUndefined()) {
47         return JSIterator::CreateIterResultObject(thread, string, true).GetTaggedValue();
48     }
49     // 6. Let position be the value of the [[StringIteratorNextIndex]] internal slot of O.
50     uint32_t position = thisValue.GetObject<JSStringIterator>()->GetStringIteratorNextIndex();
51 
52     // 7. Let len be the number of elements in s.
53     uint32_t len = EcmaStringAccessor(string.GetObject<EcmaString>()).GetLength();
54     // If position ≥ len, then
55     // a. Set the value of the [[IteratedString]] internal slot of O to
56     // b. Return CreateIterResultObject(undefined, true).
57     if (position >= len) {
58         thisValue.GetObject<JSStringIterator>()->SetIteratedString(thread, JSTaggedValue::Undefined());
59         JSHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
60         return JSIterator::CreateIterResultObject(thread, result, true).GetTaggedValue();
61     }
62 
63     // 9. Let first be the code unit value at index position in s.
64     uint16_t first = EcmaStringAccessor(string.GetObject<EcmaString>()).Get<false>(thread, position);
65     JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
66     uint32_t resultSize = 1;
67     // 10. If first < 0xD800 or first > 0xDBFF or position+1 = len, let resultString be the string consisting of the
68     // single code unit first.
69     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
70     if (position + 1 == len || first < common::utf_helper::DECODE_LEAD_LOW ||
71         first > common::utf_helper::DECODE_LEAD_HIGH) {
72         if (EcmaStringAccessor::CanBeCompressed(&first, 1)) {
73             JSHandle<SingleCharTable> singleCharTable(thread, thread->GetSingleCharTable());
74             result.Update(singleCharTable->GetStringFromSingleCharTable(thread, first));
75         } else {
76             std::vector<uint16_t> resultString {first, 0x0};
77             result.Update(factory->NewFromUtf16(resultString.data(), 1).GetTaggedValue());
78         }
79     } else {
80         // 11. Else,
81         // a. Let second be the code unit value at index position+1 in the String S.
82         // b. If second < 0xDC00 or second > 0xDFFF, let resultString be the string consisting of the single code unit
83         // first.
84         // c. Else, let resultString be the string consisting of the code unit first followed by the code unit second.
85         uint16_t second = EcmaStringAccessor(string.GetObject<EcmaString>()).Get<false>(thread, position + 1);
86         if (second < common::utf_helper::DECODE_TRAIL_LOW || second > common::utf_helper::DECODE_TRAIL_HIGH) {
87             std::vector<uint16_t> resultString {first, 0x0};
88             result.Update(factory->NewFromUtf16NotCompress(resultString.data(), 1).GetTaggedValue());
89         } else {
90             std::vector<uint16_t> resultString {first, second, 0x0};
91             result.Update(
92                 factory->NewFromUtf16NotCompress(resultString.data(), 2).GetTaggedValue());  // 2: two bytes
93             resultSize = 2;  // 2: 2 means that two bytes represent a character string
94         }
95     }
96     // 12. Let resultSize be the number of code units in resultString.
97     // 13. Set the value of the [[StringIteratorNextIndex]] internal slot of O to position+ resultSize.
98     thisValue.GetObject<JSStringIterator>()->SetStringIteratorNextIndex(position + resultSize);
99 
100     // 14. Return CreateIterResultObject(resultString, false).
101     return JSIterator::CreateIterResultObject(thread, result, false).GetTaggedValue();
102 }
103 }  // namespace panda::ecmascript::builtins
104