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