1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/containers/containers_list.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_api/js_api_list.h"
21 #include "ecmascript/js_api/js_api_list_iterator.h"
22 #include "ecmascript/js_function.h"
23
24 namespace panda::ecmascript::containers {
ListConstructor(EcmaRuntimeCallInfo * argv)25 JSTaggedValue ContainersList::ListConstructor(EcmaRuntimeCallInfo *argv)
26 {
27 ASSERT(argv != nullptr);
28 JSThread *thread = argv->GetThread();
29 BUILTINS_API_TRACE(thread, List, Constructor);
30 [[maybe_unused]] EcmaHandleScope handleScope(thread);
31 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
32 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
33 if (newTarget->IsUndefined()) {
34 JSTaggedValue error =
35 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
36 "The List's constructor cannot be directly invoked");
37 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
38 }
39 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
40 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
41 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
42 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(obj);
43 list->SetIsOrderedList(true);
44
45 JSTaggedValue singleList = TaggedSingleList::Create(thread);
46 list->SetSingleList(thread, singleList);
47
48 return list.GetTaggedValue();
49 }
50
Add(EcmaRuntimeCallInfo * argv)51 JSTaggedValue ContainersList::Add(EcmaRuntimeCallInfo *argv)
52 {
53 ASSERT(argv != nullptr);
54 JSThread *thread = argv->GetThread();
55 BUILTINS_API_TRACE(thread, List, Add);
56 [[maybe_unused]] EcmaHandleScope handleScope(thread);
57 JSHandle<JSTaggedValue> self = GetThis(argv);
58 if (!self->IsJSAPIList()) {
59 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
60 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
61 } else {
62 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
63 "The add method cannot be bound");
64 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
65 }
66 }
67
68 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
69 JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
70 JSAPIList::Add(thread, jSAPIList, value);
71 return JSTaggedValue::True();
72 }
73
Insert(EcmaRuntimeCallInfo * argv)74 JSTaggedValue ContainersList::Insert(EcmaRuntimeCallInfo *argv)
75 {
76 ASSERT(argv != nullptr);
77 JSThread *thread = argv->GetThread();
78 BUILTINS_API_TRACE(thread, List, Insert);
79 [[maybe_unused]] EcmaHandleScope handleScope(thread);
80 JSHandle<JSTaggedValue> self = GetThis(argv);
81 if (!self->IsJSAPIList()) {
82 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
83 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
84 } else {
85 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
86 "The insert method cannot be bound");
87 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
88 }
89 }
90 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
91 JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
92 if (index->IsDouble()) {
93 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
94 }
95 if (!index->IsInt()) {
96 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
97 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
98 CString errorMsg =
99 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
100 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
101 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
102 }
103 JSHandle<JSAPIList> jSAPIList = JSHandle<JSAPIList>::Cast(self);
104 JSAPIList::Insert(thread, jSAPIList, value, index->GetInt());
105 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
106 return JSTaggedValue::True();
107 }
108
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->IsDouble()) {
209 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
210 }
211 if (!index->IsInt()) {
212 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
213 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
214 CString errorMsg =
215 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
216 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
217 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
218 }
219 return jsAPIList->Get(index->GetInt());
220 }
221
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->IsDouble()) {
283 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
284 }
285 if (!index->IsInt()) {
286 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
287 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
288 CString errorMsg =
289 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
290 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
291 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
292 }
293 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
294 JSTaggedValue oldValue = JSAPIList::Set(thread, jsAPIList, index->GetInt(), element);
295 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
296 return oldValue;
297 }
298
ForEach(EcmaRuntimeCallInfo * argv)299 JSTaggedValue ContainersList::ForEach(EcmaRuntimeCallInfo *argv)
300 {
301 ASSERT(argv != nullptr);
302 JSThread *thread = argv->GetThread();
303 BUILTINS_API_TRACE(thread, List, ForEach);
304 [[maybe_unused]] EcmaHandleScope handleScope(thread);
305 // get and check List object
306 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
307 if (!thisHandle->IsJSAPIList()) {
308 if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIList()) {
309 thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
310 } else {
311 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
312 "The forEach method cannot be bound");
313 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
314 }
315 }
316
317 // get and check callback function
318 JSHandle<JSTaggedValue> callbackFnHandle(GetCallArg(argv, 0));
319 if (!callbackFnHandle->IsCallable()) {
320 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
321 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
322 CString errorMsg =
323 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
324 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
325 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
326 }
327
328 // If thisArgHandle was supplied, let T be thisArgHandle; else let T be undefined.
329 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
330 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(thisHandle);
331 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
332 uint32_t length = list->Length();
333
334 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
335 uint32_t index = 0;
336 const uint32_t argsLength = 3; // 3: «kValue, k, O»
337 int valueNode = TaggedSingleList::ELEMENTS_START_INDEX;
338 while (index < length) {
339 valueNode = singleList->GetNextDataIndex(valueNode);
340 JSTaggedValue value = singleList->GetElement(valueNode);
341 EcmaRuntimeCallInfo *info =
342 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength);
343 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
344 info->SetCallArg(value, JSTaggedValue(index), thisHandle.GetTaggedValue());
345 JSTaggedValue funcResult = JSFunction::Call(info);
346 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
347 index++;
348 }
349 return JSTaggedValue::Undefined();
350 }
351
Clear(EcmaRuntimeCallInfo * argv)352 JSTaggedValue ContainersList::Clear(EcmaRuntimeCallInfo *argv)
353 {
354 ASSERT(argv != nullptr);
355 JSThread *thread = argv->GetThread();
356 BUILTINS_API_TRACE(thread, List, Clear);
357 [[maybe_unused]] EcmaHandleScope handleScope(thread);
358 JSHandle<JSTaggedValue> self = GetThis(argv);
359 if (!self->IsJSAPIList()) {
360 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
361 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
362 } else {
363 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
364 "The clear method cannot be bound");
365 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
366 }
367 }
368 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
369 jsAPIList->Clear(thread);
370 return JSTaggedValue::Undefined();
371 }
372
RemoveByIndex(EcmaRuntimeCallInfo * argv)373 JSTaggedValue ContainersList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
374 {
375 ASSERT(argv != nullptr);
376 JSThread *thread = argv->GetThread();
377 BUILTINS_API_TRACE(thread, List, RemoveByIndex);
378 [[maybe_unused]] EcmaHandleScope handleScope(thread);
379 JSHandle<JSTaggedValue> self = GetThis(argv);
380 if (!self->IsJSAPIList()) {
381 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
382 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
383 } else {
384 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
385 "The removeByIndex method cannot be bound");
386 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
387 }
388 }
389 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
390 if (index->IsDouble()) {
391 index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
392 }
393 if (!index->IsInt()) {
394 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index.GetTaggedValue());
395 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
396 CString errorMsg =
397 "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
398 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
399 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
400 }
401 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
402 JSTaggedValue result = JSAPIList::RemoveByIndex(thread, jsAPIList, index->GetInt());
403 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
404 return result;
405 }
406
Remove(EcmaRuntimeCallInfo * argv)407 JSTaggedValue ContainersList::Remove(EcmaRuntimeCallInfo *argv)
408 {
409 ASSERT(argv != nullptr);
410 JSThread *thread = argv->GetThread();
411 BUILTINS_API_TRACE(thread, List, Remove);
412 [[maybe_unused]] EcmaHandleScope handleScope(thread);
413 JSHandle<JSTaggedValue> self = GetThis(argv);
414 if (!self->IsJSAPIList()) {
415 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
416 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
417 } else {
418 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
419 "The remove method cannot be bound");
420 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
421 }
422 }
423 JSHandle<JSTaggedValue> element = GetCallArg(argv, 0);
424 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
425 return jsAPIList->Remove(thread, element.GetTaggedValue());
426 }
427
ReplaceAllElements(EcmaRuntimeCallInfo * argv)428 JSTaggedValue ContainersList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
429 {
430 ASSERT(argv != nullptr);
431 JSThread *thread = argv->GetThread();
432 BUILTINS_API_TRACE(thread, List, ReplaceAllElements);
433 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
434 if (!thisHandle->IsJSAPIList()) {
435 if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIList()) {
436 thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
437 } else {
438 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
439 "The replaceAllElements method cannot be bound");
440 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
441 }
442 }
443 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
444 if (!callbackFnHandle->IsCallable()) {
445 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
446 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
447 CString errorMsg =
448 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
449 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
450 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
451 }
452 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
453 return JSAPIList::ReplaceAllElements(thread, thisHandle, callbackFnHandle, thisArgHandle);
454 }
455
Equal(EcmaRuntimeCallInfo * argv)456 JSTaggedValue ContainersList::Equal(EcmaRuntimeCallInfo *argv)
457 {
458 ASSERT(argv != nullptr);
459 JSThread *thread = argv->GetThread();
460 BUILTINS_API_TRACE(thread, List, Equal);
461 [[maybe_unused]] EcmaHandleScope handleScope(thread);
462 JSHandle<JSTaggedValue> self = GetThis(argv);
463 if (!self->IsJSAPIList()) {
464 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
465 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
466 } else {
467 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
468 "The equal method cannot be bound");
469 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
470 }
471 }
472 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
473 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
474 if (!obj->IsJSAPIList()) {
475 if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPIList()) {
476 obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
477 } else {
478 return JSTaggedValue::False();
479 }
480 }
481 JSHandle<JSAPIList> handleObj = JSHandle<JSAPIList>::Cast(obj);
482 return jsAPIList->Equal(thread, handleObj);
483 }
484
Sort(EcmaRuntimeCallInfo * argv)485 JSTaggedValue ContainersList::Sort(EcmaRuntimeCallInfo *argv)
486 {
487 ASSERT(argv != nullptr);
488 JSThread *thread = argv->GetThread();
489 BUILTINS_API_TRACE(thread, List, Sort);
490 [[maybe_unused]] EcmaHandleScope handleScope(thread);
491 JSHandle<JSTaggedValue> self = GetThis(argv);
492 if (!self->IsJSAPIList()) {
493 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
494 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
495 } else {
496 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
497 "The sort method cannot be bound");
498 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
499 }
500 }
501 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
502 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
503 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
504 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
505 CString errorMsg =
506 "The type of \"comparator\" must be callable. Received value is: " + ConvertToString(*result);
507 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
508 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
509 }
510 return JSAPIList::Sort(thread, self, callbackFnHandle);
511 }
512
GetIteratorObj(EcmaRuntimeCallInfo * argv)513 JSTaggedValue ContainersList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
514 {
515 ASSERT(argv != nullptr);
516 JSThread *thread = argv->GetThread();
517 BUILTINS_API_TRACE(thread, List, GetIteratorObj);
518 [[maybe_unused]] EcmaHandleScope handleScope(thread);
519 JSHandle<JSTaggedValue> self = GetThis(argv);
520 JSHandle<JSTaggedValue> iter = JSAPIListIterator::CreateListIterator(thread, self);
521 return iter.GetTaggedValue();
522 }
523
ConvertToArray(EcmaRuntimeCallInfo * argv)524 JSTaggedValue ContainersList::ConvertToArray(EcmaRuntimeCallInfo *argv)
525 {
526 ASSERT(argv != nullptr);
527 JSThread *thread = argv->GetThread();
528 BUILTINS_API_TRACE(thread, List, ConvertToArray);
529 [[maybe_unused]] EcmaHandleScope handleScope(thread);
530 JSHandle<JSTaggedValue> self = GetThis(argv);
531 if (!self->IsJSAPIList()) {
532 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
533 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
534 } else {
535 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
536 "The convertToArray method cannot be bound");
537 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
538 }
539 }
540 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
541 return JSAPIList::ConvertToArray(thread, jsAPIList);
542 }
543
GetSubList(EcmaRuntimeCallInfo * argv)544 JSTaggedValue ContainersList::GetSubList(EcmaRuntimeCallInfo *argv)
545 {
546 ASSERT(argv != nullptr);
547 JSThread *thread = argv->GetThread();
548 BUILTINS_API_TRACE(thread, List, GetSubList);
549 [[maybe_unused]] EcmaHandleScope handleScope(thread);
550 JSHandle<JSTaggedValue> self = GetThis(argv);
551 if (!self->IsJSAPIList()) {
552 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
553 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
554 } else {
555 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
556 "The getSubList method cannot be bound");
557 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
558 }
559 }
560 JSHandle<JSTaggedValue> fromIndex = GetCallArg(argv, 0);
561
562 if (fromIndex->IsDouble()) {
563 fromIndex = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(fromIndex->GetDouble()));
564 }
565
566 if (!fromIndex->IsInt()) {
567 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, fromIndex.GetTaggedValue());
568 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
569 CString errorMsg =
570 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
571 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
572 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
573 }
574
575 JSHandle<JSTaggedValue> toIndex = GetCallArg(argv, 1);
576
577 // for case like Math.foor(1.3), it gives double 1.0;
578 if (toIndex->IsDouble()) {
579 toIndex = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(toIndex->GetDouble()));
580 }
581
582 if (!toIndex->IsInt()) {
583 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, toIndex.GetTaggedValue());
584 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
585 CString errorMsg =
586 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
587 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
588 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
589 }
590
591 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
592 JSTaggedValue newList = JSAPIList::GetSubList(thread, jsAPIList, fromIndex->GetInt(), toIndex->GetInt());
593 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
594 return newList;
595 }
596
Length(EcmaRuntimeCallInfo * argv)597 JSTaggedValue ContainersList::Length(EcmaRuntimeCallInfo *argv)
598 {
599 ASSERT(argv != nullptr);
600 JSThread *thread = argv->GetThread();
601 BUILTINS_API_TRACE(thread, List, Length);
602 [[maybe_unused]] EcmaHandleScope handleScope(thread);
603 JSHandle<JSTaggedValue> self = GetThis(argv);
604 if (!self->IsJSAPIList()) {
605 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIList()) {
606 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
607 } else {
608 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
609 "The getLength method cannot be bound");
610 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
611 }
612 }
613 JSHandle<JSAPIList> jsAPIList = JSHandle<JSAPIList>::Cast(self);
614 return JSTaggedValue(jsAPIList->Length());
615 }
616 } // namespace panda::ecmascript::containers
617