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