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/js_api/js_api_list.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/js_api/js_api_list_iterator.h"
20 #include "ecmascript/js_array.h"
21 #include "ecmascript/js_function.h"
22 #include "ecmascript/js_handle.h"
23 #include "ecmascript/js_tagged_number.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/object_factory.h"
26 #include "ecmascript/tagged_list.h"
27
28 namespace panda::ecmascript {
29 using ContainerError = containers::ContainerError;
30 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPIList> & list,const JSHandle<JSTaggedValue> & value)31 void JSAPIList::Add(JSThread *thread, const JSHandle<JSAPIList> &list, const JSHandle<JSTaggedValue> &value)
32 {
33 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
34 JSTaggedValue newList = TaggedSingleList::Add(thread, singleList, value);
35 list->SetSingleList(thread, newList);
36 }
37
GetFirst()38 JSTaggedValue JSAPIList::GetFirst()
39 {
40 JSTaggedValue res = TaggedSingleList::Cast(GetSingleList().GetTaggedObject())->GetFirst();
41 if (res.IsHole()) {
42 return JSTaggedValue::Undefined();
43 }
44 return res;
45 }
46
GetLast()47 JSTaggedValue JSAPIList::GetLast()
48 {
49 JSTaggedValue res = TaggedSingleList::Cast(GetSingleList().GetTaggedObject())->GetLast();
50 if (res.IsHole()) {
51 return JSTaggedValue::Undefined();
52 }
53 return res;
54 }
55
Insert(JSThread * thread,const JSHandle<JSAPIList> & list,const JSHandle<JSTaggedValue> & value,const int index)56 JSTaggedValue JSAPIList::Insert(JSThread *thread, const JSHandle<JSAPIList> &list, const JSHandle<JSTaggedValue> &value,
57 const int index)
58 {
59 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
60 int nodeLength = singleList->Length();
61 if (index < 0 || index > nodeLength) {
62 std::ostringstream oss;
63 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << nodeLength
64 << ". Received value is: " << index;
65 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
66 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
67 }
68 JSTaggedValue newList = TaggedSingleList::Insert(thread, singleList, value, index);
69 list->SetSingleList(thread, newList);
70 return JSTaggedValue::True();
71 }
72
Set(JSThread * thread,const JSHandle<JSAPIList> & list,const int index,const JSHandle<JSTaggedValue> & value)73 JSTaggedValue JSAPIList::Set(JSThread *thread, const JSHandle<JSAPIList> &list,
74 const int index, const JSHandle<JSTaggedValue> &value)
75 {
76 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
77 int nodeLength = singleList->Length();
78 if (index < 0 || index >= nodeLength) {
79 std::ostringstream oss;
80 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (nodeLength - 1)
81 << ". Received value is: " << index;
82 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
83 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
84 }
85 TaggedSingleList::Set(thread, singleList, index, value);
86 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
87 return value.GetTaggedValue();
88 }
89
Has(const JSTaggedValue & element)90 bool JSAPIList::Has(const JSTaggedValue &element)
91 {
92 TaggedSingleList *singleList = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
93 return singleList->Has(element);
94 }
95
IsEmpty()96 bool JSAPIList::IsEmpty()
97 {
98 return TaggedSingleList::Cast(GetSingleList().GetTaggedObject())->IsEmpty();
99 }
100
Get(const int index)101 JSTaggedValue JSAPIList::Get(const int index)
102 {
103 TaggedSingleList *singleList = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
104 int nodeLength = singleList->Length();
105 if (index < 0 || index >= nodeLength) {
106 return JSTaggedValue::Undefined();
107 }
108 return singleList->Get(index);
109 }
110
GetIndexOf(const JSTaggedValue & element)111 JSTaggedValue JSAPIList::GetIndexOf(const JSTaggedValue &element)
112 {
113 TaggedSingleList *singleList = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
114 return JSTaggedValue(singleList->GetIndexOf(element));
115 }
116
GetLastIndexOf(const JSTaggedValue & element)117 JSTaggedValue JSAPIList::GetLastIndexOf(const JSTaggedValue &element)
118 {
119 TaggedSingleList *singleList = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
120 return JSTaggedValue(singleList->GetLastIndexOf(element));
121 }
122
Clear(JSThread * thread)123 void JSAPIList::Clear(JSThread *thread)
124 {
125 TaggedSingleList *singleList = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
126 if (singleList->NumberOfNodes() > 0) {
127 singleList->Clear(thread);
128 }
129 }
130
RemoveByIndex(JSThread * thread,const JSHandle<JSAPIList> & list,const int & index)131 JSTaggedValue JSAPIList::RemoveByIndex(JSThread *thread, const JSHandle<JSAPIList> &list, const int &index)
132 {
133 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
134 int nodeLength = singleList->Length();
135 if (index < 0 || index >= nodeLength) {
136 int size = (nodeLength > 0) ? (nodeLength - 1) : 0;
137 std::ostringstream oss;
138 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << size
139 << ". Received value is: " << index;
140 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
141 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
142 }
143 return singleList->RemoveByIndex(thread, index);
144 }
145
Remove(JSThread * thread,const JSTaggedValue & element)146 JSTaggedValue JSAPIList::Remove(JSThread *thread, const JSTaggedValue &element)
147 {
148 TaggedSingleList *singleList = TaggedSingleList::Cast(GetSingleList().GetTaggedObject());
149 return singleList->Remove(thread, element);
150 }
151
ReplaceAllElements(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)152 JSTaggedValue JSAPIList::ReplaceAllElements(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
153 const JSHandle<JSTaggedValue> &callbackFn,
154 const JSHandle<JSTaggedValue> &thisArg)
155 {
156 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(thisHandle);
157 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
158 return TaggedSingleList::ReplaceAllElements(thread, thisHandle, callbackFn, thisArg, singleList);
159 }
160
Sort(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn)161 JSTaggedValue JSAPIList::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
162 const JSHandle<JSTaggedValue> &callbackFn)
163 {
164 JSHandle<JSAPIList> list = JSHandle<JSAPIList>::Cast(thisHandle);
165 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
166 return TaggedSingleList::Sort(thread, callbackFn, singleList);
167 }
168
Equal(JSThread * thread,const JSHandle<JSAPIList> & list)169 JSTaggedValue JSAPIList::Equal(JSThread *thread, const JSHandle<JSAPIList> &list)
170 {
171 JSHandle<TaggedSingleList> compareList(thread, list->GetSingleList());
172 return TaggedSingleList::Cast(GetSingleList().GetTaggedObject())->Equal(compareList);
173 }
174
ConvertToArray(const JSThread * thread,const JSHandle<JSAPIList> & list)175 JSTaggedValue JSAPIList::ConvertToArray(const JSThread *thread, const JSHandle<JSAPIList> &list)
176 {
177 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
178 return TaggedSingleList::ConvertToArray(thread, singleList);
179 }
180
GetSubList(JSThread * thread,const JSHandle<JSAPIList> & list,const int fromIndex,const int toIndex)181 JSTaggedValue JSAPIList::GetSubList(JSThread *thread, const JSHandle<JSAPIList> &list,
182 const int fromIndex, const int toIndex)
183 {
184 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
185 int nodeLength = singleList->Length();
186 int32_t size = nodeLength > toIndex ? toIndex : nodeLength;
187 if (fromIndex < 0 || fromIndex >= size) {
188 std::ostringstream oss;
189 oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= "
190 << (size - 1) << ". Received value is: " << fromIndex;
191 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
192 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
193 }
194 if (toIndex < 0 || toIndex <= fromIndex || toIndex >= nodeLength) {
195 std::ostringstream oss;
196 oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= "
197 << nodeLength << ". Received value is: " << toIndex;
198 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
199 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
200 }
201 uint32_t len = TaggedSingleList::ELEMENTS_START_INDEX + (toIndex - fromIndex + 1) * TaggedSingleList::ENTRY_SIZE;
202 JSHandle<TaggedArray> newElement = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len);
203 JSHandle<TaggedSingleList> subSingleList = JSHandle<TaggedSingleList>::Cast(newElement);
204 JSHandle<JSAPIList> sublist = thread->GetEcmaVM()->GetFactory()->NewJSAPIList();
205 TaggedSingleList::GetSubList(thread, singleList, fromIndex, toIndex, subSingleList);
206 sublist->SetSingleList(thread, subSingleList);
207 return sublist.GetTaggedValue();
208 }
209
OwnKeys(JSThread * thread,const JSHandle<JSAPIList> & list)210 JSHandle<TaggedArray> JSAPIList::OwnKeys(JSThread *thread, const JSHandle<JSAPIList> &list)
211 {
212 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
213 return TaggedSingleList::OwnKeys(thread, singleList);
214 }
215
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIList> & list,const JSHandle<JSTaggedValue> & key)216 bool JSAPIList::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIList> &list, const JSHandle<JSTaggedValue> &key)
217 {
218 uint32_t index = 0;
219 if (UNLIKELY(!JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
220 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
221 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
222 CString errorMsg =
223 "The type of \"index\" can not obtain attributes of no-number type. Received value is: "
224 + ConvertToString(*result);
225 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
226 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
227 }
228 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
229 uint32_t length = static_cast<uint32_t>(singleList->Length());
230 if (index >= length) {
231 std::ostringstream oss;
232 oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
233 << ". Received value is: " << index;
234 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
235 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
236 }
237 list->Get(index);
238 return true;
239 }
240
GetProperty(JSThread * thread,const JSHandle<JSAPIList> & list,const JSHandle<JSTaggedValue> & key)241 OperationResult JSAPIList::GetProperty(JSThread *thread, const JSHandle<JSAPIList> &list,
242 const JSHandle<JSTaggedValue> &key)
243 {
244 JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList());
245 int nodeLength = singleList->Length();
246 int index = key->GetInt();
247 if (index < 0 || index >= nodeLength) {
248 std::ostringstream oss;
249 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (nodeLength - 1)
250 << ". Received value is: " << index;
251 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
252 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
253 JSTaggedValue::Exception(),
254 PropertyMetaData(false)));
255 }
256
257 return OperationResult(thread, singleList->Get(index), PropertyMetaData(false));
258 }
259
SetProperty(JSThread * thread,const JSHandle<JSAPIList> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)260 bool JSAPIList::SetProperty(JSThread *thread, const JSHandle<JSAPIList> &obj,
261 const JSHandle<JSTaggedValue> &key,
262 const JSHandle<JSTaggedValue> &value)
263 {
264 JSHandle<TaggedSingleList> singleList(thread, obj->GetSingleList());
265 int nodeLength = singleList->Length();
266 int index = key->GetInt();
267 if (index < 0 || index >= nodeLength) {
268 return false;
269 }
270
271 TaggedSingleList::Set(thread, singleList, index, value);
272 return true;
273 }
274 } // namespace panda::ecmascript
275