• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
98         CString errorMsg =
99             "The type of \"index\" must be number. 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 
GetFirst(EcmaRuntimeCallInfo * argv)109 JSTaggedValue 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 
GetLast(EcmaRuntimeCallInfo * argv)129 JSTaggedValue 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 
Has(EcmaRuntimeCallInfo * argv)149 JSTaggedValue 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 
IsEmpty(EcmaRuntimeCallInfo * argv)170 JSTaggedValue 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 
Get(EcmaRuntimeCallInfo * argv)190 JSTaggedValue 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->IsInteger()) {
209         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
210         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
211         CString errorMsg =
212             "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
213         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
214         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
215     }
216     if (index->IsDouble()) {
217         index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
218     }
219     return jsAPIList->Get(index->GetInt());
220 }
221 
GetIndexOf(EcmaRuntimeCallInfo * argv)222 JSTaggedValue 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 
GetLastIndexOf(EcmaRuntimeCallInfo * argv)243 JSTaggedValue 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 
Set(EcmaRuntimeCallInfo * argv)264 JSTaggedValue 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->IsInteger()) {
283         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
284         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
285         CString errorMsg =
286             "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
287         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
288         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
289     }
290     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
291     JSTaggedValue oldValue = JSAPIList::Set(thread, jsAPIList, index->GetInt(), element);
292     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
293     return oldValue;
294 }
295 
ForEach(EcmaRuntimeCallInfo * argv)296 JSTaggedValue ContainersList::ForEach(EcmaRuntimeCallInfo *argv)
297 {
298     ASSERT(argv != nullptr);
299     JSThread *thread = argv->GetThread();
300     BUILTINS_API_TRACE(thread, List, ForEach);
301     [[maybe_unused]] EcmaHandleScope handleScope(thread);
302     // get and check List object
303     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
304     if (!thisHandle->IsJSAPIList()) {
305         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIList()) {
306             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
307         } else {
308             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
309                                                                 "The forEach method cannot be bound");
310             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
311         }
312     }
313 
314     // get and check callback function
315     JSHandle<JSTaggedValue> callbackFnHandle(GetCallArg(argv, 0));
316     if (!callbackFnHandle->IsCallable()) {
317         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
318         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
319         CString errorMsg =
320             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
321         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
322         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
323     }
324 
325     // If thisArgHandle was supplied, let T be thisArgHandle; else let T be undefined.
326     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
327     JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(thisHandle);
328     JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
329     uint32_t length = list->Length();
330 
331     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
332     uint32_t index = 0;
333     const uint32_t argsLength = 3; // 3: «kValue, k, O»
334     int valueNode = TaggedSingleList::ELEMENTS_START_INDEX;
335     while (index < length) {
336         valueNode = singleList->GetNextDataIndex(valueNode);
337         JSTaggedValue value = singleList->GetElement(valueNode);
338         EcmaRuntimeCallInfo *info =
339             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
340         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
341         info->SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue());
342         JSTaggedValue funcResult = JSFunction::Call(info);
343         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
344         index++;
345     }
346     return JSTaggedValue::Undefined();
347 }
348 
Clear(EcmaRuntimeCallInfo * argv)349 JSTaggedValue ContainersList::Clear(EcmaRuntimeCallInfo *argv)
350 {
351     ASSERT(argv != nullptr);
352     JSThread *thread = argv->GetThread();
353     BUILTINS_API_TRACE(thread, List, Clear);
354     [[maybe_unused]] EcmaHandleScope handleScope(thread);
355     JSHandle<JSTaggedValue> self = GetThis(argv);
356     if (!self->IsJSAPIList()) {
357         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
358             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
359         } else {
360             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
361                                                                 "The clear method cannot be bound");
362             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
363         }
364     }
365     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
366     jsAPIList->Clear(thread);
367     return JSTaggedValue::Undefined();
368 }
369 
RemoveByIndex(EcmaRuntimeCallInfo * argv)370 JSTaggedValue ContainersList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
371 {
372     ASSERT(argv != nullptr);
373     JSThread *thread = argv->GetThread();
374     BUILTINS_API_TRACE(thread, List, RemoveByIndex);
375     [[maybe_unused]] EcmaHandleScope handleScope(thread);
376     JSHandle<JSTaggedValue> self = GetThis(argv);
377     if (!self->IsJSAPIList()) {
378         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
379             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
380         } else {
381             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
382                                                                 "The removeByIndex method cannot be bound");
383             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
384         }
385     }
386     JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
387     if (!index->IsInteger()) {
388         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
389         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
390         CString errorMsg =
391             "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
392         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
393         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
394     }
395     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
396     JSTaggedValue result = JSAPIList::RemoveByIndex(thread, jsAPIList, index->GetInt());
397     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
398     return result;
399 }
400 
Remove(EcmaRuntimeCallInfo * argv)401 JSTaggedValue ContainersList::Remove(EcmaRuntimeCallInfo *argv)
402 {
403     ASSERT(argv != nullptr);
404     JSThread *thread = argv->GetThread();
405     BUILTINS_API_TRACE(thread, List, Remove);
406     [[maybe_unused]] EcmaHandleScope handleScope(thread);
407     JSHandle<JSTaggedValue> self = GetThis(argv);
408     if (!self->IsJSAPIList()) {
409         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
410             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
411         } else {
412             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
413                                                                 "The remove method cannot be bound");
414             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
415         }
416     }
417     JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
418     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
419     return jsAPIList->Remove(thread, element.GetTaggedValue());
420 }
421 
ReplaceAllElements(EcmaRuntimeCallInfo * argv)422 JSTaggedValue ContainersList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
423 {
424     ASSERT(argv != nullptr);
425     JSThread *thread = argv->GetThread();
426     BUILTINS_API_TRACE(thread, List, ReplaceAllElements);
427     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
428     if (!thisHandle->IsJSAPIList()) {
429         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIList()) {
430             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
431         } else {
432             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
433                                                                 "The replaceAllElements method cannot be bound");
434             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
435         }
436     }
437     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
438     if (!callbackFnHandle->IsCallable()) {
439         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
440         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
441         CString errorMsg =
442             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
443         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
444         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
445     }
446     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
447     return JSAPIList::ReplaceAllElements(thread, thisHandle, callbackFnHandle, thisArgHandle);
448 }
449 
Equal(EcmaRuntimeCallInfo * argv)450 JSTaggedValue ContainersList::Equal(EcmaRuntimeCallInfo *argv)
451 {
452     ASSERT(argv != nullptr);
453     JSThread *thread = argv->GetThread();
454     BUILTINS_API_TRACE(thread, List, Equal);
455     [[maybe_unused]] EcmaHandleScope handleScope(thread);
456     JSHandle<JSTaggedValue> self = GetThis(argv);
457     if (!self->IsJSAPIList()) {
458         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
459             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
460         } else {
461             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
462                                                                 "The equal method cannot be bound");
463             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
464         }
465     }
466     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
467     JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
468     if (!obj->IsJSAPIList()) {
469         if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPIList()) {
470             obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
471         } else {
472             return JSTaggedValue::False();
473         }
474     }
475     JSHandle<JSAPIList> handleObj = JSHandle<JSAPIList>::Cast(obj);
476     return jsAPIList->Equal(thread, handleObj);
477 }
478 
Sort(EcmaRuntimeCallInfo * argv)479 JSTaggedValue ContainersList::Sort(EcmaRuntimeCallInfo *argv)
480 {
481     ASSERT(argv != nullptr);
482     JSThread *thread = argv->GetThread();
483     BUILTINS_API_TRACE(thread, List, Sort);
484     [[maybe_unused]] EcmaHandleScope handleScope(thread);
485     JSHandle<JSTaggedValue> self = GetThis(argv);
486     if (!self->IsJSAPIList()) {
487         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
488             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
489         } else {
490             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
491                                                                 "The sort method cannot be bound");
492             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
493         }
494     }
495     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
496     if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
497         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
498         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
499         CString errorMsg =
500             "The type of \"comparator\" must be callable. Received value is: " + ConvertToString(*result);
501         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
502         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
503     }
504     return JSAPIList::Sort(thread, self, callbackFnHandle);
505 }
506 
GetIteratorObj(EcmaRuntimeCallInfo * argv)507 JSTaggedValue ContainersList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
508 {
509     ASSERT(argv != nullptr);
510     JSThread *thread = argv->GetThread();
511     BUILTINS_API_TRACE(thread, List, GetIteratorObj);
512     [[maybe_unused]] EcmaHandleScope handleScope(thread);
513     JSHandle<JSTaggedValue> self = GetThis(argv);
514     JSHandle<JSTaggedValue> iter = JSAPIListIterator::CreateListIterator(thread, self);
515     return iter.GetTaggedValue();
516 }
517 
ConvertToArray(EcmaRuntimeCallInfo * argv)518 JSTaggedValue ContainersList::ConvertToArray(EcmaRuntimeCallInfo *argv)
519 {
520     ASSERT(argv != nullptr);
521     JSThread *thread = argv->GetThread();
522     BUILTINS_API_TRACE(thread, List, ConvertToArray);
523     [[maybe_unused]] EcmaHandleScope handleScope(thread);
524     JSHandle<JSTaggedValue> self = GetThis(argv);
525     if (!self->IsJSAPIList()) {
526         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
527             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
528         } else {
529             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
530                                                                 "The convertToArray method cannot be bound");
531             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
532         }
533     }
534     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
535     return JSAPIList::ConvertToArray(thread, jsAPIList);
536 }
537 
GetSubList(EcmaRuntimeCallInfo * argv)538 JSTaggedValue ContainersList::GetSubList(EcmaRuntimeCallInfo *argv)
539 {
540     ASSERT(argv != nullptr);
541     JSThread *thread = argv->GetThread();
542     BUILTINS_API_TRACE(thread, List, GetSubList);
543     [[maybe_unused]] EcmaHandleScope handleScope(thread);
544     JSHandle<JSTaggedValue> self = GetThis(argv);
545     if (!self->IsJSAPIList()) {
546         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
547             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
548         } else {
549             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
550                                                                 "The getSubList method cannot be bound");
551             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
552         }
553     }
554     JSHandle<JSTaggedValue> fromIndex = GetCallArg(argv, 0);
555 
556     if (!fromIndex->IsInteger()) {
557         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, fromIndex.GetTaggedValue());
558         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
559         CString errorMsg =
560             "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
561         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
562         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
563     }
564 
565     JSHandle<JSTaggedValue> toIndex = GetCallArg(argv, 1);
566 
567     if (!toIndex->IsInteger()) {
568         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, toIndex.GetTaggedValue());
569         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
570         CString errorMsg =
571             "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
572         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
573         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
574     }
575 
576     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
577     JSTaggedValue newList = JSAPIList::GetSubList(thread, jsAPIList, fromIndex->GetInt(), toIndex->GetInt());
578     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
579     return newList;
580 }
581 
Length(EcmaRuntimeCallInfo * argv)582 JSTaggedValue ContainersList::Length(EcmaRuntimeCallInfo *argv)
583 {
584     ASSERT(argv != nullptr);
585     JSThread *thread = argv->GetThread();
586     BUILTINS_API_TRACE(thread, List, Length);
587     [[maybe_unused]] EcmaHandleScope handleScope(thread);
588     JSHandle<JSTaggedValue> self = GetThis(argv);
589     if (!self->IsJSAPIList()) {
590         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
591             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
592         } else {
593             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
594                                                                 "The length method cannot be bound");
595             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
596         }
597     }
598     JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
599     return JSTaggedValue(jsAPIList->Length());
600 }
601 }  // namespace panda::ecmascript::containers
602