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.
5 // Features shared by parsing and pre-parsing scanners.
10 #include "src/allocation.h"
11 #include "src/base/logging.h"
12 #include "src/char-predicates.h"
13 #include "src/globals.h"
14 #include "src/hashmap.h"
16 #include "src/token.h"
17 #include "src/unicode-inl.h"
18 #include "src/unicode-decoder.h"
19 #include "src/utils.h"
26 class AstValueFactory;
30 // Returns the value (0 .. 15) of a hexadecimal character c.
31 // If c is not a legal hexadecimal character, returns a value < 0.
32 inline int HexValue(uc32 c) {
34 if (static_cast<unsigned>(c) <= 9) return c;
35 c = (c | 0x20) - ('a' - '0'); // detect 0x11..0x16 and 0x31..0x36.
36 if (static_cast<unsigned>(c) <= 5) return c + 10;
41 // ---------------------------------------------------------------------
42 // Buffered stream of UTF-16 code units, using an internal UTF-16 buffer.
43 // A code unit is a 16 bit value representing either a 16 bit code point
44 // or one part of a surrogate pair that make a single 21 bit code point.
46 class Utf16CharacterStream {
48 Utf16CharacterStream() : pos_(0) { }
49 virtual ~Utf16CharacterStream() { }
51 // Returns and advances past the next UTF-16 code unit in the input
52 // stream. If there are no more code units, it returns a negative
54 inline uc32 Advance() {
55 if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
57 return static_cast<uc32>(*(buffer_cursor_++));
59 // Note: currently the following increment is necessary to avoid a
60 // parser problem! The scanner treats the final kEndOfInput as
61 // a code unit with a position, and does math relative to that
68 // Return the current position in the code unit stream.
70 inline size_t pos() const { return pos_; }
72 // Skips forward past the next code_unit_count UTF-16 code units
73 // in the input, or until the end of input if that comes sooner.
74 // Returns the number of code units actually skipped. If less
75 // than code_unit_count,
76 inline size_t SeekForward(size_t code_unit_count) {
77 size_t buffered_chars = buffer_end_ - buffer_cursor_;
78 if (code_unit_count <= buffered_chars) {
79 buffer_cursor_ += code_unit_count;
80 pos_ += code_unit_count;
81 return code_unit_count;
83 return SlowSeekForward(code_unit_count);
86 // Pushes back the most recently read UTF-16 code unit (or negative
87 // value if at end of input), i.e., the value returned by the most recent
89 // Must not be used right after calling SeekForward.
90 virtual void PushBack(int32_t code_unit) = 0;
93 static const uc32 kEndOfInput = -1;
95 // Ensures that the buffer_cursor_ points to the code_unit at
96 // position pos_ of the input, if possible. If the position
97 // is at or after the end of the input, return false. If there
98 // are more code_units available, return true.
99 virtual bool ReadBlock() = 0;
100 virtual size_t SlowSeekForward(size_t code_unit_count) = 0;
102 const uint16_t* buffer_cursor_;
103 const uint16_t* buffer_end_;
108 // ---------------------------------------------------------------------
109 // Caching predicates used by scanners.
114 typedef unibrow::Utf8Decoder<512> Utf8Decoder;
116 StaticResource<Utf8Decoder>* utf8_decoder() {
117 return &utf8_decoder_;
120 bool IsIdentifierStart(unibrow::uchar c) { return kIsIdentifierStart.get(c); }
121 bool IsIdentifierPart(unibrow::uchar c) { return kIsIdentifierPart.get(c); }
122 bool IsLineTerminator(unibrow::uchar c) { return kIsLineTerminator.get(c); }
123 bool IsLineTerminatorSequence(unibrow::uchar c, unibrow::uchar next) {
124 if (!IsLineTerminator(c)) return false;
125 if (c == 0x000d && next == 0x000a) return false; // CR with following LF.
129 bool IsWhiteSpace(unibrow::uchar c) { return kIsWhiteSpace.get(c); }
130 bool IsWhiteSpaceOrLineTerminator(unibrow::uchar c) {
131 return kIsWhiteSpaceOrLineTerminator.get(c);
135 unibrow::Predicate<IdentifierStart, 128> kIsIdentifierStart;
136 unibrow::Predicate<IdentifierPart, 128> kIsIdentifierPart;
137 unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
138 unibrow::Predicate<WhiteSpace, 128> kIsWhiteSpace;
139 unibrow::Predicate<WhiteSpaceOrLineTerminator, 128>
140 kIsWhiteSpaceOrLineTerminator;
141 StaticResource<Utf8Decoder> utf8_decoder_;
143 DISALLOW_COPY_AND_ASSIGN(UnicodeCache);
147 // ---------------------------------------------------------------------
148 // DuplicateFinder discovers duplicate symbols.
150 class DuplicateFinder {
152 explicit DuplicateFinder(UnicodeCache* constants)
153 : unicode_constants_(constants),
157 int AddOneByteSymbol(Vector<const uint8_t> key, int value);
158 int AddTwoByteSymbol(Vector<const uint16_t> key, int value);
159 // Add a a number literal by converting it (if necessary)
160 // to the string that ToString(ToNumber(literal)) would generate.
161 // and then adding that string with AddOneByteSymbol.
162 // This string is the actual value used as key in an object literal,
163 // and the one that must be different from the other keys.
164 int AddNumber(Vector<const uint8_t> key, int value);
167 int AddSymbol(Vector<const uint8_t> key, bool is_one_byte, int value);
168 // Backs up the key and its length in the backing store.
169 // The backup is stored with a base 127 encoding of the
170 // length (plus a bit saying whether the string is one byte),
171 // followed by the bytes of the key.
172 uint8_t* BackupKey(Vector<const uint8_t> key, bool is_one_byte);
174 // Compare two encoded keys (both pointing into the backing store)
175 // for having the same base-127 encoded lengths and representation.
176 // and then having the same 'length' bytes following.
177 static bool Match(void* first, void* second);
178 // Creates a hash from a sequence of bytes.
179 static uint32_t Hash(Vector<const uint8_t> key, bool is_one_byte);
180 // Checks whether a string containing a JS number is its canonical
182 static bool IsNumberCanonical(Vector<const uint8_t> key);
184 // Size of buffer. Sufficient for using it to call DoubleToCString in
185 // from conversions.h.
186 static const int kBufferSize = 100;
188 UnicodeCache* unicode_constants_;
189 // Backing store used to store strings used as hashmap keys.
190 SequenceCollector<unsigned char> backing_store_;
192 // Buffer used for string->number->canonical string conversions.
193 char number_buffer_[kBufferSize];
197 // ----------------------------------------------------------------------------
198 // LiteralBuffer - Collector of chars of literals.
200 class LiteralBuffer {
202 LiteralBuffer() : is_one_byte_(true), position_(0), backing_store_() { }
205 if (backing_store_.length() > 0) {
206 backing_store_.Dispose();
210 INLINE(void AddChar(uint32_t code_unit)) {
211 if (position_ >= backing_store_.length()) ExpandBuffer();
213 if (code_unit <= unibrow::Latin1::kMaxChar) {
214 backing_store_[position_] = static_cast<byte>(code_unit);
215 position_ += kOneByteSize;
220 if (code_unit <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
221 *reinterpret_cast<uint16_t*>(&backing_store_[position_]) = code_unit;
222 position_ += kUC16Size;
224 *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
225 unibrow::Utf16::LeadSurrogate(code_unit);
226 position_ += kUC16Size;
227 if (position_ >= backing_store_.length()) ExpandBuffer();
228 *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
229 unibrow::Utf16::TrailSurrogate(code_unit);
230 position_ += kUC16Size;
234 bool is_one_byte() const { return is_one_byte_; }
236 bool is_contextual_keyword(Vector<const char> keyword) const {
237 return is_one_byte() && keyword.length() == position_ &&
238 (memcmp(keyword.start(), backing_store_.start(), position_) == 0);
241 Vector<const uint16_t> two_byte_literal() const {
242 DCHECK(!is_one_byte_);
243 DCHECK((position_ & 0x1) == 0);
244 return Vector<const uint16_t>(
245 reinterpret_cast<const uint16_t*>(backing_store_.start()),
249 Vector<const uint8_t> one_byte_literal() const {
250 DCHECK(is_one_byte_);
251 return Vector<const uint8_t>(
252 reinterpret_cast<const uint8_t*>(backing_store_.start()),
257 return is_one_byte_ ? position_ : (position_ >> 1);
260 void ReduceLength(int delta) {
261 position_ -= delta * (is_one_byte_ ? kOneByteSize : kUC16Size);
269 Handle<String> Internalize(Isolate* isolate) const;
272 static const int kInitialCapacity = 16;
273 static const int kGrowthFactory = 4;
274 static const int kMinConversionSlack = 256;
275 static const int kMaxGrowth = 1 * MB;
276 inline int NewCapacity(int min_capacity) {
277 int capacity = Max(min_capacity, backing_store_.length());
278 int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
282 void ExpandBuffer() {
283 Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
284 MemCopy(new_store.start(), backing_store_.start(), position_);
285 backing_store_.Dispose();
286 backing_store_ = new_store;
289 void ConvertToTwoByte() {
290 DCHECK(is_one_byte_);
291 Vector<byte> new_store;
292 int new_content_size = position_ * kUC16Size;
293 if (new_content_size >= backing_store_.length()) {
294 // Ensure room for all currently read code units as UC16 as well
295 // as the code unit about to be stored.
296 new_store = Vector<byte>::New(NewCapacity(new_content_size));
298 new_store = backing_store_;
300 uint8_t* src = backing_store_.start();
301 uint16_t* dst = reinterpret_cast<uint16_t*>(new_store.start());
302 for (int i = position_ - 1; i >= 0; i--) {
305 if (new_store.start() != backing_store_.start()) {
306 backing_store_.Dispose();
307 backing_store_ = new_store;
309 position_ = new_content_size;
310 is_one_byte_ = false;
315 Vector<byte> backing_store_;
317 DISALLOW_COPY_AND_ASSIGN(LiteralBuffer);
321 // ----------------------------------------------------------------------------
322 // JavaScript Scanner.
326 // Scoped helper for literal recording. Automatically drops the literal
327 // if aborting the scanning before it's complete.
330 explicit LiteralScope(Scanner* self) : scanner_(self), complete_(false) {
331 scanner_->StartLiteral();
334 if (!complete_) scanner_->DropLiteral();
345 // Representation of an interval of source positions.
347 Location(int b, int e) : beg_pos(b), end_pos(e) { }
348 Location() : beg_pos(0), end_pos(0) { }
350 bool IsValid() const {
351 return beg_pos >= 0 && end_pos >= beg_pos;
354 static Location invalid() { return Location(-1, -1); }
360 // -1 is outside of the range of any real source code.
361 static const int kNoOctalLocation = -1;
363 explicit Scanner(UnicodeCache* scanner_contants);
365 void Initialize(Utf16CharacterStream* source);
367 // Returns the next token and advances input.
369 // Returns the current token again.
370 Token::Value current_token() { return current_.token; }
371 // Returns the location information for the current token
372 // (the token last returned by Next()).
373 Location location() const { return current_.location; }
375 // Similar functions for the upcoming token.
377 // One token look-ahead (past the token returned by Next()).
378 Token::Value peek() const { return next_.token; }
380 Location peek_location() const { return next_.location; }
382 bool literal_contains_escapes() const {
383 Location location = current_.location;
384 int source_length = (location.end_pos - location.beg_pos);
385 if (current_.token == Token::STRING) {
386 // Subtract delimiters.
389 return current_.literal_chars->length() != source_length;
391 bool is_literal_contextual_keyword(Vector<const char> keyword) {
392 DCHECK_NOT_NULL(current_.literal_chars);
393 return current_.literal_chars->is_contextual_keyword(keyword);
395 bool is_next_contextual_keyword(Vector<const char> keyword) {
396 DCHECK_NOT_NULL(next_.literal_chars);
397 return next_.literal_chars->is_contextual_keyword(keyword);
400 const AstRawString* CurrentSymbol(AstValueFactory* ast_value_factory);
401 const AstRawString* NextSymbol(AstValueFactory* ast_value_factory);
402 const AstRawString* CurrentRawSymbol(AstValueFactory* ast_value_factory);
404 double DoubleValue();
405 bool LiteralMatches(const char* data, int length, bool allow_escapes = true) {
406 if (is_literal_one_byte() &&
407 literal_length() == length &&
408 (allow_escapes || !literal_contains_escapes())) {
410 reinterpret_cast<const char*>(literal_one_byte_string().start());
411 return !strncmp(token, data, length);
415 inline bool UnescapedLiteralMatches(const char* data, int length) {
416 return LiteralMatches(data, length, false);
419 void IsGetOrSet(bool* is_get, bool* is_set) {
420 if (is_literal_one_byte() &&
421 literal_length() == 3 &&
422 !literal_contains_escapes()) {
424 reinterpret_cast<const char*>(literal_one_byte_string().start());
425 *is_get = strncmp(token, "get", 3) == 0;
426 *is_set = !*is_get && strncmp(token, "set", 3) == 0;
430 int FindNumber(DuplicateFinder* finder, int value);
431 int FindSymbol(DuplicateFinder* finder, int value);
433 UnicodeCache* unicode_cache() { return unicode_cache_; }
435 // Returns the location of the last seen octal literal.
436 Location octal_position() const { return octal_pos_; }
437 void clear_octal_position() { octal_pos_ = Location::invalid(); }
439 // Seek forward to the given position. This operation does not
440 // work in general, for instance when there are pushed back
441 // characters, but works for seeking forward until simple delimiter
442 // tokens, which is what it is used for.
443 void SeekForward(int pos);
445 bool HarmonyScoping() const {
446 return harmony_scoping_;
448 void SetHarmonyScoping(bool scoping) {
449 harmony_scoping_ = scoping;
451 bool HarmonyModules() const {
452 return harmony_modules_;
454 void SetHarmonyModules(bool modules) {
455 harmony_modules_ = modules;
457 bool HarmonyNumericLiterals() const {
458 return harmony_numeric_literals_;
460 void SetHarmonyNumericLiterals(bool numeric_literals) {
461 harmony_numeric_literals_ = numeric_literals;
463 bool HarmonyClasses() const {
464 return harmony_classes_;
466 void SetHarmonyClasses(bool classes) {
467 harmony_classes_ = classes;
469 bool HarmonyTemplates() const { return harmony_templates_; }
470 void SetHarmonyTemplates(bool templates) { harmony_templates_ = templates; }
471 bool HarmonyUnicode() const { return harmony_unicode_; }
472 void SetHarmonyUnicode(bool unicode) { harmony_unicode_ = unicode; }
474 // Returns true if there was a line terminator before the peek'ed token,
475 // possibly inside a multi-line comment.
476 bool HasAnyLineTerminatorBeforeNext() const {
477 return has_line_terminator_before_next_ ||
478 has_multiline_comment_before_next_;
481 // Scans the input as a regular expression pattern, previous
482 // character(s) must be /(=). Returns true if a pattern is scanned.
483 bool ScanRegExpPattern(bool seen_equal);
484 // Returns true if regexp flags are scanned (always since flags can
486 bool ScanRegExpFlags();
488 // Scans the input as a template literal
489 Token::Value ScanTemplateStart();
490 Token::Value ScanTemplateContinuation();
492 const LiteralBuffer* source_url() const { return &source_url_; }
493 const LiteralBuffer* source_mapping_url() const {
494 return &source_mapping_url_;
497 bool IdentifierIsFutureStrictReserved(const AstRawString* string) const;
500 // The current and look-ahead token.
504 LiteralBuffer* literal_chars;
505 LiteralBuffer* raw_literal_chars;
508 static const int kCharacterLookaheadBufferSize = 1;
510 // Scans octal escape sequence. Also accepts "\0" decimal escape sequence.
511 template <bool capture_raw>
512 uc32 ScanOctalEscape(uc32 c, int length);
514 // Call this after setting source_ to the input.
516 // Set c0_ (one character ahead)
517 STATIC_ASSERT(kCharacterLookaheadBufferSize == 1);
519 // Initialize current_ to not refer to a literal.
520 current_.literal_chars = NULL;
521 current_.raw_literal_chars = NULL;
524 // Literal buffer support
525 inline void StartLiteral() {
526 LiteralBuffer* free_buffer = (current_.literal_chars == &literal_buffer1_) ?
527 &literal_buffer2_ : &literal_buffer1_;
528 free_buffer->Reset();
529 next_.literal_chars = free_buffer;
532 inline void StartRawLiteral() {
533 raw_literal_buffer_.Reset();
534 next_.raw_literal_chars = &raw_literal_buffer_;
537 INLINE(void AddLiteralChar(uc32 c)) {
538 DCHECK_NOT_NULL(next_.literal_chars);
539 next_.literal_chars->AddChar(c);
542 INLINE(void AddRawLiteralChar(uc32 c)) {
543 DCHECK_NOT_NULL(next_.raw_literal_chars);
544 next_.raw_literal_chars->AddChar(c);
547 INLINE(void ReduceRawLiteralLength(int delta)) {
548 DCHECK_NOT_NULL(next_.raw_literal_chars);
549 next_.raw_literal_chars->ReduceLength(delta);
552 // Stops scanning of a literal and drop the collected characters,
553 // e.g., due to an encountered error.
554 inline void DropLiteral() {
555 next_.literal_chars = NULL;
556 next_.raw_literal_chars = NULL;
559 inline void AddLiteralCharAdvance() {
564 // Low-level scanning support.
565 template <bool capture_raw = false>
568 AddRawLiteralChar(c0_);
570 c0_ = source_->Advance();
571 if (unibrow::Utf16::IsLeadSurrogate(c0_)) {
572 uc32 c1 = source_->Advance();
573 if (!unibrow::Utf16::IsTrailSurrogate(c1)) {
574 source_->PushBack(c1);
576 c0_ = unibrow::Utf16::CombineSurrogatePair(c0_, c1);
581 void PushBack(uc32 ch) {
582 if (ch > static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
583 source_->PushBack(unibrow::Utf16::TrailSurrogate(c0_));
584 source_->PushBack(unibrow::Utf16::LeadSurrogate(c0_));
586 source_->PushBack(c0_);
591 inline Token::Value Select(Token::Value tok) {
596 inline Token::Value Select(uc32 next, Token::Value then, Token::Value else_) {
606 // Returns the literal string, if any, for the current token (the
607 // token last returned by Next()). The string is 0-terminated.
608 // Literal strings are collected for identifiers, strings, numbers as well
609 // as for template literals. For template literals we also collect the raw
611 // These functions only give the correct result if the literal was scanned
612 // when a LiteralScope object is alive.
613 Vector<const uint8_t> literal_one_byte_string() {
614 DCHECK_NOT_NULL(current_.literal_chars);
615 return current_.literal_chars->one_byte_literal();
617 Vector<const uint16_t> literal_two_byte_string() {
618 DCHECK_NOT_NULL(current_.literal_chars);
619 return current_.literal_chars->two_byte_literal();
621 bool is_literal_one_byte() {
622 DCHECK_NOT_NULL(current_.literal_chars);
623 return current_.literal_chars->is_one_byte();
625 int literal_length() const {
626 DCHECK_NOT_NULL(current_.literal_chars);
627 return current_.literal_chars->length();
629 // Returns the literal string for the next token (the token that
630 // would be returned if Next() were called).
631 Vector<const uint8_t> next_literal_one_byte_string() {
632 DCHECK_NOT_NULL(next_.literal_chars);
633 return next_.literal_chars->one_byte_literal();
635 Vector<const uint16_t> next_literal_two_byte_string() {
636 DCHECK_NOT_NULL(next_.literal_chars);
637 return next_.literal_chars->two_byte_literal();
639 bool is_next_literal_one_byte() {
640 DCHECK_NOT_NULL(next_.literal_chars);
641 return next_.literal_chars->is_one_byte();
643 Vector<const uint8_t> raw_literal_one_byte_string() {
644 DCHECK_NOT_NULL(current_.raw_literal_chars);
645 return current_.raw_literal_chars->one_byte_literal();
647 Vector<const uint16_t> raw_literal_two_byte_string() {
648 DCHECK_NOT_NULL(current_.raw_literal_chars);
649 return current_.raw_literal_chars->two_byte_literal();
651 bool is_raw_literal_one_byte() {
652 DCHECK_NOT_NULL(current_.raw_literal_chars);
653 return current_.raw_literal_chars->is_one_byte();
656 template <bool capture_raw>
657 uc32 ScanHexNumber(int expected_length);
658 // Scan a number of any length but not bigger than max_value. For example, the
659 // number can be 000000001, so it's very long in characters but its value is
661 template <bool capture_raw>
662 uc32 ScanUnlimitedLengthHexNumber(int max_value);
664 // Scans a single JavaScript token.
667 bool SkipWhiteSpace();
668 Token::Value SkipSingleLineComment();
669 Token::Value SkipSourceURLComment();
670 void TryToParseSourceURLComment();
671 Token::Value SkipMultiLineComment();
672 // Scans a possible HTML comment -- begins with '<!'.
673 Token::Value ScanHtmlComment();
675 void ScanDecimalDigits();
676 Token::Value ScanNumber(bool seen_period);
677 Token::Value ScanIdentifierOrKeyword();
678 Token::Value ScanIdentifierSuffix(LiteralScope* literal);
680 Token::Value ScanString();
682 // Scans an escape-sequence which is part of a string and adds the
683 // decoded character to the current literal. Returns true if a pattern
685 template <bool capture_raw, bool in_template_literal>
688 // Decodes a Unicode escape-sequence which is part of an identifier.
689 // If the escape sequence cannot be decoded the result is kBadChar.
690 uc32 ScanIdentifierUnicodeEscape();
691 // Helper for the above functions.
692 template <bool capture_raw>
693 uc32 ScanUnicodeEscape();
695 Token::Value ScanTemplateSpan();
697 // Return the current source position.
699 return static_cast<int>(source_->pos()) - kCharacterLookaheadBufferSize;
702 UnicodeCache* unicode_cache_;
704 // Buffers collecting literal strings, numbers, etc.
705 LiteralBuffer literal_buffer1_;
706 LiteralBuffer literal_buffer2_;
708 // Values parsed from magic comments.
709 LiteralBuffer source_url_;
710 LiteralBuffer source_mapping_url_;
712 // Buffer to store raw string values
713 LiteralBuffer raw_literal_buffer_;
715 TokenDesc current_; // desc for current token (as returned by Next())
716 TokenDesc next_; // desc for next token (one token look-ahead)
718 // Input stream. Must be initialized to an Utf16CharacterStream.
719 Utf16CharacterStream* source_;
722 // Start position of the octal literal last scanned.
725 // One Unicode character look-ahead; c0_ < 0 at the end of the input.
728 // Whether there is a line terminator whitespace character after
729 // the current token, and before the next. Does not count newlines
730 // inside multiline comments.
731 bool has_line_terminator_before_next_;
732 // Whether there is a multi-line comment that contains a
733 // line-terminator after the current token, and before the next.
734 bool has_multiline_comment_before_next_;
735 // Whether we scan 'let' as a keyword for harmony block-scoped let bindings.
736 bool harmony_scoping_;
737 // Whether we scan 'module', 'import', 'export' as keywords.
738 bool harmony_modules_;
739 // Whether we scan 0o777 and 0b111 as numbers.
740 bool harmony_numeric_literals_;
741 // Whether we scan 'class', 'extends', 'static' and 'super' as keywords.
742 bool harmony_classes_;
743 // Whether we scan TEMPLATE_SPAN and TEMPLATE_TAIL
744 bool harmony_templates_;
745 // Whether we allow \u{xxxxx}.
746 bool harmony_unicode_;
749 } } // namespace v8::internal
751 #endif // V8_SCANNER_H_