/* * Copyright (c) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/containers/containers_linked_list.h" #include "ecmascript/containers/containers_errors.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_api/js_api_linked_list.h" #include "ecmascript/js_api/js_api_linked_list_iterator.h" #include "ecmascript/js_function.h" #include "ecmascript/object_factory.h" #include "ecmascript/tagged_array-inl.h" #include "ecmascript/tagged_list.h" namespace panda::ecmascript::containers { JSTaggedValue ContainersLinkedList::LinkedListConstructor(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Constructor); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newTarget = GetNewTarget(argv); if (newTarget->IsUndefined()) { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR, "The LinkedList's constructor cannot be directly invoked"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle constructor = GetConstructor(argv); JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle linkedList = JSHandle::Cast(obj); JSTaggedValue doubleList = TaggedDoubleList::Create(thread); linkedList->SetDoubleList(thread, doubleList); return linkedList.GetTaggedValue(); } JSTaggedValue ContainersLinkedList::Add(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Add); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The add method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle value = GetCallArg(argv, 0); JSHandle jsAPILinkedList = JSHandle::Cast(self); JSAPILinkedList::Add(thread, jsAPILinkedList, value); return JSTaggedValue::True(); } JSTaggedValue ContainersLinkedList::AddFirst(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, AddFirst); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The addFirst method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle value = GetCallArg(argv, 0); JSHandle jsAPILinkedList = JSHandle::Cast(self); JSAPILinkedList::AddFirst(thread, jsAPILinkedList, value); return JSTaggedValue::True(); } JSTaggedValue ContainersLinkedList::GetFirst(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, GetFirst); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getFirst method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); return jsAPILinkedList->GetFirst(); } JSTaggedValue ContainersLinkedList::GetLast(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, GetLast); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getLast method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); return jsAPILinkedList->GetLast(); } JSTaggedValue ContainersLinkedList::Length(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Length); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The length method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); return JSTaggedValue(jsAPILinkedList->Length()); } JSTaggedValue ContainersLinkedList::Insert(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Insert); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The insert method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle value = GetCallArg(argv, 1); JSHandle index = GetCallArg(argv, 0); if (!index->IsInteger()) { JSHandle result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue result = JSAPILinkedList::Insert(thread, jsAPILinkedList, value, index->GetInt()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } JSTaggedValue ContainersLinkedList::Clear(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Clear); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The clear method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); jsAPILinkedList->Clear(thread); return JSTaggedValue::Undefined(); } JSTaggedValue ContainersLinkedList::Clone(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Clone); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The clone method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSHandle newLinkedList = JSAPILinkedList::Clone(thread, jsAPILinkedList); return newLinkedList.GetTaggedValue(); } JSTaggedValue ContainersLinkedList::Has(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Has); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The has method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSHandle element = GetCallArg(argv, 0); return GetTaggedBoolean(jsAPILinkedList->Has(element.GetTaggedValue())); } JSTaggedValue ContainersLinkedList::Get(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Get); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The get method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSHandle index = GetCallArg(argv, 0); if (!index->IsInteger()) { JSHandle result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } return jsAPILinkedList->Get(index->GetInt()); } JSTaggedValue ContainersLinkedList::GetIndexOf(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, GetIndexOf); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getIndexOf method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSHandle element = GetCallArg(argv, 0); return jsAPILinkedList->GetIndexOf(element.GetTaggedValue()); } JSTaggedValue ContainersLinkedList::GetLastIndexOf(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, GetLastIndexOf); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The getLastIndexOf method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSHandle element(GetCallArg(argv, 0)); return jsAPILinkedList->GetLastIndexOf(element.GetTaggedValue()); } JSTaggedValue ContainersLinkedList::RemoveByIndex(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, RemoveByIndex); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The removeByIndex method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index = GetCallArg(argv, 0); if (!index->IsInteger()) { JSHandle result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue nodeData = JSAPILinkedList::RemoveByIndex(thread, jsAPILinkedList, index->GetInt()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return nodeData; } JSTaggedValue ContainersLinkedList::Remove(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Remove); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The remove method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); JSHandle jsAPILinkedList = JSHandle::Cast(self); return jsAPILinkedList->Remove(thread, element.GetTaggedValue()); } JSTaggedValue ContainersLinkedList::RemoveFirst(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, RemoveFirst); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The removeFirst method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue lastValue = JSAPILinkedList::RemoveFirst(thread, jsAPILinkedList); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return lastValue; } JSTaggedValue ContainersLinkedList::RemoveFirstFound(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, RemoveFirstFound); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The removeFirstFound method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue result = JSAPILinkedList::RemoveFirstFound(thread, jsAPILinkedList, element.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } JSTaggedValue ContainersLinkedList::RemoveLast(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, RemoveLast); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The removeLast method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue lastValue = JSAPILinkedList::RemoveLast(thread, jsAPILinkedList); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return lastValue; } JSTaggedValue ContainersLinkedList::RemoveLastFound(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, RemoveLastFound); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The removeLastFound method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle element = GetCallArg(argv, 0); JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue result = JSAPILinkedList::RemoveLastFound(thread, jsAPILinkedList, element.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } JSTaggedValue ContainersLinkedList::Set(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, Set); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The set method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle index = GetCallArg(argv, 0); JSHandle element = GetCallArg(argv, 1); if (!index->IsInteger()) { JSHandle result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); CString errorMsg = "The type of \"index\" must be number. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle jsAPILinkedList = JSHandle::Cast(self); JSTaggedValue oldValue = JSAPILinkedList::Set(thread, jsAPILinkedList, index->GetInt(), element); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return oldValue; } JSTaggedValue ContainersLinkedList::ConvertToArray(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, ConvertToArray); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); if (!self->IsJSAPILinkedList()) { if (self->IsJSProxy() && JSHandle::Cast(self)->GetTarget().IsJSAPILinkedList()) { self = JSHandle(thread, JSHandle::Cast(self)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The convertToArray method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle jsAPILinkedList = JSHandle::Cast(self); return JSAPILinkedList::ConvertToArray(thread, jsAPILinkedList); } JSTaggedValue ContainersLinkedList::ForEach(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, ForEach); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle thisHandle = GetThis(argv); if (!thisHandle->IsJSAPILinkedList()) { if (thisHandle->IsJSProxy() && JSHandle::Cast(thisHandle)->GetTarget().IsJSAPILinkedList()) { thisHandle = JSHandle(thread, JSHandle::Cast(thisHandle)->GetTarget()); } else { JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, "The forEach method cannot be bound"); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } } JSHandle callbackFnHandle(GetCallArg(argv, 0)); if (!callbackFnHandle->IsCallable()) { JSHandle result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue()); CString errorMsg = "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result); JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); } JSHandle thisArgHandle = GetCallArg(argv, 1); JSHandle linkedList = JSHandle::Cast(thisHandle); JSHandle doubleList(thread, linkedList->GetDoubleList()); int length = linkedList->Length(); int index = 0; const uint32_t argsLength = 3; // 3: «kValue, k, O» JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); int valueNode = TaggedDoubleList::ELEMENTS_START_INDEX; while (index < length) { valueNode = doubleList->GetNextDataIndex(valueNode); JSTaggedValue value = doubleList->GetElement(valueNode); EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); info->SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue()); JSTaggedValue funcResult = JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); index++; } return JSTaggedValue::Undefined(); } JSTaggedValue ContainersLinkedList::GetIteratorObj(EcmaRuntimeCallInfo *argv) { ASSERT(argv != nullptr); JSThread *thread = argv->GetThread(); BUILTINS_API_TRACE(thread, LinkedList, GetIteratorObj); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle self = GetThis(argv); JSHandle iter = JSAPILinkedListIterator::CreateLinkedListIterator(thread, self); return iter.GetTaggedValue(); } } // namespace panda::ecmascript::containers