• 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_stack.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_api/js_api_stack_iterator.h"
21 #include "ecmascript/js_function.h"
22 
23 namespace panda::ecmascript::containers {
StackConstructor(EcmaRuntimeCallInfo * argv)24 JSTaggedValue ContainersStack::StackConstructor(EcmaRuntimeCallInfo *argv)
25 {
26     ASSERT(argv != nullptr);
27     BUILTINS_API_TRACE(argv->GetThread(), Stack, Constructor);
28     JSThread *thread = argv->GetThread();
29     [[maybe_unused]] EcmaHandleScope handleScope(thread);
30     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
31     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
32     if (newTarget->IsUndefined()) {
33         JSTaggedValue error =
34             ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
35                                           "The List's constructor cannot be directly invoked");
36         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
37     }
38     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
39     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
40     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
41 
42     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(obj);
43     stack->SetTop(-1);
44 
45     return obj.GetTaggedValue();
46 }
47 
IsEmpty(EcmaRuntimeCallInfo * argv)48 JSTaggedValue ContainersStack::IsEmpty(EcmaRuntimeCallInfo *argv)
49 {
50     ASSERT(argv != nullptr);
51     BUILTINS_API_TRACE(argv->GetThread(), Stack, IsEmpty);
52     JSThread *thread = argv->GetThread();
53     [[maybe_unused]] EcmaHandleScope handleScope(thread);
54     JSHandle<JSTaggedValue> self = GetThis(argv);
55 
56     if (!self->IsJSAPIStack()) {
57         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
58             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
59         } else {
60             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
61                                                                 "The isEmpty method cannot be bound");
62             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
63         }
64     }
65     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
66     bool judge = stack->Empty();
67 
68     return GetTaggedBoolean(judge);
69 }
70 
Push(EcmaRuntimeCallInfo * argv)71 JSTaggedValue ContainersStack::Push(EcmaRuntimeCallInfo *argv)
72 {
73     ASSERT(argv != nullptr);
74     BUILTINS_API_TRACE(argv->GetThread(), Stack, Push);
75     JSThread *thread = argv->GetThread();
76     [[maybe_unused]] EcmaHandleScope handleScope(thread);
77     JSHandle<JSTaggedValue> self = GetThis(argv);
78 
79     if (!self->IsJSAPIStack()) {
80         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
81             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
82         } else {
83             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
84                                                                 "The push method cannot be bound");
85             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
86         }
87     }
88 
89     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
90     JSTaggedValue jsValue = JSAPIStack::Push(thread, JSHandle<JSAPIStack>::Cast(self), value);
91     return jsValue;
92 }
93 
Peek(EcmaRuntimeCallInfo * argv)94 JSTaggedValue ContainersStack::Peek(EcmaRuntimeCallInfo *argv)
95 {
96     ASSERT(argv != nullptr);
97     BUILTINS_API_TRACE(argv->GetThread(), Stack, Peek);
98     JSThread *thread = argv->GetThread();
99     [[maybe_unused]] EcmaHandleScope handleScope(thread);
100     JSHandle<JSTaggedValue> self = GetThis(argv);
101 
102     if (!self->IsJSAPIStack()) {
103         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
104             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
105         } else {
106             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
107                                                                 "The peek method cannot be bound");
108             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
109         }
110     }
111 
112     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
113     JSTaggedValue jsValue = stack->Peek();
114     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
115     return jsValue;
116 }
117 
Locate(EcmaRuntimeCallInfo * argv)118 JSTaggedValue ContainersStack::Locate(EcmaRuntimeCallInfo *argv)
119 {
120     ASSERT(argv != nullptr);
121     BUILTINS_API_TRACE(argv->GetThread(), Stack, Locate);
122     JSThread *thread = argv->GetThread();
123     [[maybe_unused]] EcmaHandleScope handleScope(thread);
124     JSHandle<JSTaggedValue> self = GetThis(argv);
125 
126     if (!self->IsJSAPIStack()) {
127         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
128             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
129         } else {
130             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
131                                                                 "The locate method cannot be bound");
132             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
133         }
134     }
135 
136     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
137     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
138     int num = stack->Search(value);
139     return JSTaggedValue(num);
140 }
141 
Pop(EcmaRuntimeCallInfo * argv)142 JSTaggedValue ContainersStack::Pop(EcmaRuntimeCallInfo *argv)
143 {
144     ASSERT(argv != nullptr);
145     BUILTINS_API_TRACE(argv->GetThread(), Stack, Pop);
146     JSThread *thread = argv->GetThread();
147     [[maybe_unused]] EcmaHandleScope handleScope(thread);
148     JSHandle<JSTaggedValue> self = GetThis(argv);
149 
150     if (!self->IsJSAPIStack()) {
151         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
152             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
153         } else {
154             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
155                                                                 "The pop method cannot be bound");
156             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
157         }
158     }
159 
160     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self);
161     JSTaggedValue jsValue = stack->Pop(thread);
162     return jsValue;
163 }
164 
ForEach(EcmaRuntimeCallInfo * argv)165 JSTaggedValue ContainersStack::ForEach(EcmaRuntimeCallInfo *argv)
166 {
167     ASSERT(argv != nullptr);
168     BUILTINS_API_TRACE(argv->GetThread(), Stack, ForEach);
169     JSThread *thread = argv->GetThread();
170     [[maybe_unused]] EcmaHandleScope handleScope(thread);
171 
172     JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
173     if (!thisHandle->IsJSAPIStack()) {
174         if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIStack()) {
175             thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
176         } else {
177             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
178                                                                 "The forEach method cannot be bound");
179             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
180         }
181     }
182 
183     JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(thisHandle);
184     int32_t len = stack->GetSize();
185     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
186 
187     JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
188     if (!callbackFnHandle->IsCallable()) {
189         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
190         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
191         CString errorMsg =
192             "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
193         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
194         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
195     }
196 
197     JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
198     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
199     uint32_t k = 0;
200     uint32_t actLen = static_cast<uint32_t>(len + 1);
201     while (k < actLen) {
202         JSTaggedValue kValue = stack->Get(k);
203         EcmaRuntimeCallInfo *info =
204             EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, 3); // 3:three args
205         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
206         info->SetCallArg(kValue, JSTaggedValue(k), thisHandle.GetTaggedValue());
207         JSTaggedValue funcResult = JSFunction::Call(info);
208         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
209         k++;
210     }
211     return JSTaggedValue::Undefined();
212 }
213 
Iterator(EcmaRuntimeCallInfo * argv)214 JSTaggedValue ContainersStack::Iterator(EcmaRuntimeCallInfo *argv)
215 {
216     ASSERT(argv != nullptr);
217     BUILTINS_API_TRACE(argv->GetThread(), Stack, Iterator);
218     JSThread *thread = argv->GetThread();
219     [[maybe_unused]] EcmaHandleScope handleScope(thread);
220     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
221     JSHandle<JSTaggedValue> self = GetThis(argv);
222     if (!self->IsJSAPIStack()) {
223         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
224             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
225         } else {
226             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
227                                                                 "The Symbol.iterator method cannot be bound");
228             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
229         }
230     }
231     JSHandle<JSAPIStackIterator> iter(factory->NewJSAPIStackIterator(JSHandle<JSAPIStack>::Cast(self)));
232     return iter.GetTaggedValue();
233 }
234 
GetLength(EcmaRuntimeCallInfo * argv)235 JSTaggedValue ContainersStack::GetLength(EcmaRuntimeCallInfo *argv)
236 {
237     ASSERT(argv != nullptr);
238     BUILTINS_API_TRACE(argv->GetThread(), Stack, GetLength);
239     JSThread *thread = argv->GetThread();
240     [[maybe_unused]] EcmaHandleScope handleScope(thread);
241     JSHandle<JSTaggedValue> self = GetThis(argv);
242 
243     if (!self->IsJSAPIStack()) {
244         if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) {
245             self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
246         } else {
247             JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
248                                                                 "The getLength method cannot be bound");
249             THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
250         }
251     }
252 
253     int32_t len = (JSHandle<JSAPIStack>::Cast(self))->GetSize();
254     return JSTaggedValue(len + 1);
255 }
256 }  // namespace panda::ecmascript::containers
257