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