• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_parser.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/global_env.h"
32 #include "ecmascript/js_tagged_value.h"
33 #include "ecmascript/object_factory.h"
34 #include "ecmascript/object_fast_operator-inl.h"
35 
36 namespace panda::ecmascript::base {
37 constexpr unsigned int UNICODE_DIGIT_LENGTH = 4;
38 constexpr unsigned int NUMBER_TEN = 10;
39 constexpr unsigned int NUMBER_SIXTEEN = 16;
40 constexpr unsigned int INTEGER_MAX_LEN = 9;
41 
42 constexpr unsigned char CODE_SPACE = 0x20;
43 constexpr unsigned char ASCII_END = 0X7F;
44 enum class Tokens : uint8_t {
45         // six structural tokens
46         OBJECT = 0,
47         ARRAY,
48         NUMBER,
49         STRING,
50         LITERAL_TRUE,
51         LITERAL_FALSE,
52         LITERAL_NULL,
53         TOKEN_ILLEGAL,
54     };
55 
56 struct JsonContinuation {
57     enum class ContinuationType : uint8_t {
58         RETURN = 0,
59         ARRAY,
60         OBJECT,
61     };
JsonContinuationJsonContinuation62     JsonContinuation(ContinuationType type, size_t index) : type_(type), index_(index) {}
63 
64     ContinuationType type_ {ContinuationType::RETURN};
65     size_t index_ {0};
66 };
67 
68 template<typename T>
69 class JsonParser {
70 protected:
71     using Text = const T *;
72     using ContType = JsonContinuation::ContinuationType;
73     // Instantiation of the class is prohibited
74     JsonParser() = default;
JsonParser(JSThread * thread)75     explicit JsonParser(JSThread *thread) : thread_(thread) {}
76     ~JsonParser() = default;
77     NO_COPY_SEMANTIC(JsonParser);
78     NO_MOVE_SEMANTIC(JsonParser);
79 
Launch(Text begin,Text end)80     JSHandle<JSTaggedValue> Launch(Text begin, Text end)
81     {
82         // check empty
83         if (UNLIKELY(begin == end)) {
84             return JSHandle<JSTaggedValue>(thread_, [&]() -> JSTaggedValue {
85                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
86             }());
87         }
88         end_ = end - 1;
89         current_ = begin;
90 
91         auto vm = thread_->GetEcmaVM();
92         factory_ = vm->GetFactory();
93         env_ = *vm->GetGlobalEnv();
94         JSHandle<JSFunction> arrayFunc(env_->GetArrayFunction());
95         initialJSArrayClass_ = JSHandle<JSHClass>(thread_, JSFunction::GetOrCreateInitialJSHClass(thread_, arrayFunc));
96         JSHandle<JSFunction> objectFunc(env_->GetObjectFunction());
97         initialJSObjectClass_ =
98             JSHandle<JSHClass>(thread_, JSFunction::GetOrCreateInitialJSHClass(thread_, objectFunc));
99 
100         SkipEndWhiteSpace();
101         range_ = end_;
102         JSTaggedValue result = ParseJSONText();
103         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
104         return JSHandle<JSTaggedValue>(thread_, result);
105     }
106 
IsInObjOrArray(ContType type)107     inline bool IsInObjOrArray(ContType type)
108     {
109         return type == ContType::ARRAY || type == ContType::OBJECT;
110     }
111 
EmptyArrayCheck()112     inline bool EmptyArrayCheck()
113     {
114         GetNextNonSpaceChar();
115         return *current_ == ']';
116     }
117 
EmptyObjectCheck()118     inline bool EmptyObjectCheck()
119     {
120         GetNextNonSpaceChar();
121         return *current_ == '}';
122     }
123 
ParseJSONText()124     JSTaggedValue ParseJSONText()
125     {
126         JSHandle<JSTaggedValue> parseValue;
127         std::vector<JsonContinuation> continuationList;
128         std::vector<JSHandle<JSTaggedValue>> elementsList;
129         std::vector<JSHandle<JSTaggedValue>> propertyList;
130         continuationList.reserve(16); // 16: initial capacity
131         elementsList.reserve(16); // 16: initial capacity
132         propertyList.reserve(16); // 16: initial capacity
133         JsonContinuation continuation(ContType::RETURN, 0);
134         while (true) {
135             while (true) {
136                 SkipStartWhiteSpace();
137                 Tokens token = ParseToken();
138                 switch (token) {
139                     case Tokens::OBJECT:
140                         if (EmptyObjectCheck()) {
141                             parseValue = JSHandle<JSTaggedValue>(factory_->NewJSObject(initialJSObjectClass_));
142                             GetNextNonSpaceChar();
143                             break;
144                         }
145                         continuationList.emplace_back(std::move(continuation));
146                         continuation = JsonContinuation(ContType::OBJECT, propertyList.size());
147 
148                         SkipStartWhiteSpace();
149                         if (*current_ == '"') {
150                             propertyList.emplace_back(JSHandle<JSTaggedValue>(thread_, ParseString(true)));
151                             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
152                         } else {
153                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object Prop in JSON",
154                                                           JSTaggedValue::Exception());
155                         }
156                         SkipStartWhiteSpace();
157                         if (*current_ == ':') {
158                             Advance();
159                         } else {
160                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON",
161                                                           JSTaggedValue::Exception());
162                         }
163                         continue;
164                     case Tokens::ARRAY:
165                         if (EmptyArrayCheck()) {
166                             parseValue = JSHandle<JSTaggedValue>(factory_->NewJSArray(0, initialJSArrayClass_));
167                             GetNextNonSpaceChar();
168                             break;
169                         }
170                         continuationList.emplace_back(std::move(continuation));
171                         continuation = JsonContinuation(ContType::ARRAY, elementsList.size());
172                         continue;
173                     case Tokens::LITERAL_TRUE:
174                         parseValue = JSHandle<JSTaggedValue>(thread_, ParseLiteralTrue());
175                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
176                         break;
177                     case Tokens::LITERAL_FALSE:
178                         parseValue = JSHandle<JSTaggedValue>(thread_, ParseLiteralFalse());
179                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
180                         break;
181                     case Tokens::LITERAL_NULL:
182                         parseValue = JSHandle<JSTaggedValue>(thread_, ParseLiteralNull());
183                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
184                         break;
185                     case Tokens::NUMBER:
186                         parseValue = JSHandle<JSTaggedValue>(thread_, ParseNumber(IsInObjOrArray(continuation.type_)));
187                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
188                         break;
189                     case Tokens::STRING:
190                         parseValue = JSHandle<JSTaggedValue>(thread_, ParseString(IsInObjOrArray(continuation.type_)));
191                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
192                         break;
193                     default:
194                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
195                 }
196                 break;
197             }
198 
199             while (true) {
200                 switch (continuation.type_) {
201                     case ContType::RETURN:
202                         ASSERT(continuationList.empty());
203                         ASSERT(elementsList.empty());
204                         ASSERT(propertyList.empty());
205                         if (current_ <= range_) {
206                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON",
207                                                           JSTaggedValue::Exception());
208                         }
209                         return parseValue.GetTaggedValue();
210                     case ContType::ARRAY: {
211                         elementsList.emplace_back(parseValue);
212                         SkipStartWhiteSpace();
213                         if (*current_ == ',') {
214                             Advance();
215                             break;
216                         }
217                         parseValue = CreateJsonArray(continuation, elementsList);
218                         if (*current_ != ']') {
219                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON",
220                                                           JSTaggedValue::Exception());
221                         }
222                         Advance();
223                         elementsList.resize(continuation.index_);
224                         continuation = std::move(continuationList.back());
225                         continuationList.pop_back();
226                         continue;
227                     }
228                     case ContType::OBJECT: {
229                         propertyList.emplace_back(parseValue);
230                         SkipStartWhiteSpace();
231                         if (*current_ == ',') {
232                             GetNextNonSpaceChar();
233                             if (*current_ == '"') {
234                                 propertyList.emplace_back(JSHandle<JSTaggedValue>(thread_, ParseString(true)));
235                                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
236                             } else {
237                                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object Prop in JSON",
238                                                               JSTaggedValue::Exception());
239                             }
240                             SkipStartWhiteSpace();
241                             if (*current_ == ':') {
242                                 Advance();
243                             } else {
244                                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON",
245                                                               JSTaggedValue::Exception());
246                             }
247                             break;
248                         }
249 
250                         parseValue = CreateJsonObject(continuation, propertyList);
251                         if (*current_ == '}') {
252                             Advance();
253                         } else {
254                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON",
255                                                           JSTaggedValue::Exception());
256                         }
257                         propertyList.resize(continuation.index_);
258                         continuation = std::move(continuationList.back());
259                         continuationList.pop_back();
260                         continue;
261                     }
262                 }
263                 break;
264             }
265         }
266     }
267 
CreateJsonArray(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & elementsList)268     JSHandle<JSTaggedValue> CreateJsonArray(JsonContinuation continuation,
269                                             std::vector<JSHandle<JSTaggedValue>> &elementsList)
270     {
271         size_t start = continuation.index_;
272         size_t size = elementsList.size() - start;
273         JSHandle<JSArray> array = factory_->NewJSArray(size, initialJSArrayClass_);
274         JSHandle<TaggedArray> elements = factory_->NewJsonFixedArray(start, size, elementsList);
275         JSHandle<JSObject> obj(array);
276         obj->SetElements(thread_, elements);
277         return JSHandle<JSTaggedValue>(array);
278     }
279 
CreateJsonObject(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)280     JSHandle<JSTaggedValue> CreateJsonObject(JsonContinuation continuation,
281                                             std::vector<JSHandle<JSTaggedValue>> &propertyList)
282     {
283         size_t start = continuation.index_;
284         size_t size = propertyList.size() - start;
285         JSHandle<JSObject> obj = factory_->NewJSObject(initialJSObjectClass_);
286         for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
287             JSHandle<JSTaggedValue> keyHandle = propertyList[start + i];
288             JSHandle<JSTaggedValue> valueHandle = propertyList[start + i + 1];
289             JSTaggedValue res = ObjectFastOperator::SetPropertyByValue<ObjectFastOperator::Status::UseOwn>
290                 (thread_, obj.GetTaggedValue(), keyHandle.GetTaggedValue(), valueHandle.GetTaggedValue());
291             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
292             if (res.IsHole()) {
293                 // slow path
294                 JSTaggedValue::SetProperty(thread_, JSHandle<JSTaggedValue>(obj), keyHandle, valueHandle, true);
295                 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
296             }
297         }
298         return JSHandle<JSTaggedValue>(obj);
299     }
300 
301     JSTaggedValue ParseNumber(bool inObjorArr = false)
302     {
303         if (inObjorArr) {
304             bool isFast = true;
305             int32_t fastInteger = 0;
306             bool isNumber = ReadNumberRange(isFast, fastInteger);
307             if (!isNumber) {
308                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON Array Or Object",
309                                               JSTaggedValue::Exception());
310             }
311             if (isFast) {
312                 return JSTaggedValue(fastInteger);
313             }
314         }
315 
316         Text current = current_;
317         bool hasExponent = false;
318         if (*current_ == '-') {
319             if (UNLIKELY(current_++ == end_)) {
320                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
321             }
322         }
323         if (*current_ == '0') {
324             if (!CheckZeroBeginNumber(hasExponent)) {
325                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
326             }
327         } else if (*current_ >= '1' && *current_ <= '9') {
328             if (!CheckNonZeroBeginNumber(hasExponent)) {
329                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
330             }
331         } else {
332             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
333         }
334 
335         std::string strNum(current, end_ + 1);
336         current_ = end_ + 1;
337         errno = 0; // reset errno to 0 to avoid errno has been changed
338         double v = std::strtod(strNum.c_str(), nullptr);
339         if (errno == ERANGE) {
340             errno = 0;
341             return v > 0 ? JSTaggedValue(base::POSITIVE_INFINITY): JSTaggedValue(-base::POSITIVE_INFINITY);
342         }
343         errno = 0;
344         return JSTaggedValue::TryCastDoubleToInt32(v);
345     }
346 
ParseBackslash(std::u16string & res)347     bool ParseBackslash(std::u16string &res)
348     {
349         if (current_ == end_) {
350             return false;
351         }
352         Advance();
353         switch (*current_) {
354             case '\"':
355                 res += '\"';
356                 break;
357             case '\\':
358                 res += '\\';
359                 break;
360             case '/':
361                 res += '/';
362                 break;
363             case 'b':
364                 res += '\b';
365                 break;
366             case 'f':
367                 res += '\f';
368                 break;
369             case 'n':
370                 res += '\n';
371                 break;
372             case 'r':
373                 res += '\r';
374                 break;
375             case 't':
376                 res += '\t';
377                 break;
378             case 'u': {
379                 std::u16string u16Str;
380                 if (UNLIKELY(!ConvertStringUnicode(u16Str))) {
381                     return false;
382                 }
383                 res += u16Str;
384                 break;
385             }
386             default:
387                 return false;
388         }
389         return true;
390     }
391 
SlowParseString()392     JSTaggedValue SlowParseString()
393     {
394         end_--;
395         std::u16string res;
396         res.reserve(end_ - current_);
397         while (current_ <= end_) {
398             if (*current_ == '\\') {
399                 bool isLegalChar = ParseBackslash(res);
400                 if (!isLegalChar) {
401                     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected string in JSON", JSTaggedValue::Exception());
402                 }
403                 Advance();
404             } else {
405                 Text nextCurrent = current_;
406                 while (nextCurrent <= end_ && *nextCurrent != '\\') {
407                     ++nextCurrent;
408                 }
409                 res += std::u16string(current_, nextCurrent);
410                 current_ = nextCurrent;
411             }
412         }
413         ASSERT(res.size() <= static_cast<size_t>(UINT32_MAX));
414         Advance();
415         return factory_->NewFromUtf16(
416             reinterpret_cast<const uint16_t *>(res.data()), res.size()).GetTaggedValue();
417     }
418 
419     virtual void ParticalParseString(std::string& str, Text current, Text nextCurrent) = 0;
420 
421     virtual JSTaggedValue ParseString(bool inObjorArr = false) = 0;
422 
SkipEndWhiteSpace()423     void SkipEndWhiteSpace()
424     {
425         while (current_ != end_) {
426             if (*end_ == ' ' || *end_ == '\r' || *end_ == '\n' || *end_ == '\t') {
427                 end_--;
428             } else {
429                 break;
430             }
431         }
432     }
433 
SkipStartWhiteSpace()434     void SkipStartWhiteSpace()
435     {
436         while (current_ != end_) {
437             if (*current_ == ' ' || *current_ == '\r' || *current_ == '\n' || *current_ == '\t') {
438                 Advance();
439             } else {
440                 break;
441             }
442         }
443     }
444 
GetNextNonSpaceChar()445     void GetNextNonSpaceChar()
446     {
447         Advance();
448         SkipStartWhiteSpace();
449     }
450 
ParseToken()451     Tokens ParseToken()
452     {
453         switch (*current_) {
454             case '{':
455                 return Tokens::OBJECT;
456             case '[':
457                 return Tokens::ARRAY;
458             case '"':
459                 return Tokens::STRING;
460             case '0':
461             case '1':
462             case '2':
463             case '3':
464             case '4':
465             case '5':
466             case '6':
467             case '7':
468             case '8':
469             case '9':
470             case '-':
471                 return Tokens::NUMBER;
472             case 't':
473                 return Tokens::LITERAL_TRUE;
474             case 'f':
475                 return Tokens::LITERAL_FALSE;
476             case 'n':
477                 return Tokens::LITERAL_NULL;
478             default:
479                 return Tokens::TOKEN_ILLEGAL;
480         }
481     }
482 
ParseLiteralTrue()483     JSTaggedValue ParseLiteralTrue()
484     {
485         static const char literalTrue[] = "true";
486         uint32_t remainingLength = range_ - current_;
487         if (UNLIKELY(remainingLength < 3)) { // 3: literalTrue length - 1
488             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
489         }
490         bool isMatch = MatchText(literalTrue, 4); // 4: literalTrue length
491         if (LIKELY(isMatch)) {
492             return JSTaggedValue::True();
493         }
494         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
495     }
496 
ParseLiteralFalse()497     JSTaggedValue ParseLiteralFalse()
498     {
499         static const char literalFalse[] = "false";
500         uint32_t remainingLength = range_ - current_;
501         if (UNLIKELY(remainingLength < 4)) { // 4: literalFalse length - 1
502             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
503         }
504         bool isMatch = MatchText(literalFalse, 5); // 5: literalFalse length
505         if (LIKELY(isMatch)) {
506             return JSTaggedValue::False();
507         }
508         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
509     }
510 
ParseLiteralNull()511     JSTaggedValue ParseLiteralNull()
512     {
513         static const char literalNull[] = "null";
514         uint32_t remainingLength = range_ - current_;
515         if (UNLIKELY(remainingLength < 3)) { // 3: literalNull length - 1
516             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
517         }
518         bool isMatch = MatchText(literalNull, 4); // 4: literalNull length
519         if (LIKELY(isMatch)) {
520             return JSTaggedValue::Null();
521         }
522         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
523     }
524 
MatchText(const char * str,uint32_t matchLen)525     bool MatchText(const char *str, uint32_t matchLen)
526     {
527         // first char is already matched
528         for (uint32_t pos = 1; pos < matchLen; ++pos) {
529             if (current_[pos] != str[pos]) {
530                 return false;
531             }
532         }
533         current_ += matchLen;
534         return true;
535     }
536 
ReadNumberRange(bool & isFast,int32_t & fastInteger)537     bool ReadNumberRange(bool &isFast, int32_t &fastInteger)
538     {
539         Text current = current_;
540         int32_t sign = 1;
541         if (*current == '-') {
542             current++;
543             sign = -1;
544         }
545 
546         if (*current == '0') {
547             isFast = false;
548             current++;
549         } else {
550             Text advance = AdvanceLastNumberCharacter(current);
551             if (UNLIKELY(current == advance)) {
552                 return false;
553             }
554             size_t numberLength = advance - current;
555             int32_t i = 0;
556             if (numberLength <= INTEGER_MAX_LEN && (*advance == ',' || *advance == ']' || *advance == '}')) {
557                 for (; current != advance; current++) {
558                     i = (i * 10) + ((*current) - '0');
559                 }
560                 fastInteger = i * sign;
561                 current_ = advance;
562                 return true;
563             }
564             isFast = false;
565         }
566 
567         while (current != range_) {
568             if (IsNumberCharacter(*current)) {
569                 current++;
570                 continue;
571             } else if (IsNumberSignalCharacter(*current)) {
572                 isFast = false;
573                 current++;
574                 continue;
575             }
576             Text end = current;
577             while (current != range_) {
578                 if (*current == ' ' || *current == '\r' || *current == '\n' || *current == '\t') {
579                     current++;
580                 } else if (*current == ',' || *current == ']' || *current == '}') {
581                     end_ = end - 1;
582                     return true;
583                 } else {
584                     return false;
585                 }
586             }
587             if (*current == ']' || *current == '}') {
588                 end_ = end - 1;
589                 return true;
590             }
591             return false;
592         }
593         end_ = range_ - 1;
594         return true;
595     }
596 
AdvanceLastNumberCharacter(Text current)597     Text AdvanceLastNumberCharacter(Text current)
598     {
599         return std::find_if(current, range_, [this](T c) { return !IsNumberCharacter(c); });
600     }
601 
IsNumberCharacter(T ch)602     bool IsNumberCharacter(T ch)
603     {
604         if (ch >= '0' && ch <= '9') {
605             return true;
606         }
607         return false;
608     }
609 
IsNumberSignalCharacter(T ch)610     bool IsNumberSignalCharacter(T ch)
611     {
612         return ch == '.' || ch == 'e' || ch == 'E' || ch == '+' || ch == '-';
613     }
614 
IsExponentNumber()615     bool IsExponentNumber()
616     {
617         if (IsNumberCharacter(*current_)) {
618             return true;
619         } else if (*current_ == '-' || *current_ == '+') {
620             if (current_ == end_) {
621                 return false;
622             }
623             Advance();
624             if (IsNumberCharacter(*current_)) {
625                 return true;
626             }
627         }
628         return false;
629     }
630 
IsDecimalsLegal(bool & hasExponent)631     bool IsDecimalsLegal(bool &hasExponent)
632     {
633         if (current_ == end_ && !IsNumberCharacter(*++current_)) {
634             return false;
635         }
636 
637         while (current_ != end_) {
638             Advance();
639             if (IsNumberCharacter(*current_)) {
640                 continue;
641             } else if (*current_ == 'e' || *current_ == 'E') {
642                 if (hasExponent || current_ == end_) {
643                     return false;
644                 }
645                 Advance();
646                 if (!IsExponentNumber()) {
647                     return false;
648                 }
649                 hasExponent = true;
650             } else {
651                 return false;
652             }
653         }
654         return true;
655     }
656 
IsExponentLegal(bool & hasExponent)657     bool IsExponentLegal(bool &hasExponent)
658     {
659         if (hasExponent || current_ == end_) {
660             return false;
661         }
662         Advance();
663         if (!IsExponentNumber()) {
664             return false;
665         }
666         while (current_ != end_) {
667             if (!IsNumberCharacter(*current_)) {
668                 return false;
669             }
670             Advance();
671         }
672         return true;
673     }
674 
ConvertStringUnicode(std::u16string & u16Str)675     bool ConvertStringUnicode(std::u16string &u16Str)
676     {
677         do {
678             uint32_t remainingLength = end_ - current_;
679             if (remainingLength < UNICODE_DIGIT_LENGTH) {
680                 return false;
681             }
682             uint16_t res = 0;
683             for (uint32_t pos = 0; pos < UNICODE_DIGIT_LENGTH; pos++) {
684                 Advance();
685                 if (*current_ >= '0' && *current_ <= '9') {
686                     res *= NUMBER_SIXTEEN;
687                     res += (*current_ - '0');
688                 } else if (*current_ >= 'a' && *current_ <= 'f') {
689                     res *= NUMBER_SIXTEEN;
690                     res += (*current_ - 'a' + NUMBER_TEN);
691                 } else if (*current_ >= 'A' && *current_ <= 'F') {
692                     res *= NUMBER_SIXTEEN;
693                     res += (*current_ - 'A' + NUMBER_TEN);
694                 } else {
695                     return false;
696                 }
697             }
698             u16Str.push_back(res);
699         } while ([&]() -> bool {
700             static const int unicodePrefixLen = 2;
701             if (end_ - current_ < unicodePrefixLen) {
702                 return false;
703             }
704             if (*(current_ + 1) == '\\' && *(current_ + unicodePrefixLen) == 'u') {
705                 AdvanceMultiStep(unicodePrefixLen);
706                 return true;
707             }
708             return false;
709         }());
710         return true;
711     }
712 
CheckZeroBeginNumber(bool & hasExponent)713     bool CheckZeroBeginNumber(bool &hasExponent)
714     {
715         if (current_++ != end_) {
716             if (*current_ == '.') {
717                 if (!IsDecimalsLegal(hasExponent)) {
718                     return false;
719                 }
720             } else if (*current_ == 'e' || *current_ == 'E') {
721                 if (!IsExponentLegal(hasExponent)) {
722                     return false;
723                 }
724             } else {
725                 return false;
726             }
727         }
728         return true;
729     }
730 
CheckNonZeroBeginNumber(bool & hasExponent)731     bool CheckNonZeroBeginNumber(bool &hasExponent)
732     {
733         while (current_ != end_) {
734             Advance();
735             if (IsNumberCharacter(*current_)) {
736                 continue;
737             } else if (*current_ == '.') {
738                 if (!IsDecimalsLegal(hasExponent)) {
739                     return false;
740                 }
741             } else if (*current_ == 'e' || *current_ == 'E') {
742                 if (!IsExponentLegal(hasExponent)) {
743                     return false;
744                 }
745             } else {
746                 return false;
747             }
748         }
749         return true;
750     }
751 
Advance()752     inline void Advance()
753     {
754         ++current_;
755     }
756 
AdvanceMultiStep(int step)757     inline void AdvanceMultiStep(int step)
758     {
759         current_ += step;
760     }
761 
762     Text end_ {nullptr};
763     Text current_ {nullptr};
764     Text range_ {nullptr};
765     JSThread *thread_ {nullptr};
766     ObjectFactory *factory_ {nullptr};
767     GlobalEnv *env_ {nullptr};
768     JSHandle<JSHClass> initialJSArrayClass_;
769     JSHandle<JSHClass> initialJSObjectClass_;
770 };
771 
772 class Utf8JsonParser : public JsonParser<uint8_t> {
773 public:
774     Utf8JsonParser() = default;
Utf8JsonParser(JSThread * thread)775     explicit Utf8JsonParser(JSThread *thread) : JsonParser(thread) {}
776     ~Utf8JsonParser() = default;
777     NO_COPY_SEMANTIC(Utf8JsonParser);
778     NO_MOVE_SEMANTIC(Utf8JsonParser);
779 
Parse(EcmaString * str)780     JSHandle<JSTaggedValue> Parse(EcmaString *str)
781     {
782         ASSERT(str != nullptr);
783         auto stringAccessor = EcmaStringAccessor(str);
784         uint32_t len = stringAccessor.GetLength();
785         ASSERT(len != UINT32_MAX);
786         CVector<uint8_t> buf(len + 1);
787         stringAccessor.WriteToFlatUtf8(buf.data(), len);
788         Text begin = buf.data();
789         return Launch(begin, begin + len);
790     }
791 
792 private:
ParticalParseString(std::string & str,Text current,Text nextCurrent)793     void ParticalParseString(std::string& str, Text current, Text nextCurrent) override
794     {
795         str += std::string_view(reinterpret_cast<const char *>(current), nextCurrent - current);
796     }
797 
798     JSTaggedValue ParseString(bool inObjorArr = false) override
799     {
800         bool isFastString = true;
801         bool isLegal = true;
802         if (inObjorArr) {
803             isLegal = ReadJsonStringRange(isFastString);
804             if (!isLegal) {
805                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
806             }
807             if (isFastString) {
808                 size_t strLength = end_ - current_;
809                 ASSERT(strLength <= static_cast<size_t>(UINT32_MAX));
810                 JSTaggedValue res = factory_->NewCompressedUtf8(
811                     reinterpret_cast<const uint8_t *>(current_), strLength).GetTaggedValue();
812                 current_ = end_ + 1;
813                 return res;
814             }
815         } else {
816             if (*end_ != '"' || current_ == end_) {
817                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
818             }
819             isLegal = IsFastParseJsonString(isFastString);
820             if (!isLegal) {
821                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
822             }
823             if (LIKELY(isFastString)) {
824                 std::string_view value(reinterpret_cast<const char *>(current_), end_ - current_);
825                 current_ = end_ + 1;
826                 ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
827                 return factory_->NewFromUtf8LiteralCompress(
828                     reinterpret_cast<const uint8_t *>(value.data()), value.size()).GetTaggedValue();
829             }
830         }
831         return SlowParseString();
832     }
833 
ReadJsonStringRange(bool & isFastString)834     bool ReadJsonStringRange(bool &isFastString)
835     {
836         Advance();
837         // chars are within Ascii
838         for (Text current = current_; current != range_; ++current) {
839             uint8_t c = *current;
840             if (c == '"') {
841                 end_ = current;
842                 return true;
843             } else if (UNLIKELY(c == '\\')) {
844                 current++;
845                 isFastString = false;
846             } else if (UNLIKELY(c < CODE_SPACE)) {
847                 return false;
848             }
849         }
850         return false;
851     }
852 
IsFastParseJsonString(bool & isFastString)853     bool IsFastParseJsonString(bool &isFastString)
854     {
855         Advance();
856         // chars are within Ascii
857         for (Text current = current_; current != end_; ++current) {
858             if (*current < CODE_SPACE) {
859                 return false;
860             } else if (*current == '\\') {
861                 isFastString = false;
862             }
863         }
864         return true;
865     }
866 };
867 
868 class Utf16JsonParser : public JsonParser<uint16_t> {
869 public:
870     Utf16JsonParser() = default;
Utf16JsonParser(JSThread * thread)871     explicit Utf16JsonParser(JSThread *thread) : JsonParser(thread) {}
872     ~Utf16JsonParser() = default;
873     NO_COPY_SEMANTIC(Utf16JsonParser);
874     NO_MOVE_SEMANTIC(Utf16JsonParser);
875 
Parse(EcmaString * str)876     JSHandle<JSTaggedValue> Parse(EcmaString *str)
877     {
878         ASSERT(str != nullptr);
879         uint32_t len = EcmaStringAccessor(str).GetLength();
880         CVector<uint16_t> buf(len);
881         EcmaStringAccessor(str).WriteToFlatUtf16(buf.data(), len);
882         Text begin = buf.data();
883         return Launch(begin, begin + len);
884     }
885 
886 private:
ParticalParseString(std::string & str,Text current,Text nextCurrent)887     void ParticalParseString(std::string& str, Text current, Text nextCurrent) override
888     {
889         str += StringHelper::U16stringToString(std::u16string(current, nextCurrent));
890     }
891 
892     JSTaggedValue ParseString(bool inObjorArr = false) override
893     {
894         bool isFastString = true;
895         bool isAscii = true;
896         bool isLegal = true;
897         if (inObjorArr) {
898             isLegal = ReadJsonStringRange(isFastString, isAscii);
899             if (!isLegal) {
900                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
901             }
902             if (isFastString) {
903                 if (isAscii) {
904                     std::string value(current_, end_); // from uint16_t* to std::string, can't use std::string_view
905                     current_ = end_ + 1;
906                     ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
907                     return factory_->NewFromUtf8LiteralCompress(
908                         reinterpret_cast<const uint8_t *>(value.c_str()), value.size()).GetTaggedValue();
909                 }
910                 std::u16string_view value(reinterpret_cast<const char16_t *>(current_), end_ - current_);
911                 current_ = end_ + 1;
912                 ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
913                 return factory_->NewFromUtf16LiteralNotCompress(
914                     reinterpret_cast<const uint16_t *>(value.data()), value.size()).GetTaggedValue();
915             }
916         } else {
917             if (*end_ != '"' || current_ == end_) {
918                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
919             }
920             isLegal = IsFastParseJsonString(isFastString, isAscii);
921             if (!isLegal) {
922                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
923             }
924             if (LIKELY(isFastString)) {
925                 if (isAscii) {
926                     std::string value(current_, end_);  // from uint16_t* to std::string, can't use std::string_view
927                     ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
928                     current_ = end_ + 1;
929                     return factory_->NewFromUtf8LiteralCompress(
930                         reinterpret_cast<const uint8_t *>(value.c_str()), value.size()).GetTaggedValue();
931                 }
932                 std::u16string_view value(reinterpret_cast<const char16_t *>(current_), end_ - current_);
933                 ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
934                 current_ = end_ + 1;
935                 return factory_->NewFromUtf16LiteralNotCompress(
936                     reinterpret_cast<const uint16_t *>(value.data()), value.size()).GetTaggedValue();
937             }
938         }
939         return SlowParseString();
940     }
941 
ReadJsonStringRange(bool & isFastString,bool & isAscii)942     bool ReadJsonStringRange(bool &isFastString, bool &isAscii)
943     {
944         Advance();
945         for (Text current = current_; current != range_; ++current) {
946             uint16_t c = *current;
947             if (c == '"') {
948                 end_ = current;
949                 return true;
950             } else if (UNLIKELY(c == '\\')) {
951                 ++current;
952                 isFastString = false;
953             }
954             if (!IsLegalAsciiCharacter(c, isAscii)) {
955                 return false;
956             }
957         }
958         return false;
959     }
960 
IsFastParseJsonString(bool & isFastString,bool & isAscii)961     bool IsFastParseJsonString(bool &isFastString, bool &isAscii)
962     {
963         Advance();
964         for (Text current = current_; current != end_; ++current) {
965             if (!IsLegalAsciiCharacter(*current, isAscii)) {
966                 return false;
967             }
968             if (*current == '\\') {
969                 isFastString = false;
970             }
971         }
972         return true;
973     }
974 
IsLegalAsciiCharacter(uint16_t c,bool & isAscii)975     bool IsLegalAsciiCharacter(uint16_t c, bool &isAscii)
976     {
977         if (c <= ASCII_END) {
978             return c >= CODE_SPACE ? true : false;
979         }
980         isAscii = false;
981         return true;
982     }
983 };
984 
985 class Internalize {
986 public:
987     static JSHandle<JSTaggedValue> InternalizeJsonProperty(JSThread *thread, const JSHandle<JSObject> &holder,
988                                                            const JSHandle<JSTaggedValue> &name,
989                                                            const JSHandle<JSTaggedValue> &receiver);
990 private:
991     static bool RecurseAndApply(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &name,
992                                 const JSHandle<JSTaggedValue> &receiver);
993 };
994 }  // namespace panda::ecmascript::base
995 
996 #endif  // ECMASCRIPT_BASE_JSON_PARSE_INL_H
997