1 /*
2 * Copyright (c) 2022 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/js_api/js_api_hashmap_iterator.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/global_env.h"
20 #include "ecmascript/js_api/js_api_hasharray_iterator.h"
21
22 namespace panda::ecmascript {
23 using BuiltinsBase = base::BuiltinsBase;
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
Next(EcmaRuntimeCallInfo * argv)26 JSTaggedValue JSAPIHashMapIterator::Next(EcmaRuntimeCallInfo *argv)
27 {
28 ASSERT(argv);
29 JSThread *thread = argv->GetThread();
30 [[maybe_unused]] EcmaHandleScope handleScope(thread);
31 JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
32
33 if (!input->IsJSAPIHashMapIterator()) {
34 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
35 "The Symbol.iterator method cannot be bound");
36 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
37 }
38 JSHandle<JSAPIHashMapIterator> iter = JSHandle<JSAPIHashMapIterator>::Cast(input);
39 JSHandle<JSTaggedValue> iteratedHashMap(thread, iter->GetIteratedHashMap(thread));
40 // If m is undefined, return undefinedIteratorResult.
41 if (iteratedHashMap->IsUndefined()) {
42 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
43 return env->GetUndefinedIteratorResult().GetTaggedValue();
44 }
45 JSHandle<TaggedHashArray> tableArr(thread, JSHandle<JSAPIHashMap>::Cast(iteratedHashMap)->GetTable(thread));
46 uint32_t tableLength = tableArr->GetLength();
47 uint32_t index = iter->GetNextIndex();
48
49 JSMutableHandle<TaggedQueue> queue(thread, iter->GetTaggedQueue(thread));
50 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
51 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
52 JSMutableHandle<TaggedNode> currentNode(thread, JSTaggedValue::Undefined());
53
54 IterationKind itemKind = iter->GetIterationKind();
55 while (index < tableLength) {
56 currentNode.Update(JSAPIHashArrayIterator::GetCurrentNode<JSAPIHashMapIterator>(thread, iter, queue, tableArr));
57 if (currentNode.GetTaggedValue().IsHole()) {
58 iter->SetNextIndex(++index);
59 continue;
60 }
61 JSTaggedValue key = currentNode->GetKey(thread);
62 keyHandle.Update(key);
63 if (itemKind == IterationKind::KEY) {
64 return JSIterator::CreateIterResultObject(thread, keyHandle, false).GetTaggedValue();
65 }
66 valueHandle.Update(currentNode->GetValue(thread));
67 if (itemKind == IterationKind::VALUE) {
68 return JSIterator::CreateIterResultObject(thread, valueHandle, false).GetTaggedValue();
69 }
70 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
71 JSHandle<TaggedArray> array = factory->NewTaggedArray(2); // 2 means the length of array
72 array->Set(thread, 0, keyHandle);
73 array->Set(thread, 1, valueHandle);
74 JSHandle<JSTaggedValue> keyAndValue(JSArray::CreateArrayFromList(thread, array));
75 return JSIterator::CreateIterResultObject(thread, keyAndValue, false).GetTaggedValue();
76 }
77 // Set [[IteratedMap]] to undefined.
78 iter->SetIteratedHashMap(thread, JSTaggedValue::Undefined());
79 JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
80 return env->GetUndefinedIteratorResult().GetTaggedValue();
81 }
82
CreateHashMapIterator(JSThread * thread,const JSHandle<JSTaggedValue> & obj,IterationKind kind)83 JSHandle<JSTaggedValue> JSAPIHashMapIterator::CreateHashMapIterator(JSThread *thread,
84 const JSHandle<JSTaggedValue> &obj,
85 IterationKind kind)
86 {
87 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
88 if (!obj->IsJSAPIHashMap()) {
89 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
90 "The Symbol.iterator method cannot be bound");
91 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSHandle<JSTaggedValue>(thread, JSTaggedValue::Exception()));
92 }
93 JSHandle<JSTaggedValue> iter(factory->NewJSAPIHashMapIterator(JSHandle<JSAPIHashMap>(obj), kind));
94 return iter;
95 }
96 } // namespace panda::ecmascript