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 24namespace panda::ecmascript { 25 26void 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 43void 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 60JSHandle<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 85JSTaggedValue 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