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/containers/containers_linked_list.h" 17 18#include "ecmascript/containers/containers_errors.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/js_api/js_api_linked_list.h" 21#include "ecmascript/js_api/js_api_linked_list_iterator.h" 22#include "ecmascript/js_function.h" 23 24namespace panda::ecmascript::containers { 25JSTaggedValue ContainersLinkedList::LinkedListConstructor(EcmaRuntimeCallInfo *argv) 26{ 27 ASSERT(argv != nullptr); 28 JSThread *thread = argv->GetThread(); 29 BUILTINS_API_TRACE(thread, LinkedList, Constructor); 30 [[maybe_unused]] EcmaHandleScope handleScope(thread); 31 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 32 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 33 if (newTarget->IsUndefined()) { 34 JSTaggedValue error = 35 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR, 36 "The LinkedList's constructor cannot be directly invoked"); 37 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 38 } 39 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 40 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 41 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 42 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(obj); 43 JSTaggedValue doubleList = TaggedDoubleList::Create(thread); 44 linkedList->SetDoubleList(thread, doubleList); 45 return linkedList.GetTaggedValue(); 46} 47 48JSTaggedValue ContainersLinkedList::Add(EcmaRuntimeCallInfo *argv) 49{ 50 ASSERT(argv != nullptr); 51 JSThread *thread = argv->GetThread(); 52 BUILTINS_API_TRACE(thread, LinkedList, Add); 53 [[maybe_unused]] EcmaHandleScope handleScope(thread); 54 JSHandle<JSTaggedValue> self = GetThis(argv); 55 if (!self->IsJSAPILinkedList()) { 56 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 57 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 58 } else { 59 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 60 "The add method cannot be bound"); 61 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 62 } 63 } 64 65 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 66 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 67 JSAPILinkedList::Add(thread, jsAPILinkedList, value); 68 return JSTaggedValue::True(); 69} 70 71JSTaggedValue ContainersLinkedList::AddFirst(EcmaRuntimeCallInfo *argv) 72{ 73 ASSERT(argv != nullptr); 74 JSThread *thread = argv->GetThread(); 75 BUILTINS_API_TRACE(thread, LinkedList, AddFirst); 76 [[maybe_unused]] EcmaHandleScope handleScope(thread); 77 JSHandle<JSTaggedValue> self = GetThis(argv); 78 if (!self->IsJSAPILinkedList()) { 79 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 80 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 81 } else { 82 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 83 "The addFirst method cannot be bound"); 84 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 85 } 86 } 87 88 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 89 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 90 JSAPILinkedList::AddFirst(thread, jsAPILinkedList, value); 91 return JSTaggedValue::True(); 92} 93 94JSTaggedValue ContainersLinkedList::GetFirst(EcmaRuntimeCallInfo *argv) 95{ 96 ASSERT(argv != nullptr); 97 JSThread *thread = argv->GetThread(); 98 BUILTINS_API_TRACE(thread, LinkedList, GetFirst); 99 [[maybe_unused]] EcmaHandleScope handleScope(thread); 100 JSHandle<JSTaggedValue> self = GetThis(argv); 101 if (!self->IsJSAPILinkedList()) { 102 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 103 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 104 } else { 105 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 106 "The getFirst method cannot be bound"); 107 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 108 } 109 } 110 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 111 return jsAPILinkedList->GetFirst(); 112} 113 114JSTaggedValue ContainersLinkedList::GetLast(EcmaRuntimeCallInfo *argv) 115{ 116 ASSERT(argv != nullptr); 117 JSThread *thread = argv->GetThread(); 118 BUILTINS_API_TRACE(thread, LinkedList, GetLast); 119 [[maybe_unused]] EcmaHandleScope handleScope(thread); 120 JSHandle<JSTaggedValue> self = GetThis(argv); 121 if (!self->IsJSAPILinkedList()) { 122 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 123 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 124 } else { 125 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 126 "The getLast method cannot be bound"); 127 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 128 } 129 } 130 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 131 return jsAPILinkedList->GetLast(); 132} 133 134JSTaggedValue ContainersLinkedList::Length(EcmaRuntimeCallInfo *argv) 135{ 136 ASSERT(argv != nullptr); 137 JSThread *thread = argv->GetThread(); 138 BUILTINS_API_TRACE(thread, LinkedList, Length); 139 [[maybe_unused]] EcmaHandleScope handleScope(thread); 140 JSHandle<JSTaggedValue> self = GetThis(argv); 141 if (!self->IsJSAPILinkedList()) { 142 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 143 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 144 } else { 145 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 146 "The getLength method cannot be bound"); 147 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 148 } 149 } 150 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 151 return JSTaggedValue(jsAPILinkedList->Length()); 152} 153 154JSTaggedValue ContainersLinkedList::Insert(EcmaRuntimeCallInfo *argv) 155{ 156 ASSERT(argv != nullptr); 157 JSThread *thread = argv->GetThread(); 158 BUILTINS_API_TRACE(thread, LinkedList, Insert); 159 [[maybe_unused]] EcmaHandleScope handleScope(thread); 160 JSHandle<JSTaggedValue> self = GetThis(argv); 161 162 if (!self->IsJSAPILinkedList()) { 163 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 164 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 165 } else { 166 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 167 "The insert method cannot be bound"); 168 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 169 } 170 } 171 172 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1); 173 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0); 174 175 if (index->IsDouble()) { 176 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 177 } 178 if (!index->IsInt()) { 179 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); 180 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 181 CString errorMsg = 182 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 183 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 184 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 185 } 186 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 187 JSTaggedValue result = 188 JSAPILinkedList::Insert(thread, jsAPILinkedList, value, index->GetInt()); 189 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 190 return result; 191} 192 193JSTaggedValue ContainersLinkedList::Clear(EcmaRuntimeCallInfo *argv) 194{ 195 ASSERT(argv != nullptr); 196 JSThread *thread = argv->GetThread(); 197 BUILTINS_API_TRACE(thread, LinkedList, Clear); 198 [[maybe_unused]] EcmaHandleScope handleScope(thread); 199 JSHandle<JSTaggedValue> self = GetThis(argv); 200 if (!self->IsJSAPILinkedList()) { 201 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 202 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 203 } else { 204 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 205 "The clear method cannot be bound"); 206 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 207 } 208 } 209 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 210 jsAPILinkedList->Clear(thread); 211 return JSTaggedValue::Undefined(); 212} 213 214JSTaggedValue ContainersLinkedList::Clone(EcmaRuntimeCallInfo *argv) 215{ 216 ASSERT(argv != nullptr); 217 JSThread *thread = argv->GetThread(); 218 BUILTINS_API_TRACE(thread, LinkedList, Clone); 219 [[maybe_unused]] EcmaHandleScope handleScope(thread); 220 JSHandle<JSTaggedValue> self = GetThis(argv); 221 222 if (!self->IsJSAPILinkedList()) { 223 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 224 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 225 } else { 226 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 227 "The clone method cannot be bound"); 228 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 229 } 230 } 231 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 232 JSHandle<JSAPILinkedList> newLinkedList = JSAPILinkedList::Clone(thread, jsAPILinkedList); 233 return newLinkedList.GetTaggedValue(); 234} 235 236JSTaggedValue ContainersLinkedList::Has(EcmaRuntimeCallInfo *argv) 237{ 238 ASSERT(argv != nullptr); 239 JSThread *thread = argv->GetThread(); 240 BUILTINS_API_TRACE(thread, LinkedList, Has); 241 [[maybe_unused]] EcmaHandleScope handleScope(thread); 242 JSHandle<JSTaggedValue> self = GetThis(argv); 243 if (!self->IsJSAPILinkedList()) { 244 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 245 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 246 } else { 247 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 248 "The has method cannot be bound"); 249 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 250 } 251 } 252 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 253 JSHandle<JSTaggedValue> element = GetCallArg(argv, 0); 254 return GetTaggedBoolean(jsAPILinkedList->Has(element.GetTaggedValue())); 255} 256 257JSTaggedValue ContainersLinkedList::Get(EcmaRuntimeCallInfo *argv) 258{ 259 ASSERT(argv != nullptr); 260 JSThread *thread = argv->GetThread(); 261 BUILTINS_API_TRACE(thread, LinkedList, Get); 262 [[maybe_unused]] EcmaHandleScope handleScope(thread); 263 JSHandle<JSTaggedValue> self = GetThis(argv); 264 if (!self->IsJSAPILinkedList()) { 265 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 266 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 267 } else { 268 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 269 "The get method cannot be bound"); 270 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 271 } 272 } 273 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 274 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0); 275 if (index->IsDouble()) { 276 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 277 } 278 if (!index->IsInt()) { 279 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); 280 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 281 CString errorMsg = 282 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 283 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 284 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 285 } 286 return jsAPILinkedList->Get(index->GetInt()); 287} 288 289JSTaggedValue ContainersLinkedList::GetIndexOf(EcmaRuntimeCallInfo *argv) 290{ 291 ASSERT(argv != nullptr); 292 JSThread *thread = argv->GetThread(); 293 BUILTINS_API_TRACE(thread, LinkedList, GetIndexOf); 294 [[maybe_unused]] EcmaHandleScope handleScope(thread); 295 JSHandle<JSTaggedValue> self = GetThis(argv); 296 if (!self->IsJSAPILinkedList()) { 297 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 298 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 299 } else { 300 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 301 "The getIndexOf method cannot be bound"); 302 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 303 } 304 } 305 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 306 JSHandle<JSTaggedValue> element = GetCallArg(argv, 0); 307 return jsAPILinkedList->GetIndexOf(element.GetTaggedValue()); 308} 309 310JSTaggedValue ContainersLinkedList::GetLastIndexOf(EcmaRuntimeCallInfo *argv) 311{ 312 ASSERT(argv != nullptr); 313 JSThread *thread = argv->GetThread(); 314 BUILTINS_API_TRACE(thread, LinkedList, GetLastIndexOf); 315 [[maybe_unused]] EcmaHandleScope handleScope(thread); 316 JSHandle<JSTaggedValue> self = GetThis(argv); 317 if (!self->IsJSAPILinkedList()) { 318 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 319 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 320 } else { 321 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 322 "The getLastIndexOf method cannot be bound"); 323 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 324 } 325 } 326 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 327 JSHandle<JSTaggedValue> element(GetCallArg(argv, 0)); 328 return jsAPILinkedList->GetLastIndexOf(element.GetTaggedValue()); 329} 330 331JSTaggedValue ContainersLinkedList::RemoveByIndex(EcmaRuntimeCallInfo *argv) 332{ 333 ASSERT(argv != nullptr); 334 JSThread *thread = argv->GetThread(); 335 BUILTINS_API_TRACE(thread, LinkedList, RemoveByIndex); 336 [[maybe_unused]] EcmaHandleScope handleScope(thread); 337 JSHandle<JSTaggedValue> self = GetThis(argv); 338 if (!self->IsJSAPILinkedList()) { 339 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 340 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 341 } else { 342 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 343 "The removeByIndex method cannot be bound"); 344 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 345 } 346 } 347 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0); 348 if (index->IsDouble()) { 349 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 350 } 351 if (!index->IsInt()) { 352 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); 353 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 354 CString errorMsg = 355 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 356 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 357 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 358 } 359 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 360 JSTaggedValue nodeData = 361 JSAPILinkedList::RemoveByIndex(thread, jsAPILinkedList, index->GetInt()); 362 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 363 return nodeData; 364} 365 366JSTaggedValue ContainersLinkedList::Remove(EcmaRuntimeCallInfo *argv) 367{ 368 ASSERT(argv != nullptr); 369 JSThread *thread = argv->GetThread(); 370 BUILTINS_API_TRACE(thread, LinkedList, Remove); 371 [[maybe_unused]] EcmaHandleScope handleScope(thread); 372 JSHandle<JSTaggedValue> self = GetThis(argv); 373 if (!self->IsJSAPILinkedList()) { 374 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 375 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 376 } else { 377 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 378 "The remove method cannot be bound"); 379 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 380 } 381 } 382 JSHandle<JSTaggedValue> element = GetCallArg(argv, 0); 383 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 384 return jsAPILinkedList->Remove(thread, element.GetTaggedValue()); 385} 386 387JSTaggedValue ContainersLinkedList::RemoveFirst(EcmaRuntimeCallInfo *argv) 388{ 389 ASSERT(argv != nullptr); 390 JSThread *thread = argv->GetThread(); 391 BUILTINS_API_TRACE(thread, LinkedList, RemoveFirst); 392 [[maybe_unused]] EcmaHandleScope handleScope(thread); 393 JSHandle<JSTaggedValue> self = GetThis(argv); 394 if (!self->IsJSAPILinkedList()) { 395 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 396 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 397 } else { 398 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 399 "The removeFirst method cannot be bound"); 400 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 401 } 402 } 403 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 404 JSTaggedValue lastValue = JSAPILinkedList::RemoveFirst(thread, jsAPILinkedList); 405 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 406 return lastValue; 407} 408 409JSTaggedValue ContainersLinkedList::RemoveFirstFound(EcmaRuntimeCallInfo *argv) 410{ 411 ASSERT(argv != nullptr); 412 JSThread *thread = argv->GetThread(); 413 BUILTINS_API_TRACE(thread, LinkedList, RemoveFirstFound); 414 [[maybe_unused]] EcmaHandleScope handleScope(thread); 415 JSHandle<JSTaggedValue> self = GetThis(argv); 416 if (!self->IsJSAPILinkedList()) { 417 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 418 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 419 } else { 420 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 421 "The removeFirstFound method cannot be bound"); 422 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 423 } 424 } 425 JSHandle<JSTaggedValue> element = GetCallArg(argv, 0); 426 427 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 428 JSTaggedValue result = JSAPILinkedList::RemoveFirstFound(thread, jsAPILinkedList, element.GetTaggedValue()); 429 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 430 return result; 431} 432 433JSTaggedValue ContainersLinkedList::RemoveLast(EcmaRuntimeCallInfo *argv) 434{ 435 ASSERT(argv != nullptr); 436 JSThread *thread = argv->GetThread(); 437 BUILTINS_API_TRACE(thread, LinkedList, RemoveLast); 438 [[maybe_unused]] EcmaHandleScope handleScope(thread); 439 JSHandle<JSTaggedValue> self = GetThis(argv); 440 if (!self->IsJSAPILinkedList()) { 441 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 442 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 443 } else { 444 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 445 "The removeLast method cannot be bound"); 446 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 447 } 448 } 449 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 450 JSTaggedValue lastValue = JSAPILinkedList::RemoveLast(thread, jsAPILinkedList); 451 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 452 return lastValue; 453} 454 455JSTaggedValue ContainersLinkedList::RemoveLastFound(EcmaRuntimeCallInfo *argv) 456{ 457 ASSERT(argv != nullptr); 458 JSThread *thread = argv->GetThread(); 459 BUILTINS_API_TRACE(thread, LinkedList, RemoveLastFound); 460 [[maybe_unused]] EcmaHandleScope handleScope(thread); 461 JSHandle<JSTaggedValue> self = GetThis(argv); 462 if (!self->IsJSAPILinkedList()) { 463 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 464 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 465 } else { 466 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 467 "The removeLastFound method cannot be bound"); 468 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 469 } 470 } 471 JSHandle<JSTaggedValue> element = GetCallArg(argv, 0); 472 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 473 JSTaggedValue result = JSAPILinkedList::RemoveLastFound(thread, jsAPILinkedList, element.GetTaggedValue()); 474 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 475 return result; 476} 477 478JSTaggedValue ContainersLinkedList::Set(EcmaRuntimeCallInfo *argv) 479{ 480 ASSERT(argv != nullptr); 481 JSThread *thread = argv->GetThread(); 482 BUILTINS_API_TRACE(thread, LinkedList, Set); 483 [[maybe_unused]] EcmaHandleScope handleScope(thread); 484 JSHandle<JSTaggedValue> self = GetThis(argv); 485 if (!self->IsJSAPILinkedList()) { 486 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 487 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 488 } else { 489 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 490 "The set method cannot be bound"); 491 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 492 } 493 } 494 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0); 495 JSHandle<JSTaggedValue> element = GetCallArg(argv, 1); 496 if (index->IsDouble()) { 497 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble())); 498 } 499 if (!index->IsInt()) { 500 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue()); 501 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 502 CString errorMsg = 503 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result); 504 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 505 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 506 } 507 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 508 JSTaggedValue oldValue = 509 JSAPILinkedList::Set(thread, jsAPILinkedList, index->GetInt(), element); 510 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 511 return oldValue; 512} 513 514JSTaggedValue ContainersLinkedList::ConvertToArray(EcmaRuntimeCallInfo *argv) 515{ 516 ASSERT(argv != nullptr); 517 JSThread *thread = argv->GetThread(); 518 BUILTINS_API_TRACE(thread, LinkedList, ConvertToArray); 519 [[maybe_unused]] EcmaHandleScope handleScope(thread); 520 JSHandle<JSTaggedValue> self = GetThis(argv); 521 if (!self->IsJSAPILinkedList()) { 522 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILinkedList()) { 523 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 524 } else { 525 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 526 "The convertToArray method cannot be bound"); 527 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 528 } 529 } 530 JSHandle<JSAPILinkedList> jsAPILinkedList = JSHandle<JSAPILinkedList>::Cast(self); 531 return JSAPILinkedList::ConvertToArray(thread, jsAPILinkedList); 532} 533 534JSTaggedValue ContainersLinkedList::ForEach(EcmaRuntimeCallInfo *argv) 535{ 536 ASSERT(argv != nullptr); 537 JSThread *thread = argv->GetThread(); 538 BUILTINS_API_TRACE(thread, LinkedList, ForEach); 539 [[maybe_unused]] EcmaHandleScope handleScope(thread); 540 JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 541 if (!thisHandle->IsJSAPILinkedList()) { 542 if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPILinkedList()) { 543 thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget()); 544 } else { 545 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 546 "The forEach method cannot be bound"); 547 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 548 } 549 } 550 551 JSHandle<JSTaggedValue> callbackFnHandle(GetCallArg(argv, 0)); 552 if (!callbackFnHandle->IsCallable()) { 553 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue()); 554 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 555 CString errorMsg = 556 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result); 557 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 558 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 559 } 560 561 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 562 JSHandle<JSAPILinkedList> linkedList = JSHandle<JSAPILinkedList>::Cast(thisHandle); 563 JSHandle<TaggedDoubleList> doubleList(thread, linkedList->GetDoubleList()); 564 uint32_t length = linkedList->Length(); 565 566 uint32_t index = 0; 567 const uint32_t argsLength = 3; // 3: «kValue, k, O» 568 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 569 int valueNode = TaggedDoubleList::ELEMENTS_START_INDEX; 570 while (index < length) { 571 valueNode = doubleList->GetNextDataIndex(valueNode); 572 JSTaggedValue value = doubleList->GetElement(valueNode); 573 EcmaRuntimeCallInfo *info = 574 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); 575 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 576 info->SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue()); 577 JSTaggedValue funcResult = JSFunction::Call(info); 578 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); 579 index++; 580 } 581 return JSTaggedValue::Undefined(); 582} 583 584JSTaggedValue ContainersLinkedList::GetIteratorObj(EcmaRuntimeCallInfo *argv) 585{ 586 ASSERT(argv != nullptr); 587 JSThread *thread = argv->GetThread(); 588 BUILTINS_API_TRACE(thread, LinkedList, GetIteratorObj); 589 [[maybe_unused]] EcmaHandleScope handleScope(thread); 590 JSHandle<JSTaggedValue> self = GetThis(argv); 591 JSHandle<JSTaggedValue> iter = JSAPILinkedListIterator::CreateLinkedListIterator(thread, self); 592 return iter.GetTaggedValue(); 593} 594} // namespace panda::ecmascript::containers 595