1 /*
2 * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development 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/js_segment_iterator.h"
17
18 #include <cstring>
19
20 #include "ecmascript/js_iterator.h"
21 #include "ecmascript/js_segments.h"
22 #include "ecmascript/object_factory-inl.h"
23
24 namespace panda::ecmascript {
25
SetIcuBreakIterator(JSThread * thread,const JSHandle<JSSegmentIterator> & iterator,icu::BreakIterator * icuBreakIterator,const NativePointerCallback & callback)26 void JSSegmentIterator::SetIcuBreakIterator(JSThread *thread, const JSHandle<JSSegmentIterator> &iterator,
27 icu::BreakIterator* icuBreakIterator, const NativePointerCallback &callback)
28 {
29 EcmaVM *ecmaVm = thread->GetEcmaVM();
30 ObjectFactory *factory = ecmaVm->GetFactory();
31
32 ASSERT(icuBreakIterator != nullptr);
33 JSTaggedValue data = iterator->GetIcuField();
34 if (data.IsJSNativePointer()) {
35 JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject());
36 native->ResetExternalPointer(thread, icuBreakIterator);
37 return;
38 }
39 JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(icuBreakIterator, callback);
40 iterator->SetIcuField(thread, pointer.GetTaggedValue());
41 }
42
SetUString(JSThread * thread,const JSHandle<JSSegmentIterator> & iterator,icu::UnicodeString * icuUnicodeString,const NativePointerCallback & callback)43 void JSSegmentIterator::SetUString(JSThread *thread, const JSHandle<JSSegmentIterator> &iterator,
44 icu::UnicodeString* icuUnicodeString, const NativePointerCallback &callback)
45 {
46 EcmaVM *ecmaVm = thread->GetEcmaVM();
47 ObjectFactory *factory = ecmaVm->GetFactory();
48
49 ASSERT(icuUnicodeString != nullptr);
50 JSTaggedValue data = iterator->GetUnicodeString();
51 if (data.IsJSNativePointer()) {
52 JSNativePointer *native = JSNativePointer::Cast(data.GetTaggedObject());
53 native->ResetExternalPointer(thread, icuUnicodeString);
54 return;
55 }
56 JSHandle<JSNativePointer> pointer = factory->NewJSNativePointer(icuUnicodeString, callback);
57 iterator->SetUnicodeString(thread, pointer.GetTaggedValue());
58 }
59
CreateSegmentIterator(JSThread * thread,icu::BreakIterator * icuBreakIterator,const JSHandle<EcmaString> & string,GranularityOption granularity)60 JSHandle<JSSegmentIterator> JSSegmentIterator::CreateSegmentIterator(JSThread *thread,
61 icu::BreakIterator* icuBreakIterator, const JSHandle<EcmaString> &string, GranularityOption granularity)
62 {
63 // 1. Let internalSlotsList be « [[IteratingSegmenter]], [[IteratedString]],
64 // [[IteratedStringNextSegmentCodeUnitIndex]] ».
65 // 2. Let iterator be OrdinaryObjectCreate(%SegmentIteratorPrototype%, internalSlotsList).
66 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
67 JSHandle<JSFunction> segIterCtor(env->GetSegmentIterator());
68 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
69 JSHandle<JSSegmentIterator> iterator(factory->NewJSObjectByConstructor(segIterCtor));
70 icuBreakIterator = icuBreakIterator->clone();
71 // 5. Set iterator.[[IteratedStringNextSegmentCodeUnitIndex]] to 0.
72 icuBreakIterator->first();
73 icu::UnicodeString* uString = new icu::UnicodeString();
74 icuBreakIterator->getText().getText(*uString);
75 // 3. Set iterator.[[IteratingSegmenter]] to segmenter.
76 SetIcuBreakIterator(thread, iterator, icuBreakIterator, JSSegmentIterator::FreeIcuBreakIterator);
77 iterator->SetGranularity(granularity);
78 // 4. Set iterator.[[IteratedString]] to string.
79 iterator->SetIteratedString(thread, string);
80 SetUString(thread, iterator, uString, JSSegmentIterator::FreeUString);
81 // 6. Return iterator.
82 return iterator;
83 }
84
Next(JSThread * thread,const JSHandle<JSSegmentIterator> & iterator)85 JSTaggedValue JSSegmentIterator::Next(JSThread *thread, const JSHandle<JSSegmentIterator> &iterator)
86 {
87 icu::BreakIterator* icuBreakIterator = iterator->GetIcuBreakIterator();
88 // 5. Let startIndex be iterator.[[IteratedStringNextSegmentCodeUnitIndex]].
89 int32_t startIndex = icuBreakIterator->current();
90 // 6. Let endIndex be ! FindBoundary(segmenter, string, startIndex, after).
91 int32_t endIndex = icuBreakIterator->next();
92 // 7. If endIndex is not finite, then
93 if (endIndex == icu::BreakIterator::DONE) {
94 // a. Return CreateIterResultObject(undefined, true).
95 JSHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
96 return JSIterator::CreateIterResultObject(thread, result, true).GetTaggedValue();
97 }
98
99 // 8. Set iterator.[[IteratedStringNextSegmentCodeUnitIndex]] to endIndex.
100 // 9. Let segmentData be ! CreateSegmentDataObject(segmenter, string, startIndex, endIndex).
101 icu::UnicodeString unicodeString;
102 icuBreakIterator->getText().getText(unicodeString);
103 JSHandle<JSObject> segmentData = JSSegments::CreateSegmentDataObject(thread, iterator->GetGranularity(),
104 icuBreakIterator, JSHandle<EcmaString>(thread, iterator->GetIteratedString()),
105 unicodeString, startIndex, endIndex);
106
107 // 10. Return CreateIterResultObject(segmentData, false).
108 return JSIterator::CreateIterResultObject(thread, JSHandle<JSTaggedValue>::Cast(segmentData), false)
109 .GetTaggedValue();
110 }
111 } // namespace panda::ecmascript
112