1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Features shared by parsing and pre-parsing scanners. 6 7 #ifndef V8_PARSING_SCANNER_H_ 8 #define V8_PARSING_SCANNER_H_ 9 10 #include <algorithm> 11 #include <memory> 12 13 #include "src/base/logging.h" 14 #include "src/base/strings.h" 15 #include "src/common/globals.h" 16 #include "src/common/message-template.h" 17 #include "src/parsing/literal-buffer.h" 18 #include "src/parsing/parse-info.h" 19 #include "src/parsing/token.h" 20 #include "src/regexp/regexp-flags.h" 21 #include "src/strings/char-predicates.h" 22 #include "src/strings/unicode.h" 23 #include "src/utils/allocation.h" 24 25 namespace v8 { 26 namespace internal { 27 28 class AstRawString; 29 class AstValueFactory; 30 class ExternalOneByteString; 31 class ExternalTwoByteString; 32 class ParserRecorder; 33 class RuntimeCallStats; 34 class Zone; 35 36 // --------------------------------------------------------------------- 37 // Buffered stream of UTF-16 code units, using an internal UTF-16 buffer. 38 // A code unit is a 16 bit value representing either a 16 bit code point 39 // or one part of a surrogate pair that make a single 21 bit code point. 40 class Utf16CharacterStream { 41 public: 42 static constexpr base::uc32 kEndOfInput = static_cast<base::uc32>(-1); 43 44 virtual ~Utf16CharacterStream() = default; 45 set_parser_error()46 V8_INLINE void set_parser_error() { 47 buffer_cursor_ = buffer_end_; 48 has_parser_error_ = true; 49 } reset_parser_error_flag()50 V8_INLINE void reset_parser_error_flag() { has_parser_error_ = false; } has_parser_error()51 V8_INLINE bool has_parser_error() const { return has_parser_error_; } 52 Peek()53 inline base::uc32 Peek() { 54 if (V8_LIKELY(buffer_cursor_ < buffer_end_)) { 55 return static_cast<base::uc32>(*buffer_cursor_); 56 } else if (ReadBlockChecked(pos())) { 57 return static_cast<base::uc32>(*buffer_cursor_); 58 } else { 59 return kEndOfInput; 60 } 61 } 62 63 // Returns and advances past the next UTF-16 code unit in the input 64 // stream. If there are no more code units it returns kEndOfInput. Advance()65 inline base::uc32 Advance() { 66 base::uc32 result = Peek(); 67 buffer_cursor_++; 68 return result; 69 } 70 71 // Returns and advances past the next UTF-16 code unit in the input stream 72 // that meets the checks requirement. If there are no more code units it 73 // returns kEndOfInput. 74 template <typename FunctionType> AdvanceUntil(FunctionType check)75 V8_INLINE base::uc32 AdvanceUntil(FunctionType check) { 76 while (true) { 77 auto next_cursor_pos = 78 std::find_if(buffer_cursor_, buffer_end_, [&check](uint16_t raw_c0_) { 79 base::uc32 c0_ = static_cast<base::uc32>(raw_c0_); 80 return check(c0_); 81 }); 82 83 if (next_cursor_pos == buffer_end_) { 84 buffer_cursor_ = buffer_end_; 85 if (!ReadBlockChecked(pos())) { 86 buffer_cursor_++; 87 return kEndOfInput; 88 } 89 } else { 90 buffer_cursor_ = next_cursor_pos + 1; 91 return static_cast<base::uc32>(*next_cursor_pos); 92 } 93 } 94 } 95 96 // Go back one by one character in the input stream. 97 // This undoes the most recent Advance(). Back()98 inline void Back() { 99 // The common case - if the previous character is within 100 // buffer_start_ .. buffer_end_ will be handles locally. 101 // Otherwise, a new block is requested. 102 if (V8_LIKELY(buffer_cursor_ > buffer_start_)) { 103 buffer_cursor_--; 104 } else { 105 ReadBlockChecked(pos() - 1); 106 } 107 } 108 pos()109 inline size_t pos() const { 110 return buffer_pos_ + (buffer_cursor_ - buffer_start_); 111 } 112 Seek(size_t pos)113 inline void Seek(size_t pos) { 114 if (V8_LIKELY(pos >= buffer_pos_ && 115 pos < (buffer_pos_ + (buffer_end_ - buffer_start_)))) { 116 buffer_cursor_ = buffer_start_ + (pos - buffer_pos_); 117 } else { 118 ReadBlockChecked(pos); 119 } 120 } 121 122 // Returns true if the stream could access the V8 heap after construction. can_be_cloned_for_parallel_access()123 bool can_be_cloned_for_parallel_access() const { 124 return can_be_cloned() && !can_access_heap(); 125 } 126 127 // Returns true if the stream can be cloned with Clone. 128 // TODO(rmcilroy): Remove this once ChunkedStreams can be cloned. 129 virtual bool can_be_cloned() const = 0; 130 131 // Clones the character stream to enable another independent scanner to access 132 // the same underlying stream. 133 virtual std::unique_ptr<Utf16CharacterStream> Clone() const = 0; 134 135 // Returns true if the stream could access the V8 heap after construction. 136 virtual bool can_access_heap() const = 0; 137 runtime_call_stats()138 RuntimeCallStats* runtime_call_stats() const { return runtime_call_stats_; } set_runtime_call_stats(RuntimeCallStats * runtime_call_stats)139 void set_runtime_call_stats(RuntimeCallStats* runtime_call_stats) { 140 runtime_call_stats_ = runtime_call_stats; 141 } 142 143 protected: Utf16CharacterStream(const uint16_t * buffer_start,const uint16_t * buffer_cursor,const uint16_t * buffer_end,size_t buffer_pos)144 Utf16CharacterStream(const uint16_t* buffer_start, 145 const uint16_t* buffer_cursor, 146 const uint16_t* buffer_end, size_t buffer_pos) 147 : buffer_start_(buffer_start), 148 buffer_cursor_(buffer_cursor), 149 buffer_end_(buffer_end), 150 buffer_pos_(buffer_pos) {} Utf16CharacterStream()151 Utf16CharacterStream() : Utf16CharacterStream(nullptr, nullptr, nullptr, 0) {} 152 ReadBlockChecked(size_t position)153 bool ReadBlockChecked(size_t position) { 154 // The callers of this method (Back/Back2/Seek) should handle the easy 155 // case (seeking within the current buffer), and we should only get here 156 // if we actually require new data. 157 // (This is really an efficiency check, not a correctness invariant.) 158 DCHECK(position < buffer_pos_ || 159 position >= buffer_pos_ + (buffer_end_ - buffer_start_)); 160 161 bool success = !has_parser_error() && ReadBlock(position); 162 163 // Post-conditions: 1, We should always be at the right position. 164 // 2, Cursor should be inside the buffer. 165 // 3, We should have more characters available iff success. 166 DCHECK_EQ(pos(), position); 167 DCHECK_LE(buffer_cursor_, buffer_end_); 168 DCHECK_LE(buffer_start_, buffer_cursor_); 169 DCHECK_EQ(success, buffer_cursor_ < buffer_end_); 170 return success; 171 } 172 173 // Read more data, and update buffer_*_ to point to it. 174 // Returns true if more data was available. 175 // 176 // ReadBlock(position) may modify any of the buffer_*_ members, but must make 177 // sure that the result of pos() becomes |position|. 178 // 179 // Examples: 180 // - a stream could either fill a separate buffer. Then buffer_start_ and 181 // buffer_cursor_ would point to the beginning of the buffer, and 182 // buffer_pos would be the old pos(). 183 // - a stream with existing buffer chunks would set buffer_start_ and 184 // buffer_end_ to cover the full chunk, and then buffer_cursor_ would 185 // point into the middle of the buffer, while buffer_pos_ would describe 186 // the start of the buffer. 187 virtual bool ReadBlock(size_t position) = 0; 188 189 // Fields describing the location of the current buffer physically in memory, 190 // and semantically within the source string. 191 // 192 // 0 buffer_pos_ pos() 193 // | | | 194 // v________________________v___v_____________ 195 // | | | | 196 // Source string: | | Buffer | | 197 // |________________________|________|________| 198 // ^ ^ ^ 199 // | | | 200 // Pointers: buffer_start_ | buffer_end_ 201 // buffer_cursor_ 202 const uint16_t* buffer_start_; 203 const uint16_t* buffer_cursor_; 204 const uint16_t* buffer_end_; 205 size_t buffer_pos_; 206 RuntimeCallStats* runtime_call_stats_; 207 bool has_parser_error_ = false; 208 }; 209 210 // ---------------------------------------------------------------------------- 211 // JavaScript Scanner. 212 213 class V8_EXPORT_PRIVATE Scanner { 214 public: 215 // Scoped helper for a re-settable bookmark. 216 class V8_EXPORT_PRIVATE V8_NODISCARD BookmarkScope { 217 public: BookmarkScope(Scanner * scanner)218 explicit BookmarkScope(Scanner* scanner) 219 : scanner_(scanner), 220 bookmark_(kNoBookmark), 221 had_parser_error_(scanner->has_parser_error()) { 222 DCHECK_NOT_NULL(scanner_); 223 } 224 ~BookmarkScope() = default; 225 BookmarkScope(const BookmarkScope&) = delete; 226 BookmarkScope& operator=(const BookmarkScope&) = delete; 227 228 void Set(size_t bookmark); 229 void Apply(); 230 bool HasBeenSet() const; 231 bool HasBeenApplied() const; 232 233 private: 234 static const size_t kNoBookmark; 235 static const size_t kBookmarkWasApplied; 236 237 Scanner* scanner_; 238 size_t bookmark_; 239 bool had_parser_error_; 240 }; 241 242 // Sets the Scanner into an error state to stop further scanning and terminate 243 // the parsing by only returning ILLEGAL tokens after that. set_parser_error()244 V8_INLINE void set_parser_error() { 245 if (!has_parser_error()) { 246 c0_ = kEndOfInput; 247 source_->set_parser_error(); 248 for (TokenDesc& desc : token_storage_) desc.token = Token::ILLEGAL; 249 } 250 } reset_parser_error_flag()251 V8_INLINE void reset_parser_error_flag() { 252 source_->reset_parser_error_flag(); 253 } has_parser_error()254 V8_INLINE bool has_parser_error() const { 255 return source_->has_parser_error(); 256 } 257 258 // Representation of an interval of source positions. 259 struct Location { LocationLocation260 Location(int b, int e) : beg_pos(b), end_pos(e) { } LocationLocation261 Location() : beg_pos(0), end_pos(0) { } 262 lengthLocation263 int length() const { return end_pos - beg_pos; } IsValidLocation264 bool IsValid() const { return base::IsInRange(beg_pos, 0, end_pos); } 265 invalidLocation266 static Location invalid() { return Location(-1, 0); } 267 268 int beg_pos; 269 int end_pos; 270 }; 271 272 // -1 is outside of the range of any real source code. 273 static constexpr base::uc32 kEndOfInput = Utf16CharacterStream::kEndOfInput; 274 static constexpr base::uc32 kInvalidSequence = static_cast<base::uc32>(-1); 275 Invalid()276 static constexpr base::uc32 Invalid() { return Scanner::kInvalidSequence; } 277 static bool IsInvalid(base::uc32 c); 278 279 explicit Scanner(Utf16CharacterStream* source, UnoptimizedCompileFlags flags); 280 281 void Initialize(); 282 283 // Returns the next token and advances input. 284 Token::Value Next(); 285 // Returns the token following peek() 286 Token::Value PeekAhead(); 287 // Returns the current token again. current_token()288 Token::Value current_token() const { return current().token; } 289 290 // Returns the location information for the current token 291 // (the token last returned by Next()). location()292 const Location& location() const { return current().location; } 293 294 // This error is specifically an invalid hex or unicode escape sequence. has_error()295 bool has_error() const { return scanner_error_ != MessageTemplate::kNone; } error()296 MessageTemplate error() const { return scanner_error_; } error_location()297 const Location& error_location() const { return scanner_error_location_; } 298 has_invalid_template_escape()299 bool has_invalid_template_escape() const { 300 return current().invalid_template_escape_message != MessageTemplate::kNone; 301 } invalid_template_escape_message()302 MessageTemplate invalid_template_escape_message() const { 303 DCHECK(has_invalid_template_escape()); 304 return current().invalid_template_escape_message; 305 } 306 clear_invalid_template_escape_message()307 void clear_invalid_template_escape_message() { 308 DCHECK(has_invalid_template_escape()); 309 current_->invalid_template_escape_message = MessageTemplate::kNone; 310 } 311 invalid_template_escape_location()312 Location invalid_template_escape_location() const { 313 DCHECK(has_invalid_template_escape()); 314 return current().invalid_template_escape_location; 315 } 316 317 // Similar functions for the upcoming token. 318 319 // One token look-ahead (past the token returned by Next()). peek()320 Token::Value peek() const { return next().token; } 321 peek_location()322 const Location& peek_location() const { return next().location; } 323 literal_contains_escapes()324 bool literal_contains_escapes() const { 325 return LiteralContainsEscapes(current()); 326 } 327 next_literal_contains_escapes()328 bool next_literal_contains_escapes() const { 329 return LiteralContainsEscapes(next()); 330 } 331 332 const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory) const; 333 334 const AstRawString* NextSymbol(AstValueFactory* ast_value_factory) const; 335 const AstRawString* CurrentRawSymbol( 336 AstValueFactory* ast_value_factory) const; 337 338 double DoubleValue(); BigIntLiteral()339 base::Vector<const uint8_t> BigIntLiteral() const { 340 return literal_one_byte_string(); 341 } 342 343 const char* CurrentLiteralAsCString(Zone* zone) const; 344 CurrentMatches(Token::Value token)345 inline bool CurrentMatches(Token::Value token) const { 346 DCHECK(Token::IsKeyword(token)); 347 return current().token == token; 348 } 349 350 template <size_t N> NextLiteralExactlyEquals(const char (& s)[N])351 bool NextLiteralExactlyEquals(const char (&s)[N]) { 352 DCHECK(next().CanAccessLiteral()); 353 // The length of the token is used to make sure the literal equals without 354 // taking escape sequences (e.g., "use \x73trict") or line continuations 355 // (e.g., "use \(newline) strict") into account. 356 if (!is_next_literal_one_byte()) return false; 357 if (peek_location().length() != N + 1) return false; 358 359 base::Vector<const uint8_t> next = next_literal_one_byte_string(); 360 const char* chars = reinterpret_cast<const char*>(next.begin()); 361 return next.length() == N - 1 && strncmp(s, chars, N - 1) == 0; 362 } 363 364 template <size_t N> CurrentLiteralEquals(const char (& s)[N])365 bool CurrentLiteralEquals(const char (&s)[N]) { 366 DCHECK(current().CanAccessLiteral()); 367 if (!is_literal_one_byte()) return false; 368 369 base::Vector<const uint8_t> current = literal_one_byte_string(); 370 const char* chars = reinterpret_cast<const char*>(current.begin()); 371 return current.length() == N - 1 && strncmp(s, chars, N - 1) == 0; 372 } 373 374 // Returns the location of the last seen octal literal. octal_position()375 Location octal_position() const { return octal_pos_; } clear_octal_position()376 void clear_octal_position() { 377 octal_pos_ = Location::invalid(); 378 octal_message_ = MessageTemplate::kNone; 379 } octal_message()380 MessageTemplate octal_message() const { return octal_message_; } 381 382 // Returns the value of the last smi that was scanned. smi_value()383 uint32_t smi_value() const { return current().smi_value_; } 384 385 // Seek forward to the given position. This operation does not 386 // work in general, for instance when there are pushed back 387 // characters, but works for seeking forward until simple delimiter 388 // tokens, which is what it is used for. 389 void SeekForward(int pos); 390 391 // Returns true if there was a line terminator before the peek'ed token, 392 // possibly inside a multi-line comment. HasLineTerminatorBeforeNext()393 bool HasLineTerminatorBeforeNext() const { 394 return next().after_line_terminator; 395 } 396 HasLineTerminatorAfterNext()397 bool HasLineTerminatorAfterNext() { 398 Token::Value ensure_next_next = PeekAhead(); 399 USE(ensure_next_next); 400 return next_next().after_line_terminator; 401 } 402 403 // Scans the input as a regular expression pattern, next token must be /(=). 404 // Returns true if a pattern is scanned. 405 bool ScanRegExpPattern(); 406 // Scans the input as regular expression flags. Returns the flags on success. 407 base::Optional<RegExpFlags> ScanRegExpFlags(); 408 409 // Scans the input as a template literal ScanTemplateContinuation()410 Token::Value ScanTemplateContinuation() { 411 DCHECK_EQ(next().token, Token::RBRACE); 412 DCHECK_EQ(source_pos() - 1, next().location.beg_pos); 413 return ScanTemplateSpan(); 414 } 415 416 template <typename IsolateT> 417 Handle<String> SourceUrl(IsolateT* isolate) const; 418 template <typename IsolateT> 419 Handle<String> SourceMappingUrl(IsolateT* isolate) const; 420 FoundHtmlComment()421 bool FoundHtmlComment() const { return found_html_comment_; } 422 stream()423 const Utf16CharacterStream* stream() const { return source_; } 424 425 private: 426 // Scoped helper for saving & restoring scanner error state. 427 // This is used for tagged template literals, in which normally forbidden 428 // escape sequences are allowed. 429 class ErrorState; 430 431 // The current and look-ahead token. 432 struct TokenDesc { 433 Location location = {0, 0}; 434 LiteralBuffer literal_chars; 435 LiteralBuffer raw_literal_chars; 436 Token::Value token = Token::UNINITIALIZED; 437 MessageTemplate invalid_template_escape_message = MessageTemplate::kNone; 438 Location invalid_template_escape_location; 439 uint32_t smi_value_ = 0; 440 bool after_line_terminator = false; 441 442 #ifdef DEBUG CanAccessLiteralTokenDesc443 bool CanAccessLiteral() const { 444 return token == Token::PRIVATE_NAME || token == Token::ILLEGAL || 445 token == Token::ESCAPED_KEYWORD || token == Token::UNINITIALIZED || 446 token == Token::REGEXP_LITERAL || 447 base::IsInRange(token, Token::NUMBER, Token::STRING) || 448 Token::IsAnyIdentifier(token) || Token::IsKeyword(token) || 449 base::IsInRange(token, Token::TEMPLATE_SPAN, Token::TEMPLATE_TAIL); 450 } CanAccessRawLiteralTokenDesc451 bool CanAccessRawLiteral() const { 452 return token == Token::ILLEGAL || token == Token::UNINITIALIZED || 453 base::IsInRange(token, Token::TEMPLATE_SPAN, Token::TEMPLATE_TAIL); 454 } 455 #endif // DEBUG 456 }; 457 458 enum NumberKind { 459 IMPLICIT_OCTAL, 460 BINARY, 461 OCTAL, 462 HEX, 463 DECIMAL, 464 DECIMAL_WITH_LEADING_ZERO 465 }; 466 IsValidBigIntKind(NumberKind kind)467 inline bool IsValidBigIntKind(NumberKind kind) { 468 return base::IsInRange(kind, BINARY, DECIMAL); 469 } 470 IsDecimalNumberKind(NumberKind kind)471 inline bool IsDecimalNumberKind(NumberKind kind) { 472 return base::IsInRange(kind, DECIMAL, DECIMAL_WITH_LEADING_ZERO); 473 } 474 475 static const int kCharacterLookaheadBufferSize = 1; 476 static const int kMaxAscii = 127; 477 478 // Scans octal escape sequence. Also accepts "\0" decimal escape sequence. 479 template <bool capture_raw> 480 base::uc32 ScanOctalEscape(base::uc32 c, int length); 481 482 // Call this after setting source_ to the input. Init()483 void Init() { 484 // Set c0_ (one character ahead) 485 STATIC_ASSERT(kCharacterLookaheadBufferSize == 1); 486 Advance(); 487 488 current_ = &token_storage_[0]; 489 next_ = &token_storage_[1]; 490 next_next_ = &token_storage_[2]; 491 492 found_html_comment_ = false; 493 scanner_error_ = MessageTemplate::kNone; 494 } 495 ReportScannerError(const Location & location,MessageTemplate error)496 void ReportScannerError(const Location& location, MessageTemplate error) { 497 if (has_error()) return; 498 scanner_error_ = error; 499 scanner_error_location_ = location; 500 } 501 ReportScannerError(int pos,MessageTemplate error)502 void ReportScannerError(int pos, MessageTemplate error) { 503 if (has_error()) return; 504 scanner_error_ = error; 505 scanner_error_location_ = Location(pos, pos + 1); 506 } 507 508 // Seek to the next_ token at the given position. 509 void SeekNext(size_t position); 510 AddLiteralChar(base::uc32 c)511 V8_INLINE void AddLiteralChar(base::uc32 c) { 512 next().literal_chars.AddChar(c); 513 } 514 AddLiteralChar(char c)515 V8_INLINE void AddLiteralChar(char c) { next().literal_chars.AddChar(c); } 516 AddRawLiteralChar(base::uc32 c)517 V8_INLINE void AddRawLiteralChar(base::uc32 c) { 518 next().raw_literal_chars.AddChar(c); 519 } 520 AddLiteralCharAdvance()521 V8_INLINE void AddLiteralCharAdvance() { 522 AddLiteralChar(c0_); 523 Advance(); 524 } 525 526 // Low-level scanning support. 527 template <bool capture_raw = false> Advance()528 void Advance() { 529 if (capture_raw) { 530 AddRawLiteralChar(c0_); 531 } 532 c0_ = source_->Advance(); 533 } 534 535 template <typename FunctionType> AdvanceUntil(FunctionType check)536 V8_INLINE void AdvanceUntil(FunctionType check) { 537 c0_ = source_->AdvanceUntil(check); 538 } 539 CombineSurrogatePair()540 bool CombineSurrogatePair() { 541 DCHECK(!unibrow::Utf16::IsLeadSurrogate(kEndOfInput)); 542 if (unibrow::Utf16::IsLeadSurrogate(c0_)) { 543 base::uc32 c1 = source_->Advance(); 544 DCHECK(!unibrow::Utf16::IsTrailSurrogate(kEndOfInput)); 545 if (unibrow::Utf16::IsTrailSurrogate(c1)) { 546 c0_ = unibrow::Utf16::CombineSurrogatePair(c0_, c1); 547 return true; 548 } 549 source_->Back(); 550 } 551 return false; 552 } 553 PushBack(base::uc32 ch)554 void PushBack(base::uc32 ch) { 555 DCHECK(IsInvalid(c0_) || 556 base::IsInRange(c0_, 0u, unibrow::Utf16::kMaxNonSurrogateCharCode)); 557 source_->Back(); 558 c0_ = ch; 559 } 560 Peek()561 base::uc32 Peek() const { return source_->Peek(); } 562 Select(Token::Value tok)563 inline Token::Value Select(Token::Value tok) { 564 Advance(); 565 return tok; 566 } 567 Select(base::uc32 next,Token::Value then,Token::Value else_)568 inline Token::Value Select(base::uc32 next, Token::Value then, 569 Token::Value else_) { 570 Advance(); 571 if (c0_ == next) { 572 Advance(); 573 return then; 574 } else { 575 return else_; 576 } 577 } 578 // Returns the literal string, if any, for the current token (the 579 // token last returned by Next()). The string is 0-terminated. 580 // Literal strings are collected for identifiers, strings, numbers as well 581 // as for template literals. For template literals we also collect the raw 582 // form. 583 // These functions only give the correct result if the literal was scanned 584 // when a LiteralScope object is alive. 585 // 586 // Current usage of these functions is unfortunately a little undisciplined, 587 // and is_literal_one_byte() + is_literal_one_byte_string() is also 588 // requested for tokens that do not have a literal. Hence, we treat any 589 // token as a one-byte literal. E.g. Token::FUNCTION pretends to have a 590 // literal "function". literal_one_byte_string()591 base::Vector<const uint8_t> literal_one_byte_string() const { 592 DCHECK(current().CanAccessLiteral() || Token::IsKeyword(current().token) || 593 current().token == Token::ESCAPED_KEYWORD); 594 return current().literal_chars.one_byte_literal(); 595 } literal_two_byte_string()596 base::Vector<const uint16_t> literal_two_byte_string() const { 597 DCHECK(current().CanAccessLiteral() || Token::IsKeyword(current().token) || 598 current().token == Token::ESCAPED_KEYWORD); 599 return current().literal_chars.two_byte_literal(); 600 } is_literal_one_byte()601 bool is_literal_one_byte() const { 602 DCHECK(current().CanAccessLiteral() || Token::IsKeyword(current().token) || 603 current().token == Token::ESCAPED_KEYWORD); 604 return current().literal_chars.is_one_byte(); 605 } 606 // Returns the literal string for the next token (the token that 607 // would be returned if Next() were called). next_literal_one_byte_string()608 base::Vector<const uint8_t> next_literal_one_byte_string() const { 609 DCHECK(next().CanAccessLiteral()); 610 return next().literal_chars.one_byte_literal(); 611 } next_literal_two_byte_string()612 base::Vector<const uint16_t> next_literal_two_byte_string() const { 613 DCHECK(next().CanAccessLiteral()); 614 return next().literal_chars.two_byte_literal(); 615 } is_next_literal_one_byte()616 bool is_next_literal_one_byte() const { 617 DCHECK(next().CanAccessLiteral()); 618 return next().literal_chars.is_one_byte(); 619 } raw_literal_one_byte_string()620 base::Vector<const uint8_t> raw_literal_one_byte_string() const { 621 DCHECK(current().CanAccessRawLiteral()); 622 return current().raw_literal_chars.one_byte_literal(); 623 } raw_literal_two_byte_string()624 base::Vector<const uint16_t> raw_literal_two_byte_string() const { 625 DCHECK(current().CanAccessRawLiteral()); 626 return current().raw_literal_chars.two_byte_literal(); 627 } is_raw_literal_one_byte()628 bool is_raw_literal_one_byte() const { 629 DCHECK(current().CanAccessRawLiteral()); 630 return current().raw_literal_chars.is_one_byte(); 631 } 632 633 template <bool capture_raw, bool unicode = false> 634 base::uc32 ScanHexNumber(int expected_length); 635 // Scan a number of any length but not bigger than max_value. For example, the 636 // number can be 000000001, so it's very long in characters but its value is 637 // small. 638 template <bool capture_raw> 639 base::uc32 ScanUnlimitedLengthHexNumber(base::uc32 max_value, int beg_pos); 640 641 // Scans a single JavaScript token. 642 V8_INLINE Token::Value ScanSingleToken(); 643 V8_INLINE void Scan(); 644 // Performance hack: pass through a pre-calculated "next()" value to avoid 645 // having to re-calculate it in Scan. You'd think the compiler would be able 646 // to hoist the next() calculation out of the inlined Scan method, but seems 647 // that pointer aliasing analysis fails show that this is safe. 648 V8_INLINE void Scan(TokenDesc* next_desc); 649 650 V8_INLINE Token::Value SkipWhiteSpace(); 651 Token::Value SkipSingleHTMLComment(); 652 Token::Value SkipSingleLineComment(); 653 Token::Value SkipSourceURLComment(); 654 void TryToParseSourceURLComment(); 655 Token::Value SkipMultiLineComment(); 656 // Scans a possible HTML comment -- begins with '<!'. 657 Token::Value ScanHtmlComment(); 658 659 bool ScanDigitsWithNumericSeparators(bool (*predicate)(base::uc32 ch), 660 bool is_check_first_digit); 661 bool ScanDecimalDigits(bool allow_numeric_separator); 662 // Optimized function to scan decimal number as Smi. 663 bool ScanDecimalAsSmi(uint64_t* value, bool allow_numeric_separator); 664 bool ScanDecimalAsSmiWithNumericSeparators(uint64_t* value); 665 bool ScanHexDigits(); 666 bool ScanBinaryDigits(); 667 bool ScanSignedInteger(); 668 bool ScanOctalDigits(); 669 bool ScanImplicitOctalDigits(int start_pos, NumberKind* kind); 670 671 Token::Value ScanNumber(bool seen_period); 672 V8_INLINE Token::Value ScanIdentifierOrKeyword(); 673 V8_INLINE Token::Value ScanIdentifierOrKeywordInner(); 674 Token::Value ScanIdentifierOrKeywordInnerSlow(bool escaped, 675 bool can_be_keyword); 676 677 Token::Value ScanString(); 678 Token::Value ScanPrivateName(); 679 680 // Scans an escape-sequence which is part of a string and adds the 681 // decoded character to the current literal. Returns true if a pattern 682 // is scanned. 683 template <bool capture_raw> 684 bool ScanEscape(); 685 686 // Decodes a Unicode escape-sequence which is part of an identifier. 687 // If the escape sequence cannot be decoded the result is kBadChar. 688 base::uc32 ScanIdentifierUnicodeEscape(); 689 // Helper for the above functions. 690 template <bool capture_raw> 691 base::uc32 ScanUnicodeEscape(); 692 693 Token::Value ScanTemplateSpan(); 694 695 // Return the current source position. source_pos()696 int source_pos() { 697 return static_cast<int>(source_->pos()) - kCharacterLookaheadBufferSize; 698 } 699 LiteralContainsEscapes(const TokenDesc & token)700 static bool LiteralContainsEscapes(const TokenDesc& token) { 701 Location location = token.location; 702 int source_length = (location.end_pos - location.beg_pos); 703 if (token.token == Token::STRING) { 704 // Subtract delimiters. 705 source_length -= 2; 706 } 707 return token.literal_chars.length() != source_length; 708 } 709 710 #ifdef DEBUG 711 void SanityCheckTokenDesc(const TokenDesc&) const; 712 #endif 713 next()714 TokenDesc& next() { return *next_; } 715 current()716 const TokenDesc& current() const { return *current_; } next()717 const TokenDesc& next() const { return *next_; } next_next()718 const TokenDesc& next_next() const { return *next_next_; } 719 720 UnoptimizedCompileFlags flags_; 721 722 TokenDesc* current_; // desc for current token (as returned by Next()) 723 TokenDesc* next_; // desc for next token (one token look-ahead) 724 TokenDesc* next_next_; // desc for the token after next (after PeakAhead()) 725 726 // Input stream. Must be initialized to an Utf16CharacterStream. 727 Utf16CharacterStream* const source_; 728 729 // One Unicode character look-ahead; c0_ < 0 at the end of the input. 730 base::uc32 c0_; 731 732 TokenDesc token_storage_[3]; 733 734 // Whether this scanner encountered an HTML comment. 735 bool found_html_comment_; 736 737 // Values parsed from magic comments. 738 LiteralBuffer source_url_; 739 LiteralBuffer source_mapping_url_; 740 741 // Last-seen positions of potentially problematic tokens. 742 Location octal_pos_; 743 MessageTemplate octal_message_; 744 745 MessageTemplate scanner_error_; 746 Location scanner_error_location_; 747 }; 748 749 } // namespace internal 750 } // namespace v8 751 752 #endif // V8_PARSING_SCANNER_H_ 753