14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 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/builtins/builtins_json.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/base/json_parser.h"
194514f5e3Sopenharmony_ci#include "ecmascript/base/json_stringifier.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript::builtins {
224514f5e3Sopenharmony_cinamespace {
234514f5e3Sopenharmony_ciusing TransformType = base::JsonHelper::TransformType;
244514f5e3Sopenharmony_ciusing ParseOptions =  base::JsonHelper::ParseOptions;
254514f5e3Sopenharmony_ciusing ParseReturnType = base::JsonHelper::ParseReturnType;
264514f5e3Sopenharmony_ciusing BigIntMode = base::JsonHelper::BigIntMode;
274514f5e3Sopenharmony_ci
284514f5e3Sopenharmony_civoid InitWithTransformType(JSHandle<GlobalEnv> &env, TransformType transformType,
294514f5e3Sopenharmony_ci                           JSMutableHandle<JSFunction> &constructor, SCheckMode &sCheckMode)
304514f5e3Sopenharmony_ci{
314514f5e3Sopenharmony_ci    if (transformType == TransformType::NORMAL || transformType == TransformType::BIGINT) {
324514f5e3Sopenharmony_ci        sCheckMode = SCheckMode::CHECK;
334514f5e3Sopenharmony_ci        constructor.Update(env->GetObjectFunction());
344514f5e3Sopenharmony_ci    } else {
354514f5e3Sopenharmony_ci        sCheckMode = SCheckMode::SKIP;
364514f5e3Sopenharmony_ci        constructor.Update(env->GetSObjectFunction());
374514f5e3Sopenharmony_ci    }
384514f5e3Sopenharmony_ci}
394514f5e3Sopenharmony_ci}  // namespace
404514f5e3Sopenharmony_ci
414514f5e3Sopenharmony_ciusing Internalize = base::Internalize;
424514f5e3Sopenharmony_ci
434514f5e3Sopenharmony_ciJSTaggedValue BuiltinsJson::Parse(EcmaRuntimeCallInfo *argv)
444514f5e3Sopenharmony_ci{
454514f5e3Sopenharmony_ci    return ParseWithTransformType(argv, TransformType::NORMAL);
464514f5e3Sopenharmony_ci}
474514f5e3Sopenharmony_ci
484514f5e3Sopenharmony_ciJSTaggedValue BuiltinsSendableJson::Parse(EcmaRuntimeCallInfo *argv)
494514f5e3Sopenharmony_ci{
504514f5e3Sopenharmony_ci    uint32_t argc = argv->GetArgsNumber();
514514f5e3Sopenharmony_ci    if (argc >= 2) { // 2: two args
524514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> reviverVal = GetCallArg(argv, 1);
534514f5e3Sopenharmony_ci        if (!reviverVal->IsUndefined()) {
544514f5e3Sopenharmony_ci            THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), GET_MESSAGE_STRING(ReviverOnlySupportUndefined),
554514f5e3Sopenharmony_ci                                        JSTaggedValue::Exception());
564514f5e3Sopenharmony_ci        }
574514f5e3Sopenharmony_ci    }
584514f5e3Sopenharmony_ci    return BuiltinsJson::ParseWithTransformType(argv, TransformType::SENDABLE);
594514f5e3Sopenharmony_ci}
604514f5e3Sopenharmony_ci
614514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigIntJson::Parse(EcmaRuntimeCallInfo *argv)
624514f5e3Sopenharmony_ci{
634514f5e3Sopenharmony_ci    return BuiltinsJson::ParseWithTransformType(argv, TransformType::BIGINT);
644514f5e3Sopenharmony_ci}
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_ci// 24.5.1
674514f5e3Sopenharmony_ciJSTaggedValue BuiltinsJson::ParseWithTransformType(EcmaRuntimeCallInfo *argv, TransformType transformType)
684514f5e3Sopenharmony_ci{
694514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Json, Parse);
704514f5e3Sopenharmony_ci    ASSERT(argv);
714514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
724514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
734514f5e3Sopenharmony_ci
744514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
754514f5e3Sopenharmony_ci
764514f5e3Sopenharmony_ci    uint32_t argc = argv->GetArgsNumber();
774514f5e3Sopenharmony_ci    if (argc == 0) {
784514f5e3Sopenharmony_ci        JSHandle<JSObject> syntaxError = factory->GetJSError(base::ErrorType::SYNTAX_ERROR,
794514f5e3Sopenharmony_ci                                                             "arg is empty", StackCheck::NO);
804514f5e3Sopenharmony_ci        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, syntaxError.GetTaggedValue(), JSTaggedValue::Exception());
814514f5e3Sopenharmony_ci    }
824514f5e3Sopenharmony_ci
834514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> msg = GetCallArg(argv, 0);
844514f5e3Sopenharmony_ci    JSMutableHandle<JSTaggedValue> reviverVal(thread, JSTaggedValue::Undefined());
854514f5e3Sopenharmony_ci    ParseOptions parseOptions;
864514f5e3Sopenharmony_ci    if (argc == 2) {  // 2: two args
874514f5e3Sopenharmony_ci        reviverVal.Update(GetCallArg(argv, 1));
884514f5e3Sopenharmony_ci    } else if (argc == 3 && base::JsonHelper::IsTypeSupportBigInt(transformType)) { // 3: three args
894514f5e3Sopenharmony_ci        reviverVal.Update(GetCallArg(argv, 1));
904514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> options = GetCallArg(argv, 2); // 2: two args
914514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> modeKey(factory->NewFromStdString("bigIntMode"));
924514f5e3Sopenharmony_ci        JSHandle<JSTaggedValue> typeKey(factory->NewFromStdString("parseReturnType"));
934514f5e3Sopenharmony_ci        if (options->IsECMAObject()) {
944514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> type = JSTaggedValue::GetProperty(thread, options, typeKey).GetValue();
954514f5e3Sopenharmony_ci            if (transformType == TransformType::SENDABLE && type->IsInt() && type->GetInt() == 1) { // 1: map
964514f5e3Sopenharmony_ci                parseOptions.returnType = ParseReturnType::MAP;
974514f5e3Sopenharmony_ci            }
984514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> modeValue = JSTaggedValue::GetProperty(thread, options, modeKey).GetValue();
994514f5e3Sopenharmony_ci            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1004514f5e3Sopenharmony_ci            if (modeValue->IsInt()) {
1014514f5e3Sopenharmony_ci                int val = modeValue->GetInt();
1024514f5e3Sopenharmony_ci                if (val == 2) { // 2: bigIntMode
1034514f5e3Sopenharmony_ci                    parseOptions.bigIntMode = BigIntMode::ALWAYS_PARSE_AS_BIGINT;
1044514f5e3Sopenharmony_ci                } else if (val == 1) {
1054514f5e3Sopenharmony_ci                    parseOptions.bigIntMode = BigIntMode::PARSE_AS_BIGINT;
1064514f5e3Sopenharmony_ci                }
1074514f5e3Sopenharmony_ci            }
1084514f5e3Sopenharmony_ci        }
1094514f5e3Sopenharmony_ci    }
1104514f5e3Sopenharmony_ci    return ParseWithTransformType(thread->GetEcmaVM(), msg, reviverVal, transformType, parseOptions);
1114514f5e3Sopenharmony_ci}
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ciJSTaggedValue BuiltinsJson::ParseWithTransformType(const EcmaVM *vm, JSHandle<JSTaggedValue> &msg,
1144514f5e3Sopenharmony_ci                                                   JSHandle<JSTaggedValue> &reviverVal, TransformType transformType,
1154514f5e3Sopenharmony_ci                                                   ParseOptions options)
1164514f5e3Sopenharmony_ci{
1174514f5e3Sopenharmony_ci    JSThread *thread = vm->GetJSThread();
1184514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
1214514f5e3Sopenharmony_ci    JSHandle<EcmaString> parseString = JSTaggedValue::ToString(thread, msg);
1224514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1234514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> result;
1244514f5e3Sopenharmony_ci    if (EcmaStringAccessor(parseString).IsUtf8()) {
1254514f5e3Sopenharmony_ci        panda::ecmascript::base::Utf8JsonParser parser(thread, transformType, options);
1264514f5e3Sopenharmony_ci        result = parser.Parse(parseString);
1274514f5e3Sopenharmony_ci    } else {
1284514f5e3Sopenharmony_ci        panda::ecmascript::base::Utf16JsonParser parser(thread, transformType, options);
1294514f5e3Sopenharmony_ci        result = parser.Parse(*parseString);
1304514f5e3Sopenharmony_ci    }
1314514f5e3Sopenharmony_ci    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1324514f5e3Sopenharmony_ci    JSTaggedValue reviver = JSTaggedValue::Undefined();
1334514f5e3Sopenharmony_ci    if (reviverVal->IsJSFunction()) {
1344514f5e3Sopenharmony_ci        reviver = reviverVal.GetTaggedValue();
1354514f5e3Sopenharmony_ci        if (reviver.IsCallable()) {
1364514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> callbackfnHandle(thread, reviver);
1374514f5e3Sopenharmony_ci            // Let root be ! OrdinaryObjectCreate(%Object.prototype%).
1384514f5e3Sopenharmony_ci            JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
1394514f5e3Sopenharmony_ci            JSMutableHandle<JSFunction> constructor(thread, JSTaggedValue::Undefined());
1404514f5e3Sopenharmony_ci            SCheckMode sCheckMode = SCheckMode::CHECK;
1414514f5e3Sopenharmony_ci            InitWithTransformType(env, transformType, constructor, sCheckMode);
1424514f5e3Sopenharmony_ci            JSHandle<JSObject> root = factory->NewJSObjectByConstructor(constructor);
1434514f5e3Sopenharmony_ci            // Let rootName be the empty String.
1444514f5e3Sopenharmony_ci            JSHandle<JSTaggedValue> rootName(factory->GetEmptyString());
1454514f5e3Sopenharmony_ci            // Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered).
1464514f5e3Sopenharmony_ci            bool success = JSObject::CreateDataProperty(thread, root, rootName, result, sCheckMode);
1474514f5e3Sopenharmony_ci            if (success) {
1484514f5e3Sopenharmony_ci                result = Internalize::InternalizeJsonProperty(thread, root, rootName, callbackfnHandle, transformType);
1494514f5e3Sopenharmony_ci                RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
1504514f5e3Sopenharmony_ci            }
1514514f5e3Sopenharmony_ci        }
1524514f5e3Sopenharmony_ci    }
1534514f5e3Sopenharmony_ci    if (transformType == TransformType::SENDABLE) {
1544514f5e3Sopenharmony_ci        if (result->IsHeapObject() && !result->IsJSShared() && !result->IsString()) {
1554514f5e3Sopenharmony_ci            THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(ClassNotDerivedFromShared),
1564514f5e3Sopenharmony_ci                                        JSTaggedValue::Exception());
1574514f5e3Sopenharmony_ci        }
1584514f5e3Sopenharmony_ci    }
1594514f5e3Sopenharmony_ci    return result.GetTaggedValue();
1604514f5e3Sopenharmony_ci}
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ci// 24.5.2
1634514f5e3Sopenharmony_ciJSTaggedValue BuiltinsJson::Stringify(EcmaRuntimeCallInfo *argv)
1644514f5e3Sopenharmony_ci{
1654514f5e3Sopenharmony_ci    return BuiltinsJson::StringifyWithTransformType(argv, TransformType::NORMAL);
1664514f5e3Sopenharmony_ci}
1674514f5e3Sopenharmony_ci
1684514f5e3Sopenharmony_ciJSTaggedValue BuiltinsSendableJson::Stringify(EcmaRuntimeCallInfo *argv)
1694514f5e3Sopenharmony_ci{
1704514f5e3Sopenharmony_ci    return BuiltinsJson::StringifyWithTransformType(argv, TransformType::SENDABLE);
1714514f5e3Sopenharmony_ci}
1724514f5e3Sopenharmony_ci
1734514f5e3Sopenharmony_ciJSTaggedValue BuiltinsBigIntJson::Stringify(EcmaRuntimeCallInfo *argv)
1744514f5e3Sopenharmony_ci{
1754514f5e3Sopenharmony_ci    return BuiltinsJson::StringifyWithTransformType(argv, TransformType::BIGINT);
1764514f5e3Sopenharmony_ci}
1774514f5e3Sopenharmony_ci
1784514f5e3Sopenharmony_ciJSTaggedValue BuiltinsJson::StringifyWithTransformType(EcmaRuntimeCallInfo *argv, TransformType transformType)
1794514f5e3Sopenharmony_ci{
1804514f5e3Sopenharmony_ci    BUILTINS_API_TRACE(argv->GetThread(), Json, Stringify);
1814514f5e3Sopenharmony_ci    ASSERT(argv);
1824514f5e3Sopenharmony_ci    JSThread *thread = argv->GetThread();
1834514f5e3Sopenharmony_ci    [[maybe_unused]] EcmaHandleScope handleScope(thread);
1844514f5e3Sopenharmony_ci
1854514f5e3Sopenharmony_ci    uint32_t argc = argv->GetArgsNumber();
1864514f5e3Sopenharmony_ci    JSTaggedValue value = GetCallArg(argv, 0).GetTaggedValue();
1874514f5e3Sopenharmony_ci    JSTaggedValue replacer = JSTaggedValue::Undefined();
1884514f5e3Sopenharmony_ci    JSTaggedValue gap = JSTaggedValue::Undefined();
1894514f5e3Sopenharmony_ci
1904514f5e3Sopenharmony_ci    if (argc == 2) {  // 2: 2 args
1914514f5e3Sopenharmony_ci        replacer = GetCallArg(argv, 1).GetTaggedValue();
1924514f5e3Sopenharmony_ci    } else if (argc == 3) {  // 3: 3 args
1934514f5e3Sopenharmony_ci        replacer = GetCallArg(argv, 1).GetTaggedValue();
1944514f5e3Sopenharmony_ci        gap = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD).GetTaggedValue();
1954514f5e3Sopenharmony_ci    }
1964514f5e3Sopenharmony_ci
1974514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handleValue(thread, value);
1984514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handleReplacer(thread, replacer);
1994514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> handleGap(thread, gap);
2004514f5e3Sopenharmony_ci    panda::ecmascript::base::JsonStringifier stringifier(thread, transformType);
2014514f5e3Sopenharmony_ci    JSHandle<JSTaggedValue> result = stringifier.Stringify(handleValue, handleReplacer, handleGap);
2024514f5e3Sopenharmony_ci
2034514f5e3Sopenharmony_ci    return result.GetTaggedValue();
2044514f5e3Sopenharmony_ci}
2054514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::builtins
206