1/*
2 * Copyright (c) 2021-2024 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#ifndef ECMASCRIPT_BASE_JSON_PARSE_INL_H
17#define ECMASCRIPT_BASE_JSON_PARSE_INL_H
18
19#include <cerrno>
20
21#include "ecmascript/base/json_helper.h"
22#include "ecmascript/base/builtins_base.h"
23#include "ecmascript/base/number_helper.h"
24#include "ecmascript/base/string_helper.h"
25#include "ecmascript/base/utf_helper.h"
26#include "ecmascript/ecma_string-inl.h"
27#include "ecmascript/ecma_string.h"
28#include "ecmascript/js_array.h"
29#include "ecmascript/js_function.h"
30#include "ecmascript/js_handle.h"
31#include "ecmascript/js_map.h"
32#include "ecmascript/global_env.h"
33#include "ecmascript/js_tagged_value.h"
34#include "ecmascript/message_string.h"
35#include "ecmascript/object_factory.h"
36#include "ecmascript/object_fast_operator-inl.h"
37#include "ecmascript/shared_objects/js_shared_map.h"
38
39namespace panda::ecmascript::base {
40constexpr unsigned int UNICODE_DIGIT_LENGTH = 4;
41constexpr unsigned int NUMBER_TEN = 10;
42constexpr unsigned int NUMBER_SIXTEEN = 16;
43constexpr unsigned int INTEGER_MAX_LEN = 9;
44
45constexpr unsigned char CODE_SPACE = 0x20;
46constexpr unsigned char ASCII_END = 0X7F;
47enum class Tokens : uint8_t {
48        // six structural tokens
49        OBJECT = 0,
50        ARRAY,
51        NUMBER,
52        STRING,
53        LITERAL_TRUE,
54        LITERAL_FALSE,
55        LITERAL_NULL,
56        TOKEN_ILLEGAL,
57        MAP,
58    };
59
60struct JsonContinuation {
61    enum class ContinuationType : uint8_t {
62        RETURN = 0,
63        ARRAY,
64        OBJECT,
65        MAP,
66    };
67    JsonContinuation(ContinuationType type, size_t index) : type_(type), index_(index) {}
68
69    ContinuationType type_ {ContinuationType::RETURN};
70    size_t index_ {0};
71};
72
73template<typename T>
74class JsonParser {
75protected:
76    using BigIntMode =  base::JsonHelper::BigIntMode;
77    using ParseReturnType = base::JsonHelper::ParseReturnType;
78    using ParseOptions =  base::JsonHelper::ParseOptions;
79    using TransformType = base::JsonHelper::TransformType;
80    using Text = const T *;
81    using ContType = JsonContinuation::ContinuationType;
82    // Instantiation of the class is prohibited
83    JsonParser() = default;
84    JsonParser(JSThread *thread, TransformType transformType,
85               ParseOptions options = ParseOptions())
86        : thread_(thread), transformType_(transformType), parseOptions_(options)
87    {
88    }
89    virtual ~JsonParser() = default;
90    NO_COPY_SEMANTIC(JsonParser);
91    NO_MOVE_SEMANTIC(JsonParser);
92
93    JSHandle<JSTaggedValue> Launch(Text begin, Text end);
94
95    inline bool IsInObjOrArrayOrMap(ContType type)
96    {
97        return type == ContType::ARRAY || type == ContType::OBJECT || type == ContType::MAP;
98    }
99
100    inline bool EmptyArrayCheck()
101    {
102        GetNextNonSpaceChar();
103        return *current_ == ']';
104    }
105
106    inline bool EmptyObjectCheck()
107    {
108        GetNextNonSpaceChar();
109        return *current_ == '}';
110    }
111
112    JSHandle<JSTaggedValue> GetSJsonPrototype()
113    {
114        JSHandle<JSFunction> sObjFunction(thread_->GetEcmaVM()->GetGlobalEnv()->GetSObjectFunction());
115        JSHandle<JSTaggedValue> jsonPrototype = JSHandle<JSTaggedValue>(thread_, sObjFunction->GetFunctionPrototype());
116        return jsonPrototype;
117    }
118
119    JSHandle<JSTaggedValue> GetSMapPrototype()
120    {
121        auto globalEnv = thread_->GetEcmaVM()->GetGlobalEnv();
122        JSHandle<JSTaggedValue> proto = globalEnv->GetSharedMapPrototype();
123        return proto;
124    }
125
126    JSTaggedValue ParseJSONText();
127
128    JSHandle<JSTaggedValue> CreateJsonArray(JsonContinuation continuation,
129                                            std::vector<JSHandle<JSTaggedValue>> &elementsList);
130
131    JSHandle<JSTaggedValue> CreateSJsonArray([[maybe_unused]] JsonContinuation continuation,
132                                             [[maybe_unused]] std::vector<JSHandle<JSTaggedValue>> &elementsList);
133
134    JSHandle<JSTaggedValue> CreateJsonObject(JsonContinuation continuation,
135                                             std::vector<JSHandle<JSTaggedValue>> &propertyList);
136
137    JSHandle<JSTaggedValue> CreateSJsonObject(JsonContinuation continuation,
138                                              std::vector<JSHandle<JSTaggedValue>> &propertyList);
139
140    JSHandle<JSSharedMap> CreateSharedMap();
141
142    JSHandle<JSMap> CreateMap();
143
144    JSHandle<JSTaggedValue> CreateJsonMap(JsonContinuation continuation,
145                                          std::vector<JSHandle<JSTaggedValue>> &propertyList);
146
147    JSHandle<JSTaggedValue> CreateSJsonMap(JsonContinuation continuation,
148                                           std::vector<JSHandle<JSTaggedValue>> &propertyList);
149
150    JSTaggedValue SetPropertyByValue(const JSHandle<JSTaggedValue> &receiver, const JSHandle<JSTaggedValue> &key,
151                                     const JSHandle<JSTaggedValue> &value);
152
153    JSTaggedValue ParseNumber(bool inObjorArr = false);
154
155    JSTaggedValue ConvertToNumber(const std::string &str, bool negative, bool hasExponent, bool hasDecimal);
156
157    bool ParseStringLength(size_t &length, bool &isAscii, bool inObjorArr);
158
159    bool CheckBackslash(Text &text, Text last, bool &isAscii);
160
161    template<typename Char>
162    void ParseBackslash(Char *&p);
163
164    template<typename Char>
165    void CopyCharWithBackslash(Char *&p);
166
167    JSHandle<JSTaggedValue> ParseStringWithBackslash(bool inObjorArr);
168    virtual void ParticalParseString(std::string& str, Text current, Text nextCurrent) = 0;
169
170    virtual JSHandle<JSTaggedValue> ParseString(bool inObjorArr = false) = 0;
171
172    void SkipEndWhiteSpace();
173
174    void SkipStartWhiteSpace();
175
176    void GetNextNonSpaceChar();
177
178    Tokens ParseToken();
179
180    JSTaggedValue ParseLiteralTrue();
181
182    JSTaggedValue ParseLiteralFalse();
183
184    JSTaggedValue ParseLiteralNull();
185
186    bool MatchText(const char *str, uint32_t matchLen);
187
188    bool ReadNumberRange(bool &isFast, int32_t &fastInteger);
189
190    Text AdvanceLastNumberCharacter(Text current);
191
192    bool IsNumberCharacter(T ch);
193
194    bool IsNumberSignalCharacter(T ch);
195
196    bool IsExponentNumber();
197
198    bool IsDecimalsLegal(bool &hasExponent);
199
200    bool IsExponentLegal(bool &hasExponent);
201
202    bool CheckZeroBeginNumber(bool &hasExponent, bool &hasDecimal);
203
204    bool CheckNonZeroBeginNumber(bool &hasExponent, bool &hasDecimal);
205
206    inline void Advance()
207    {
208        ++current_;
209    }
210
211    inline void AdvanceMultiStep(int step)
212    {
213        current_ += step;
214    }
215
216    Text end_ {nullptr};
217    Text current_ {nullptr};
218    Text range_ {nullptr};
219    JSThread *thread_ {nullptr};
220    ObjectFactory *factory_ {nullptr};
221    GlobalEnv *env_ {nullptr};
222    TransformType transformType_ {TransformType::NORMAL};
223    ParseOptions parseOptions_;
224    JSHandle<JSHClass> initialJSArrayClass_;
225    JSHandle<JSHClass> initialJSObjectClass_;
226};
227
228class PUBLIC_API Utf8JsonParser final : public JsonParser<uint8_t> {
229public:
230    Utf8JsonParser() = default;
231    Utf8JsonParser(JSThread *thread, TransformType transformType,
232                   ParseOptions options = ParseOptions())
233        : JsonParser(thread, transformType, options) {}
234    ~Utf8JsonParser() = default;
235    NO_COPY_SEMANTIC(Utf8JsonParser);
236    NO_MOVE_SEMANTIC(Utf8JsonParser);
237
238    JSHandle<JSTaggedValue> PUBLIC_API Parse(const JSHandle<EcmaString> &strHandle);
239
240private:
241    void ParticalParseString(std::string& str, Text current, Text nextCurrent) override;
242
243    static void UpdatePointersListener(void *utf8Parser);
244
245    JSHandle<JSTaggedValue> ParseString(bool inObjOrArrOrMap  = false) override;
246
247    bool ReadJsonStringRange(bool &isFastString);
248
249    bool IsFastParseJsonString(bool &isFastString);
250
251    const uint8_t *begin_ {nullptr};
252    JSHandle<EcmaString> sourceString_;
253};
254
255class Utf16JsonParser final : public JsonParser<uint16_t> {
256public:
257    Utf16JsonParser() = default;
258    Utf16JsonParser(JSThread *thread, TransformType transformType,
259                    ParseOptions options = ParseOptions())
260        : JsonParser(thread, transformType, options) {}
261    ~Utf16JsonParser() = default;
262    NO_COPY_SEMANTIC(Utf16JsonParser);
263    NO_MOVE_SEMANTIC(Utf16JsonParser);
264
265    JSHandle<JSTaggedValue> Parse(EcmaString *str);
266
267private:
268    void ParticalParseString(std::string& str, Text current, Text nextCurrent) override;
269    JSHandle<JSTaggedValue> ParseString(bool inObjOrArrOrMap = false) override;
270
271    bool ReadJsonStringRange(bool &isFastString, bool &isAscii);
272
273    bool IsFastParseJsonString(bool &isFastString, bool &isAscii);
274
275    bool IsLegalAsciiCharacter(uint16_t c, bool &isAscii);
276};
277
278class Internalize {
279public:
280    using TransformType = base::JsonHelper::TransformType;
281    static JSHandle<JSTaggedValue> InternalizeJsonProperty(JSThread *thread, const JSHandle<JSObject> &holder,
282                                                           const JSHandle<JSTaggedValue> &name,
283                                                           const JSHandle<JSTaggedValue> &receiver,
284                                                           TransformType transformType);
285private:
286    static bool RecurseAndApply(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &name,
287                                const JSHandle<JSTaggedValue> &receiver, TransformType transformType);
288};
289}  // namespace panda::ecmascript::base
290
291#endif  // ECMASCRIPT_BASE_JSON_PARSE_INL_H
292