/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_BASE_JSON_PARSE_INL_H #define ECMASCRIPT_BASE_JSON_PARSE_INL_H #include #include "ecmascript/base/json_helper.h" #include "ecmascript/base/builtins_base.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/base/string_helper.h" #include "ecmascript/ecma_string-inl.h" #include "ecmascript/ecma_string.h" #include "ecmascript/js_array.h" #include "ecmascript/js_function.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_map.h" #include "ecmascript/global_env.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/message_string.h" #include "ecmascript/object_factory.h" #include "ecmascript/object_fast_operator-inl.h" #include "ecmascript/shared_objects/js_shared_map.h" namespace panda::ecmascript::base { constexpr unsigned int UNICODE_DIGIT_LENGTH = 4; constexpr unsigned int NUMBER_TEN = 10; constexpr unsigned int NUMBER_SIXTEEN = 16; constexpr unsigned int INTEGER_MAX_LEN = 9; constexpr unsigned char ASCII_END = 0X7F; enum class Tokens : uint8_t { // six structural tokens OBJECT = 0, ARRAY, NUMBER, STRING, LITERAL_TRUE, LITERAL_FALSE, LITERAL_NULL, TOKEN_ILLEGAL, MAP, }; struct JsonContinuation { enum class ContinuationType : uint8_t { RETURN = 0, ARRAY, OBJECT, MAP, }; JsonContinuation(ContinuationType type, size_t index) : type_(type), index_(index) {} ContinuationType type_ {ContinuationType::RETURN}; size_t index_ {0}; }; template class JsonParser { protected: using BigIntMode = base::JsonHelper::BigIntMode; using ParseReturnType = base::JsonHelper::ParseReturnType; using ParseOptions = base::JsonHelper::ParseOptions; using TransformType = base::JsonHelper::TransformType; using Text = const T *; using ContType = JsonContinuation::ContinuationType; // Instantiation of the class is prohibited JsonParser() = default; JsonParser(JSThread *thread, TransformType transformType, ParseOptions options = ParseOptions()) : thread_(thread), transformType_(transformType), parseOptions_(options) { } virtual ~JsonParser() = default; NO_COPY_SEMANTIC(JsonParser); NO_MOVE_SEMANTIC(JsonParser); JSHandle Launch(Text begin, Text end); inline bool IsInObjOrArrayOrMap(ContType type) { return type == ContType::ARRAY || type == ContType::OBJECT || type == ContType::MAP; } inline bool EmptyArrayCheck() { GetNextNonSpaceChar(); return *current_ == ']'; } inline bool EmptyObjectCheck() { GetNextNonSpaceChar(); return *current_ == '}'; } JSHandle GetSJsonPrototype() { JSHandle sObjFunction(thread_->GetEcmaVM()->GetGlobalEnv()->GetSObjectFunction()); JSHandle jsonPrototype = JSHandle(thread_, sObjFunction->GetFunctionPrototype(thread_)); return jsonPrototype; } JSHandle GetSMapPrototype() { auto globalEnv = thread_->GetEcmaVM()->GetGlobalEnv(); JSHandle proto = globalEnv->GetSharedMapPrototype(); return proto; } template JSTaggedValue ParseJSONText(); JSHandle CreateJsonArray(JsonContinuation continuation, std::vector> &elementsList); JSHandle CreateSJsonArray([[maybe_unused]] JsonContinuation continuation, [[maybe_unused]] std::vector> &elementsList); template JSHandle CreateJsonObject(JsonContinuation continuation, std::vector> &propertyList); template JSHandle CreateSJsonObject(JsonContinuation continuation, std::vector> &propertyList); JSHandle CreateSharedMap(); JSHandle CreateMap(); JSHandle CreateJsonMap(JsonContinuation continuation, std::vector> &propertyList); JSHandle CreateSJsonMap(JsonContinuation continuation, std::vector> &propertyList); JSTaggedValue SetPropertyByValue(const JSHandle &receiver, const JSHandle &key, const JSHandle &value); JSTaggedValue ParseNumber(bool inObjorArr = false); JSTaggedValue ConvertToNumber(const std::string &str, bool negative, bool hasExponent, bool hasDecimal); bool ParseStringLength(size_t &length, bool &isAscii, bool inObjorArr); bool CheckBackslash(Text &text, Text last, bool &isAscii); template void ParseBackslash(Char *&p); template void CopyCharWithBackslash(Char *&p); JSHandle ParseStringWithBackslash(bool inObjorArr); virtual void ParticalParseString(std::string& str, Text current, Text nextCurrent) = 0; virtual JSHandle ParseString(bool inObjorArr = false) = 0; void SkipEndWhiteSpace(); void SkipStartWhiteSpace(); void GetNextNonSpaceChar(); Tokens ParseToken(); JSTaggedValue ParseLiteralTrue(); JSTaggedValue ParseLiteralFalse(); JSTaggedValue ParseLiteralNull(); bool MatchText(const char *str, uint32_t matchLen); bool ReadNumberRange(bool &isFast, int32_t &fastInteger); Text AdvanceLastNumberCharacter(Text current); bool IsNumberCharacter(T ch); bool IsNumberSignalCharacter(T ch); bool IsExponentNumber(); bool IsDecimalsLegal(bool &hasExponent); bool IsExponentLegal(bool &hasExponent); bool CheckZeroBeginNumber(bool &hasExponent, bool &hasDecimal); bool CheckNonZeroBeginNumber(bool &hasExponent, bool &hasDecimal); inline void Advance() { ++current_; } inline void AdvanceMultiStep(int step) { current_ += step; } Text end_ {nullptr}; Text current_ {nullptr}; Text range_ {nullptr}; JSThread *thread_ {nullptr}; ObjectFactory *factory_ {nullptr}; GlobalEnv *env_ {nullptr}; TransformType transformType_ {TransformType::NORMAL}; ParseOptions parseOptions_; JSHandle initialJSArrayClass_; JSHandle initialJSObjectClass_; }; class PUBLIC_API Utf8JsonParser final : public JsonParser { public: Utf8JsonParser() = default; Utf8JsonParser(JSThread *thread, TransformType transformType, ParseOptions options = ParseOptions()) : JsonParser(thread, transformType, options) {} ~Utf8JsonParser() = default; NO_COPY_SEMANTIC(Utf8JsonParser); NO_MOVE_SEMANTIC(Utf8JsonParser); JSHandle PUBLIC_API Parse(const JSHandle &strHandle); private: void ParticalParseString(std::string& str, Text current, Text nextCurrent) override; static void UpdatePointersListener(void *utf8Parser); JSHandle ParseString(bool inObjOrArrOrMap = false) override; bool ReadJsonStringRange(bool &isFastString); bool IsFastParseJsonString(bool &isFastString); const uint8_t *begin_ {nullptr}; JSHandle sourceString_; }; class Utf16JsonParser final : public JsonParser { public: Utf16JsonParser() = default; Utf16JsonParser(JSThread *thread, TransformType transformType, ParseOptions options = ParseOptions()) : JsonParser(thread, transformType, options) {} ~Utf16JsonParser() = default; NO_COPY_SEMANTIC(Utf16JsonParser); NO_MOVE_SEMANTIC(Utf16JsonParser); JSHandle Parse(EcmaString *str); private: void ParticalParseString(std::string& str, Text current, Text nextCurrent) override; JSHandle ParseString(bool inObjOrArrOrMap = false) override; bool ReadJsonStringRange(bool &isFastString, bool &isAscii); bool IsFastParseJsonString(bool &isFastString, bool &isAscii); bool IsLegalAsciiCharacter(uint16_t c, bool &isAscii); }; class Internalize { public: using TransformType = base::JsonHelper::TransformType; static JSHandle InternalizeJsonProperty(JSThread *thread, const JSHandle &holder, const JSHandle &name, const JSHandle &receiver, TransformType transformType); private: static bool RecurseAndApply(JSThread *thread, const JSHandle &holder, const JSHandle &name, const JSHandle &receiver, TransformType transformType); }; } // namespace panda::ecmascript::base #endif // ECMASCRIPT_BASE_JSON_PARSE_INL_H