14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/containers/containers_stack.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/containers/containers_errors.h" 194514f5e3Sopenharmony_ci#include "ecmascript/interpreter/interpreter.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_api/js_api_stack_iterator.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_function.h" 224514f5e3Sopenharmony_ci 234514f5e3Sopenharmony_cinamespace panda::ecmascript::containers { 244514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::StackConstructor(EcmaRuntimeCallInfo *argv) 254514f5e3Sopenharmony_ci{ 264514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 274514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, Constructor); 284514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 294514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 304514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 314514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 324514f5e3Sopenharmony_ci if (newTarget->IsUndefined()) { 334514f5e3Sopenharmony_ci JSTaggedValue error = 344514f5e3Sopenharmony_ci ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR, 354514f5e3Sopenharmony_ci "The List's constructor cannot be directly invoked"); 364514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 374514f5e3Sopenharmony_ci } 384514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 394514f5e3Sopenharmony_ci JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 404514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 414514f5e3Sopenharmony_ci 424514f5e3Sopenharmony_ci JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(obj); 434514f5e3Sopenharmony_ci stack->SetTop(-1); 444514f5e3Sopenharmony_ci 454514f5e3Sopenharmony_ci return obj.GetTaggedValue(); 464514f5e3Sopenharmony_ci} 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::IsEmpty(EcmaRuntimeCallInfo *argv) 494514f5e3Sopenharmony_ci{ 504514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 514514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, IsEmpty); 524514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 534514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 544514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 554514f5e3Sopenharmony_ci 564514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 574514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 584514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 594514f5e3Sopenharmony_ci } else { 604514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 614514f5e3Sopenharmony_ci "The isEmpty method cannot be bound"); 624514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci } 654514f5e3Sopenharmony_ci JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self); 664514f5e3Sopenharmony_ci bool judge = stack->Empty(); 674514f5e3Sopenharmony_ci 684514f5e3Sopenharmony_ci return GetTaggedBoolean(judge); 694514f5e3Sopenharmony_ci} 704514f5e3Sopenharmony_ci 714514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::Push(EcmaRuntimeCallInfo *argv) 724514f5e3Sopenharmony_ci{ 734514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 744514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, Push); 754514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 764514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 774514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 784514f5e3Sopenharmony_ci 794514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 804514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 814514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 824514f5e3Sopenharmony_ci } else { 834514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 844514f5e3Sopenharmony_ci "The push method cannot be bound"); 854514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 864514f5e3Sopenharmony_ci } 874514f5e3Sopenharmony_ci } 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 904514f5e3Sopenharmony_ci JSTaggedValue jsValue = JSAPIStack::Push(thread, JSHandle<JSAPIStack>::Cast(self), value); 914514f5e3Sopenharmony_ci return jsValue; 924514f5e3Sopenharmony_ci} 934514f5e3Sopenharmony_ci 944514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::Peek(EcmaRuntimeCallInfo *argv) 954514f5e3Sopenharmony_ci{ 964514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 974514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, Peek); 984514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 994514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 1004514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 1014514f5e3Sopenharmony_ci 1024514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 1034514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 1044514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 1054514f5e3Sopenharmony_ci } else { 1064514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 1074514f5e3Sopenharmony_ci "The peek method cannot be bound"); 1084514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci } 1114514f5e3Sopenharmony_ci 1124514f5e3Sopenharmony_ci JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self); 1134514f5e3Sopenharmony_ci JSTaggedValue jsValue = stack->Peek(); 1144514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1154514f5e3Sopenharmony_ci return jsValue; 1164514f5e3Sopenharmony_ci} 1174514f5e3Sopenharmony_ci 1184514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::Locate(EcmaRuntimeCallInfo *argv) 1194514f5e3Sopenharmony_ci{ 1204514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 1214514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, Locate); 1224514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1234514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 1244514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 1254514f5e3Sopenharmony_ci 1264514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 1274514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 1284514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 1294514f5e3Sopenharmony_ci } else { 1304514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 1314514f5e3Sopenharmony_ci "The locate method cannot be bound"); 1324514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 1334514f5e3Sopenharmony_ci } 1344514f5e3Sopenharmony_ci } 1354514f5e3Sopenharmony_ci 1364514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> value = GetCallArg(argv, 0); 1374514f5e3Sopenharmony_ci JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self); 1384514f5e3Sopenharmony_ci int num = stack->Search(value); 1394514f5e3Sopenharmony_ci return JSTaggedValue(num); 1404514f5e3Sopenharmony_ci} 1414514f5e3Sopenharmony_ci 1424514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::Pop(EcmaRuntimeCallInfo *argv) 1434514f5e3Sopenharmony_ci{ 1444514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 1454514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, Pop); 1464514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1474514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 1484514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 1494514f5e3Sopenharmony_ci 1504514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 1514514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 1524514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 1534514f5e3Sopenharmony_ci } else { 1544514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 1554514f5e3Sopenharmony_ci "The pop method cannot be bound"); 1564514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci } 1594514f5e3Sopenharmony_ci 1604514f5e3Sopenharmony_ci JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(self); 1614514f5e3Sopenharmony_ci JSTaggedValue jsValue = stack->Pop(); 1624514f5e3Sopenharmony_ci return jsValue; 1634514f5e3Sopenharmony_ci} 1644514f5e3Sopenharmony_ci 1654514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::ForEach(EcmaRuntimeCallInfo *argv) 1664514f5e3Sopenharmony_ci{ 1674514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 1684514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, ForEach); 1694514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1704514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 1714514f5e3Sopenharmony_ci 1724514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 1734514f5e3Sopenharmony_ci if (!thisHandle->IsJSAPIStack()) { 1744514f5e3Sopenharmony_ci if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPIStack()) { 1754514f5e3Sopenharmony_ci thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget()); 1764514f5e3Sopenharmony_ci } else { 1774514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 1784514f5e3Sopenharmony_ci "The forEach method cannot be bound"); 1794514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 1804514f5e3Sopenharmony_ci } 1814514f5e3Sopenharmony_ci } 1824514f5e3Sopenharmony_ci 1834514f5e3Sopenharmony_ci JSHandle<JSAPIStack> stack = JSHandle<JSAPIStack>::Cast(thisHandle); 1844514f5e3Sopenharmony_ci int32_t len = stack->GetSize(); 1854514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1864514f5e3Sopenharmony_ci 1874514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0); 1884514f5e3Sopenharmony_ci if (!callbackFnHandle->IsCallable()) { 1894514f5e3Sopenharmony_ci JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue()); 1904514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1914514f5e3Sopenharmony_ci CString errorMsg = 1924514f5e3Sopenharmony_ci "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result); 1934514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 1944514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci 1974514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1); 1984514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 1994514f5e3Sopenharmony_ci uint32_t k = 0; 2004514f5e3Sopenharmony_ci uint32_t actLen = static_cast<uint32_t>(len + 1); 2014514f5e3Sopenharmony_ci while (k < actLen) { 2024514f5e3Sopenharmony_ci JSTaggedValue kValue = stack->Get(k); 2034514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 2044514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, 3); // 3:three args 2054514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2064514f5e3Sopenharmony_ci info->SetCallArg(kValue, JSTaggedValue(k), thisHandle.GetTaggedValue()); 2074514f5e3Sopenharmony_ci JSTaggedValue funcResult = JSFunction::Call(info); 2084514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); 2094514f5e3Sopenharmony_ci k++; 2104514f5e3Sopenharmony_ci } 2114514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 2124514f5e3Sopenharmony_ci} 2134514f5e3Sopenharmony_ci 2144514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::Iterator(EcmaRuntimeCallInfo *argv) 2154514f5e3Sopenharmony_ci{ 2164514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 2174514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, Iterator); 2184514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 2194514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 2204514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 2214514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 2224514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 2234514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 2244514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 2254514f5e3Sopenharmony_ci } else { 2264514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 2274514f5e3Sopenharmony_ci "The Symbol.iterator method cannot be bound"); 2284514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 2294514f5e3Sopenharmony_ci } 2304514f5e3Sopenharmony_ci } 2314514f5e3Sopenharmony_ci JSHandle<JSAPIStackIterator> iter(factory->NewJSAPIStackIterator(JSHandle<JSAPIStack>::Cast(self))); 2324514f5e3Sopenharmony_ci return iter.GetTaggedValue(); 2334514f5e3Sopenharmony_ci} 2344514f5e3Sopenharmony_ci 2354514f5e3Sopenharmony_ciJSTaggedValue ContainersStack::GetLength(EcmaRuntimeCallInfo *argv) 2364514f5e3Sopenharmony_ci{ 2374514f5e3Sopenharmony_ci ASSERT(argv != nullptr); 2384514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), Stack, GetLength); 2394514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 2404514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 2414514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> self = GetThis(argv); 2424514f5e3Sopenharmony_ci 2434514f5e3Sopenharmony_ci if (!self->IsJSAPIStack()) { 2444514f5e3Sopenharmony_ci if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIStack()) { 2454514f5e3Sopenharmony_ci self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 2464514f5e3Sopenharmony_ci } else { 2474514f5e3Sopenharmony_ci JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 2484514f5e3Sopenharmony_ci "The getLength method cannot be bound"); 2494514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 2504514f5e3Sopenharmony_ci } 2514514f5e3Sopenharmony_ci } 2524514f5e3Sopenharmony_ci 2534514f5e3Sopenharmony_ci int32_t len = (JSHandle<JSAPIStack>::Cast(self))->GetSize(); 2544514f5e3Sopenharmony_ci return JSTaggedValue(len + 1); 2554514f5e3Sopenharmony_ci} 2564514f5e3Sopenharmony_ci} // namespace panda::ecmascript::containers 257