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