• 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_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 
24 namespace panda::ecmascript::containers {
LinkedListConstructor(EcmaRuntimeCallInfo * argv)25 JSTaggedValue 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 
Add(EcmaRuntimeCallInfo * argv)48 JSTaggedValue 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 
AddFirst(EcmaRuntimeCallInfo * argv)71 JSTaggedValue 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 
GetFirst(EcmaRuntimeCallInfo * argv)94 JSTaggedValue 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 
GetLast(EcmaRuntimeCallInfo * argv)114 JSTaggedValue 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 
Length(EcmaRuntimeCallInfo * argv)134 JSTaggedValue 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 
Insert(EcmaRuntimeCallInfo * argv)154 JSTaggedValue 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 
Clear(EcmaRuntimeCallInfo * argv)193 JSTaggedValue 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 
Clone(EcmaRuntimeCallInfo * argv)214 JSTaggedValue 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 
Has(EcmaRuntimeCallInfo * argv)236 JSTaggedValue 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 
Get(EcmaRuntimeCallInfo * argv)257 JSTaggedValue 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 
GetIndexOf(EcmaRuntimeCallInfo * argv)289 JSTaggedValue 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 
GetLastIndexOf(EcmaRuntimeCallInfo * argv)310 JSTaggedValue 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 
RemoveByIndex(EcmaRuntimeCallInfo * argv)331 JSTaggedValue 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 
Remove(EcmaRuntimeCallInfo * argv)366 JSTaggedValue 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 
RemoveFirst(EcmaRuntimeCallInfo * argv)387 JSTaggedValue 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 
RemoveFirstFound(EcmaRuntimeCallInfo * argv)409 JSTaggedValue 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 
RemoveLast(EcmaRuntimeCallInfo * argv)433 JSTaggedValue 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 
RemoveLastFound(EcmaRuntimeCallInfo * argv)455 JSTaggedValue 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 
Set(EcmaRuntimeCallInfo * argv)478 JSTaggedValue 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 
ConvertToArray(EcmaRuntimeCallInfo * argv)514 JSTaggedValue 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 
ForEach(EcmaRuntimeCallInfo * argv)534 JSTaggedValue 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 
GetIteratorObj(EcmaRuntimeCallInfo * argv)584 JSTaggedValue 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