• 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 
41 constexpr unsigned char CODE_SPACE = 0x20;
42 constexpr unsigned char ASCII_END = 0X7F;
43 enum class Tokens : uint8_t {
44         // six structural tokens
45         OBJECT = 0,
46         ARRAY,
47         NUMBER,
48         STRING,
49         LITERAL_TRUE,
50         LITERAL_FALSE,
51         LITERAL_NULL,
52         TOKEN_ILLEGAL,
53     };
54 
55 template<typename T>
56 class JsonParser {
57 public:
58     using Text = const T *;
59     JsonParser() = default;
JsonParser(JSThread * thread)60     explicit JsonParser(JSThread *thread) : thread_(thread) {}
61     ~JsonParser() = default;
62     NO_COPY_SEMANTIC(JsonParser);
63     NO_MOVE_SEMANTIC(JsonParser);
Parse(Text begin,Text end)64     JSHandle<JSTaggedValue> Parse(Text begin, Text end)
65     {
66         end_ = (end == begin) ? end : end - 1;
67         current_ = begin;
68 
69         auto vm = thread_->GetEcmaVM();
70         factory_ = vm->GetFactory();
71         env_ = *vm->GetGlobalEnv();
72 
73         SkipEndWhiteSpace();
74         range_ = end_;
75         JSTaggedValue result = ParseJSONText<false>();
76         return JSHandle<JSTaggedValue>(thread_, result);
77     }
78 
ParseUtf8(EcmaString * str)79     JSHandle<JSTaggedValue> ParseUtf8(EcmaString *str)
80     {
81         ASSERT(str != nullptr);
82         isAsciiString_ = true;
83         uint32_t len = EcmaStringAccessor(str).GetLength();
84         ASSERT(len != UINT32_MAX);
85         CVector<T> buf(len + 1); // 1 means add '\0' in the end of buf
86         EcmaStringAccessor(str).WriteToFlatUtf8(buf.data(), len + 1);
87         Text begin = buf.data();
88         return Parse(begin, begin + len);
89     }
90 
ParseUtf16(EcmaString * str)91     JSHandle<JSTaggedValue> ParseUtf16(EcmaString *str)
92     {
93         ASSERT(str != nullptr);
94         uint32_t len = EcmaStringAccessor(str).GetLength();
95         CVector<T> buf(len);
96         EcmaStringAccessor(str).WriteToFlatUtf16(buf.data(), len);
97         Text begin = buf.data();
98         return Parse(begin, begin + len);
99     }
100 
101 private:
102     template<bool inObjorArr = false>
ParseJSONText()103     JSTaggedValue ParseJSONText()
104     {
105         SkipStartWhiteSpace();
106         Tokens token = ParseToken();
107         switch (token) {
108             case Tokens::OBJECT:
109                 return ParseObject<inObjorArr>();
110             case Tokens::ARRAY:
111                 return ParseArray<inObjorArr>();
112             case Tokens::LITERAL_TRUE:
113                 return ParseLiteral("true", Tokens::LITERAL_TRUE);
114             case Tokens::LITERAL_FALSE:
115                 return ParseLiteral("false", Tokens::LITERAL_FALSE);
116             case Tokens::LITERAL_NULL:
117                 return ParseLiteral("null", Tokens::LITERAL_NULL);
118             case Tokens::NUMBER:
119                 return ParseNumber<inObjorArr>();
120             case Tokens::STRING:
121                 return ParseString<inObjorArr>();
122             default:
123                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
124         }
125     }
126 
127     template<bool inObjOrArr = false>
ParseNumber()128     JSTaggedValue ParseNumber()
129     {
130         if (inObjOrArr) {
131             bool isFast = true;
132             bool isNumber = ReadNumberRange(isFast);
133             if (!isNumber) {
134                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
135             }
136             if (isFast) {
137                 std::string strNum(current_, end_ + 1);
138                 current_ = end_;
139                 double v = std::strtod(strNum.c_str(), nullptr);
140                 if (errno == ERANGE) {
141                     errno = 0;
142                     return v > 0 ? JSTaggedValue(base::POSITIVE_INFINITY): JSTaggedValue(-base::POSITIVE_INFINITY);
143                 }
144                 return JSTaggedValue::TryCastDoubleToInt32(v);
145             }
146         }
147 
148         Text current = current_;
149         bool hasExponent = false;
150         if (*current_ == '-') {
151             if (UNLIKELY(current_++ == end_)) {
152                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
153             }
154         }
155         if (*current_ == '0') {
156             if (!CheckZeroBeginNumber(hasExponent)) {
157                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
158             }
159         } else if (*current_ >= '1' && *current_ <= '9') {
160             if (!CheckNonZeroBeginNumber(hasExponent)) {
161                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
162             }
163         } else {
164             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
165         }
166 
167         std::string strNum(current, end_ + 1);
168         current_ = end_;
169         double v = std::strtod(strNum.c_str(), nullptr);
170         if (errno == ERANGE) {
171             errno = 0;
172             return v > 0 ? JSTaggedValue(base::POSITIVE_INFINITY): JSTaggedValue(-base::POSITIVE_INFINITY);
173         }
174         return JSTaggedValue::TryCastDoubleToInt32(v);
175     }
176 
ReadJsonStringRange(bool & isFastString,bool & isAscii)177     bool ReadJsonStringRange(bool &isFastString, bool &isAscii)
178     {
179         current_++;
180         if (isAsciiString_) {
181             return ReadAsciiStringRange(isFastString);
182         }
183         return ReadStringRange(isFastString, isAscii);
184     }
185 
IsFastParseJsonString(bool & isFastString,bool & isAscii)186     bool IsFastParseJsonString(bool &isFastString, bool &isAscii)
187     {
188         current_++;
189         if (isAsciiString_) {
190             return IsFastParseAsciiString(isFastString);
191         }
192         return IsFastParseString(isFastString, isAscii);
193     }
194 
ParseBackslash(CString & res)195     bool ParseBackslash(CString &res)
196     {
197         if (current_ == end_) {
198             return false;
199         }
200         current_++;
201         switch (*current_) {
202             case '\"':
203                 res += "\"";
204                 break;
205             case '\\':
206                 res += "\\";
207                 break;
208             case '/':
209                 res += "/";
210                 break;
211             case 'b':
212                 res += "\b";
213                 break;
214             case 'f':
215                 res += "\f";
216                 break;
217             case 'n':
218                 res += "\n";
219                 break;
220             case 'r':
221                 res += "\r";
222                 break;
223             case 't':
224                 res += "\t";
225                 break;
226             case 'u': {
227                 CVector<uint16_t> vec;
228                 if (UNLIKELY(!ConvertStringUnicode(vec))) {
229                     return false;
230                 }
231                 std::u16string u16Str;
232                 u16Str.assign(vec.begin(), vec.end());
233                 res += base::StringHelper::U16stringToString(u16Str);
234                 break;
235             }
236             default:
237                 return false;
238         }
239         return true;
240     }
241 
SlowParseString()242     JSTaggedValue SlowParseString()
243     {
244         end_--;
245         CString res;
246         while (current_ <= end_) {
247             if (*current_ == '\\') {
248                 bool isLegalChar = ParseBackslash(res);
249                 if (!isLegalChar) {
250                     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected string in JSON", JSTaggedValue::Exception());
251                 }
252                 current_++;
253             } else if (UNLIKELY(*current_ > ASCII_END)) {
254                 if (UNLIKELY(*current_ >= utf_helper::DECODE_LEAD_LOW && *current_ <= utf_helper::DECODE_LEAD_HIGH &&
255                              *(current_ + 1) >= utf_helper::DECODE_TRAIL_LOW &&
256                              *(current_ + 1) <= utf_helper::DECODE_TRAIL_HIGH)) {
257                     std::u16string str(current_, current_ + 2);  // 2 means twice as many bytes as normal u16string
258                     res += ConvertToString(StringHelper::U16stringToString(str));
259                     current_ += 2;  // 2 means twice as many bytes as normal u16string
260                 } else {
261                     std::u16string str(current_, current_ + 1);
262                     res += ConvertToString(StringHelper::U16stringToString(str));
263                     current_++;
264                 }
265             } else {
266                 res += *current_;
267                 current_++;
268             }
269         }
270         ASSERT(res.length() <= static_cast<size_t>(UINT32_MAX));
271         return factory_->NewFromUtf8Literal(reinterpret_cast<const uint8_t *>(res.c_str()), res.length())
272             .GetTaggedValue();
273     }
274 
275     template<bool inObjorArr = false>
ParseString()276     JSTaggedValue ParseString()
277     {
278         bool isFastString = true;
279         bool isAscii = true;
280         bool isLegal = true;
281         if (inObjorArr) {
282             isLegal = ReadJsonStringRange(isFastString, isAscii);
283             if (!isLegal) {
284                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
285             }
286             if (isFastString) {
287                 if (isAscii) {
288                     CString value(current_, end_);
289                     current_ = end_;
290                     ASSERT(value.length() <= static_cast<size_t>(UINT32_MAX));
291                     return factory_->NewFromUtf8LiteralCompress(
292                         reinterpret_cast<const uint8_t *>(value.c_str()), value.length()).GetTaggedValue();
293                 }
294                 std::u16string value(current_, end_);
295                 current_ = end_;
296                 ASSERT(value.length() <= static_cast<size_t>(UINT32_MAX));
297                 return factory_->NewFromUtf16LiteralNotCompress(
298                     reinterpret_cast<const uint16_t *>(value.c_str()), value.length()).GetTaggedValue();
299             }
300         } else {
301             if (*end_ != '"' || current_ == end_) {
302                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
303             }
304             isLegal = IsFastParseJsonString(isFastString, isAscii);
305             if (!isLegal) {
306                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception());
307             }
308             if (LIKELY(isFastString)) {
309                 if (isAscii) {
310                     CString value(current_, end_);
311                     ASSERT(value.length() <= static_cast<size_t>(UINT32_MAX));
312                     return factory_->NewFromUtf8LiteralCompress(
313                         reinterpret_cast<const uint8_t *>(value.c_str()), value.length()).GetTaggedValue();
314                 }
315                 std::u16string value(current_, end_);
316                 ASSERT(value.length() <= static_cast<size_t>(UINT32_MAX));
317                 return factory_->NewFromUtf16LiteralNotCompress(
318                     reinterpret_cast<const uint16_t *>(value.c_str()), value.length()).GetTaggedValue();
319             }
320         }
321         return SlowParseString();
322     }
323 
324     template<bool inObjorArr = false>
ParseArray()325     JSTaggedValue ParseArray()
326     {
327         if (UNLIKELY(*range_ != ']' && !inObjorArr)) {
328             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception());
329         }
330 
331         current_++;
332         SkipStartWhiteSpace();
333         JSHandle<JSArray> arr = factory_->NewJSArray();
334         if (*current_ == ']') {
335             return arr.GetTaggedValue();
336         }
337 
338         JSTaggedValue value;
339         uint32_t index = 0;
340         while (current_ <= range_) {
341             value = ParseJSONText<true>();
342             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
343             ObjectFastOperator::SetPropertyByIndex<true>(thread_, arr.GetTaggedValue(), index++, value);
344             GetNextNonSpaceChar();
345             if (*current_ == ',') {
346                 current_++;
347             } else if (*current_ == ']') {
348                 if (inObjorArr || current_ == range_) {
349                     return arr.GetTaggedValue();
350                 } else {
351                     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception());
352                 }
353             }
354         }
355         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception());
356     }
357 
358     template<bool inObjorArr = false>
ParseObject()359     JSTaggedValue ParseObject()
360     {
361         if (UNLIKELY(*range_ != '}' && !inObjorArr)) {
362             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception());
363         }
364 
365         JSHandle<JSFunction> proto(env_->GetObjectFunction());
366         JSHandle<JSObject> result = factory_->NewJSObjectByConstructor(proto);
367         current_++;
368         if (*current_ == '}') {
369             return result.GetTaggedValue();
370         }
371 
372         JSMutableHandle<JSTaggedValue> keyHandle(thread_, JSTaggedValue::Undefined());
373         JSTaggedValue value;
374         while (current_ <= range_) {
375             SkipStartWhiteSpace();
376             if (*current_ == '"') {
377                 keyHandle.Update(ParseString<true>());
378                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
379             } else {
380                 if (*current_ == '}' && (inObjorArr || current_ == range_)) {
381                     return result.GetTaggedValue();
382                 }
383                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception());
384             }
385             GetNextNonSpaceChar();
386             if (*current_ == ':') {
387                 current_++;
388             } else {
389                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception());
390             }
391             value = ParseJSONText<true>();
392             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
393             // fast path
394             JSTaggedValue res = ObjectFastOperator::SetPropertyByValue<true>(thread_, result.GetTaggedValue(),
395                                                                              keyHandle.GetTaggedValue(), value);
396             if (res.IsHole()) {
397                 // slow path
398                 JSTaggedValue::SetProperty(thread_, JSHandle<JSTaggedValue>(result), keyHandle,
399                                            JSHandle<JSTaggedValue>(thread_, value), true);
400                 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
401             }
402             GetNextNonSpaceChar();
403             if (*current_ == ',') {
404                 current_++;
405             } else if (*current_ == '}') {
406                 if (inObjorArr || current_ == range_) {
407                     return result.GetTaggedValue();
408                 } else {
409                     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception());
410                 }
411             }
412         }
413         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception());
414     }
415 
SkipEndWhiteSpace()416     void SkipEndWhiteSpace()
417     {
418         while (current_ != end_) {
419             if (*end_ == ' ' || *end_ == '\r' || *end_ == '\n' || *end_ == '\t') {
420                 end_--;
421             } else {
422                 break;
423             }
424         }
425     }
426 
SkipStartWhiteSpace()427     void SkipStartWhiteSpace()
428     {
429         while (current_ != end_) {
430             if (*current_ == ' ' || *current_ == '\r' || *current_ == '\n' || *current_ == '\t') {
431                 current_++;
432             } else {
433                 break;
434             }
435         }
436     }
437 
GetNextNonSpaceChar()438     void GetNextNonSpaceChar()
439     {
440         current_++;
441         SkipStartWhiteSpace();
442     }
443 
ParseToken()444     Tokens ParseToken()
445     {
446         switch (*current_) {
447             case '{':
448                 return Tokens::OBJECT;
449             case '[':
450                 return Tokens::ARRAY;
451             case '"':
452                 return Tokens::STRING;
453             case '0':
454             case '1':
455             case '2':
456             case '3':
457             case '4':
458             case '5':
459             case '6':
460             case '7':
461             case '8':
462             case '9':
463             case '-':
464                 return Tokens::NUMBER;
465             case 't':
466                 return Tokens::LITERAL_TRUE;
467             case 'f':
468                 return Tokens::LITERAL_FALSE;
469             case 'n':
470                 return Tokens::LITERAL_NULL;
471             default:
472                 return Tokens::TOKEN_ILLEGAL;
473         }
474     }
475 
ParseLiteral(CString str,Tokens literalToken)476     JSTaggedValue ParseLiteral(CString str, Tokens literalToken)
477     {
478         ASSERT((str.size() - 1) <= static_cast<size_t>(UINT32_MAX));
479         uint32_t strLen = str.size() - 1;
480         uint32_t remainingLength = range_ - current_;
481         if (UNLIKELY(remainingLength < strLen)) {
482             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
483         }
484 
485         bool isMatch = MatchText(str, strLen);
486         if (LIKELY(isMatch)) {
487             switch (literalToken) {
488                 case Tokens::LITERAL_TRUE:
489                     return JSTaggedValue::True();
490                 case Tokens::LITERAL_FALSE:
491                     return JSTaggedValue::False();
492                 case Tokens::LITERAL_NULL:
493                     return JSTaggedValue::Null();
494                 default:
495                     LOG_ECMA(FATAL) << "this branch is unreachable";
496                     UNREACHABLE();
497             }
498         }
499         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception());
500     }
501 
MatchText(CString str,uint32_t matchLen)502     bool MatchText(CString str, uint32_t matchLen)
503     {
504         const char *text = str.c_str();
505         uint32_t pos = 1;
506         while (pos <= matchLen) {
507             if (current_[pos] != text[pos]) {
508                 return false;
509             }
510             pos++;
511         }
512         current_ += matchLen;
513         return true;
514     }
515 
ReadNumberRange(bool & isFast)516     bool ReadNumberRange(bool &isFast)
517     {
518         Text current = current_;
519         if (*current == '0') {
520             isFast = false;
521             current++;
522         } else if (*current == '-') {
523             current++;
524             if (*current == '0') {
525                 isFast = false;
526                 current++;
527             }
528         }
529 
530         while (current != range_) {
531             if (IsNumberCharacter(*current)) {
532                 current++;
533                 continue;
534             } else if (IsNumberSignalCharacter(*current)) {
535                 isFast = false;
536                 current++;
537                 continue;
538             }
539             Text end = current;
540             while (current != range_) {
541                 if (*current == ' ' || *current == '\r' || *current == '\n' || *current == '\t') {
542                     current++;
543                 } else if (*current == ',' || *current == ']' || *current == '}') {
544                     end_ = end - 1;
545                     return true;
546                 } else {
547                     return false;
548                 }
549             }
550             if (*current == ']' || *current == '}') {
551                 end_ = end - 1;
552                 return true;
553             }
554             return false;
555         }
556         end_ = range_ - 1;
557         return true;
558     }
559 
IsNumberCharacter(T ch)560     bool IsNumberCharacter(T ch)
561     {
562         if (ch >= '0' && ch <= '9') {
563             return true;
564         }
565         return false;
566     }
567 
IsNumberSignalCharacter(T ch)568     bool IsNumberSignalCharacter(T ch)
569     {
570         return ch == '.' || ch == 'e' || ch == 'E' || ch == '+' || ch == '-';
571     }
572 
IsExponentNumber()573     bool IsExponentNumber()
574     {
575         if (IsNumberCharacter(*current_)) {
576             return true;
577         } else if (*current_ == '-' || *current_ == '+') {
578             if (current_ == end_) {
579                 return false;
580             }
581             current_++;
582             if (IsNumberCharacter(*current_)) {
583                 return true;
584             }
585         }
586         return false;
587     }
588 
IsDecimalsLegal(bool & hasExponent)589     bool IsDecimalsLegal(bool &hasExponent)
590     {
591         if (current_ == end_ && !IsNumberCharacter(*++current_)) {
592             return false;
593         }
594 
595         while (current_ != end_) {
596             current_++;
597             if (IsNumberCharacter(*current_)) {
598                 continue;
599             } else if (*current_ == 'e' || *current_ == 'E') {
600                 if (hasExponent || current_ == end_) {
601                     return false;
602                 }
603                 current_++;
604                 if (!IsExponentNumber()) {
605                     return false;
606                 }
607                 hasExponent = true;
608             } else {
609                 return false;
610             }
611         }
612         return true;
613     }
614 
IsExponentLegal(bool & hasExponent)615     bool IsExponentLegal(bool &hasExponent)
616     {
617         if (hasExponent || current_ == end_) {
618             return false;
619         }
620         current_++;
621         if (!IsExponentNumber()) {
622             return false;
623         }
624         while (current_ != end_) {
625             if (!IsNumberCharacter(*current_)) {
626                 return false;
627             }
628             current_++;
629         }
630         return true;
631     }
632 
ReadStringRange(bool & isFast,bool & isAscii)633     bool ReadStringRange(bool &isFast, bool &isAscii)
634     {
635         T c = 0;
636         Text current = current_;
637 
638         while (current != range_) {
639             c = *current;
640             if (c == '"') {
641                 end_ = current;
642                 return true;
643             } else if (UNLIKELY(c == '\\')) {
644                 current++;
645                 isFast = false;
646             }
647             if (!IsLegalAsciiCharacter(c, isAscii)) {
648                 return false;
649             }
650             current++;
651         }
652         return false;
653     }
654 
ReadAsciiStringRange(bool & isFast)655     bool ReadAsciiStringRange(bool &isFast)
656     {
657         T c = 0;
658         Text current = current_;
659 
660         while (current != range_) {
661             c = *current;
662             if (c == '"') {
663                 end_ = current;
664                 return true;
665             } else if (UNLIKELY(c == '\\')) {
666                 current++;
667                 isFast = false;
668             } else if (UNLIKELY(c < CODE_SPACE)) {
669                 return false;
670             }
671             current++;
672         }
673         return false;
674     }
675 
IsFastParseString(bool & isFast,bool & isAscii)676     bool IsFastParseString(bool &isFast, bool &isAscii)
677     {
678         Text current = current_;
679         while (current != end_) {
680             if (!IsLegalAsciiCharacter(*current, isAscii)) {
681                 return false;
682             }
683             if (*current == '\\') {
684                 isFast = false;
685             }
686             current++;
687         }
688         return true;
689     }
690 
IsFastParseAsciiString(bool & isFast)691     bool IsFastParseAsciiString(bool &isFast)
692     {
693         Text current = current_;
694         while (current != end_) {
695             if (*current < CODE_SPACE) {
696                 return false;
697             } else if (*current == '\\') {
698                 isFast = false;
699             }
700             current++;
701         }
702         return true;
703     }
704 
ConvertStringUnicode(CVector<uint16_t> & vec)705     bool ConvertStringUnicode(CVector<uint16_t> &vec)
706     {
707         uint32_t remainingLength = end_ - current_;
708         if (remainingLength < UNICODE_DIGIT_LENGTH) {
709             return false;
710         }
711         uint16_t res = 0;
712         uint32_t exponent = UNICODE_DIGIT_LENGTH;
713         for (uint32_t pos = 0; pos < UNICODE_DIGIT_LENGTH; pos++) {
714             current_++;
715             exponent--;
716             if (*current_ >= '0' && *current_ <= '9') {
717                 res += (*current_ - '0') * pow(NUMBER_SIXTEEN, exponent);
718             } else if (*current_ >= 'a' && *current_ <= 'f') {
719                 res += (*current_ - 'a' + NUMBER_TEN) * pow(NUMBER_SIXTEEN, exponent);
720             } else if (*current_ >= 'A' && *current_ <= 'F') {
721                 res += (*current_ - 'A' + NUMBER_TEN) * pow(NUMBER_SIXTEEN, exponent);
722             } else {
723                 return false;
724             }
725         }
726 
727         vec.emplace_back(res);
728 
729         if (*(current_ + 1) == '\\' && *(current_ + 2) == 'u') {  // 2: next two chars
730             current_ += 2;                                        // 2: point moves backwards by two digits
731             return ConvertStringUnicode(vec);
732         }
733         return true;
734     }
735 
CheckZeroBeginNumber(bool & hasExponent)736     bool CheckZeroBeginNumber(bool &hasExponent)
737     {
738         if (current_++ != end_) {
739             if (*current_ == '.') {
740                 if (!IsDecimalsLegal(hasExponent)) {
741                     return false;
742                 }
743             } else if (*current_ == 'e' || *current_ == 'E') {
744                 if (!IsExponentLegal(hasExponent)) {
745                     return false;
746                 }
747             } else {
748                 return false;
749             }
750         }
751         return true;
752     }
753 
CheckNonZeroBeginNumber(bool & hasExponent)754     bool CheckNonZeroBeginNumber(bool &hasExponent)
755     {
756         while (current_ != end_) {
757             current_++;
758             if (IsNumberCharacter(*current_)) {
759                 continue;
760             } else if (*current_ == '.') {
761                 if (!IsDecimalsLegal(hasExponent)) {
762                     return false;
763                 }
764             } else if (*current_ == 'e' || *current_ == 'E') {
765                 if (!IsExponentLegal(hasExponent)) {
766                     return false;
767                 }
768             } else {
769                 return false;
770             }
771         }
772         return true;
773     }
774 
IsLegalAsciiCharacter(T c,bool & isAscii)775     bool IsLegalAsciiCharacter(T c, bool &isAscii)
776     {
777         if (c <= ASCII_END) {
778             if (c >= CODE_SPACE) {
779                 return true;
780             }
781             return false;
782         }
783         isAscii = false;
784         return true;
785     }
786 
787     bool isAsciiString_ {false};
788     Text end_ {nullptr};
789     Text current_ {nullptr};
790     Text range_ {nullptr};
791     JSThread *thread_ {nullptr};
792     ObjectFactory *factory_ {nullptr};
793     GlobalEnv *env_ {nullptr};
794 };
795 
796 class Internalize {
797 public:
798     static JSHandle<JSTaggedValue> InternalizeJsonProperty(JSThread *thread, const JSHandle<JSObject> &holder,
799                                                            const JSHandle<JSTaggedValue> &name,
800                                                            const JSHandle<JSTaggedValue> &receiver);
801 private:
802     static bool RecurseAndApply(JSThread *thread, const JSHandle<JSObject> &holder, const JSHandle<JSTaggedValue> &name,
803                                 const JSHandle<JSTaggedValue> &receiver);
804 };
805 }  // namespace panda::ecmascript::base
806 
807 #endif  // ECMASCRIPT_BASE_JSON_PARSE_INL_H
808