Line data Source code
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 : #include "src/parsing/scanner.h"
8 :
9 : #include <stdint.h>
10 :
11 : #include <cmath>
12 :
13 : #include "src/ast/ast-value-factory.h"
14 : #include "src/char-predicates-inl.h"
15 : #include "src/conversions-inl.h"
16 : #include "src/parsing/duplicate-finder.h" // For Scanner::FindSymbol
17 : #include "src/unicode-cache-inl.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : class Scanner::ErrorState {
23 : public:
24 : ErrorState(MessageTemplate::Template* message_stack,
25 : Scanner::Location* location_stack)
26 : : message_stack_(message_stack),
27 : old_message_(*message_stack),
28 : location_stack_(location_stack),
29 275542 : old_location_(*location_stack) {
30 275542 : *message_stack_ = MessageTemplate::kNone;
31 275542 : *location_stack_ = Location::invalid();
32 : }
33 :
34 : ~ErrorState() {
35 275542 : *message_stack_ = old_message_;
36 275542 : *location_stack_ = old_location_;
37 : }
38 :
39 : void MoveErrorTo(TokenDesc* dest) {
40 49982 : if (*message_stack_ == MessageTemplate::kNone) {
41 : return;
42 : }
43 23142 : if (dest->invalid_template_escape_message == MessageTemplate::kNone) {
44 23142 : dest->invalid_template_escape_message = *message_stack_;
45 23142 : dest->invalid_template_escape_location = *location_stack_;
46 : }
47 23142 : *message_stack_ = MessageTemplate::kNone;
48 23142 : *location_stack_ = Location::invalid();
49 : }
50 :
51 : private:
52 : MessageTemplate::Template* const message_stack_;
53 : MessageTemplate::Template const old_message_;
54 : Scanner::Location* const location_stack_;
55 : Scanner::Location const old_location_;
56 : };
57 :
58 : // ----------------------------------------------------------------------------
59 : // Scanner::LiteralBuffer
60 :
61 2780 : Handle<String> Scanner::LiteralBuffer::Internalize(Isolate* isolate) const {
62 2780 : if (is_one_byte()) {
63 2780 : return isolate->factory()->InternalizeOneByteString(one_byte_literal());
64 : }
65 0 : return isolate->factory()->InternalizeTwoByteString(two_byte_literal());
66 : }
67 :
68 0 : int Scanner::LiteralBuffer::NewCapacity(int min_capacity) {
69 3331746 : int capacity = Max(min_capacity, backing_store_.length());
70 3331758 : int new_capacity = Min(capacity * kGrowthFactory, capacity + kMaxGrowth);
71 0 : return new_capacity;
72 : }
73 :
74 3331746 : void Scanner::LiteralBuffer::ExpandBuffer() {
75 : Vector<byte> new_store = Vector<byte>::New(NewCapacity(kInitialCapacity));
76 3331750 : MemCopy(new_store.start(), backing_store_.start(), position_);
77 : backing_store_.Dispose();
78 3331750 : backing_store_ = new_store;
79 3331750 : }
80 :
81 51693 : void Scanner::LiteralBuffer::ConvertToTwoByte() {
82 : DCHECK(is_one_byte_);
83 : Vector<byte> new_store;
84 51693 : int new_content_size = position_ * kUC16Size;
85 206772 : if (new_content_size >= backing_store_.length()) {
86 : // Ensure room for all currently read code units as UC16 as well
87 : // as the code unit about to be stored.
88 : new_store = Vector<byte>::New(NewCapacity(new_content_size));
89 : } else {
90 51681 : new_store = backing_store_;
91 : }
92 : uint8_t* src = backing_store_.start();
93 : uint16_t* dst = reinterpret_cast<uint16_t*>(new_store.start());
94 104302 : for (int i = position_ - 1; i >= 0; i--) {
95 52609 : dst[i] = src[i];
96 : }
97 51693 : if (new_store.start() != backing_store_.start()) {
98 : backing_store_.Dispose();
99 12 : backing_store_ = new_store;
100 : }
101 51693 : position_ = new_content_size;
102 51693 : is_one_byte_ = false;
103 51693 : }
104 :
105 986841 : void Scanner::LiteralBuffer::AddCharSlow(uc32 code_unit) {
106 2975447 : if (position_ >= backing_store_.length()) ExpandBuffer();
107 986841 : if (is_one_byte_) {
108 51693 : if (code_unit <= static_cast<uc32>(unibrow::Latin1::kMaxChar)) {
109 0 : backing_store_[position_] = static_cast<byte>(code_unit);
110 0 : position_ += kOneByteSize;
111 986841 : return;
112 : }
113 51693 : ConvertToTwoByte();
114 : }
115 986841 : if (code_unit <=
116 : static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
117 1958758 : *reinterpret_cast<uint16_t*>(&backing_store_[position_]) = code_unit;
118 979379 : position_ += kUC16Size;
119 : } else {
120 7462 : *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
121 14924 : unibrow::Utf16::LeadSurrogate(code_unit);
122 7462 : position_ += kUC16Size;
123 7462 : if (position_ >= backing_store_.length()) ExpandBuffer();
124 7462 : *reinterpret_cast<uint16_t*>(&backing_store_[position_]) =
125 7462 : unibrow::Utf16::TrailSurrogate(code_unit);
126 7462 : position_ += kUC16Size;
127 : }
128 : }
129 :
130 : // ----------------------------------------------------------------------------
131 : // Scanner::BookmarkScope
132 :
133 : const size_t Scanner::BookmarkScope::kBookmarkAtFirstPos =
134 : std::numeric_limits<size_t>::max() - 2;
135 : const size_t Scanner::BookmarkScope::kNoBookmark =
136 : std::numeric_limits<size_t>::max() - 1;
137 : const size_t Scanner::BookmarkScope::kBookmarkWasApplied =
138 : std::numeric_limits<size_t>::max();
139 :
140 2245915 : void Scanner::BookmarkScope::Set() {
141 : DCHECK_EQ(bookmark_, kNoBookmark);
142 : DCHECK_EQ(scanner_->next_next_.token, Token::UNINITIALIZED);
143 :
144 : // The first token is a bit special, since current_ will still be
145 : // uninitialized. In this case, store kBookmarkAtFirstPos and special-case it
146 : // when
147 : // applying the bookmark.
148 : DCHECK_IMPLIES(
149 : scanner_->current_.token == Token::UNINITIALIZED,
150 : scanner_->current_.location.beg_pos == scanner_->next_.location.beg_pos);
151 2245915 : bookmark_ = (scanner_->current_.token == Token::UNINITIALIZED)
152 : ? kBookmarkAtFirstPos
153 2245915 : : scanner_->location().beg_pos;
154 2245915 : }
155 :
156 157 : void Scanner::BookmarkScope::Apply() {
157 : DCHECK(HasBeenSet()); // Caller hasn't called SetBookmark.
158 157 : if (bookmark_ == kBookmarkAtFirstPos) {
159 6 : scanner_->SeekNext(0);
160 : } else {
161 151 : scanner_->SeekNext(bookmark_);
162 151 : scanner_->Next();
163 : DCHECK_EQ(scanner_->location().beg_pos, static_cast<int>(bookmark_));
164 : }
165 157 : bookmark_ = kBookmarkWasApplied;
166 157 : }
167 :
168 0 : bool Scanner::BookmarkScope::HasBeenSet() {
169 0 : return bookmark_ != kNoBookmark && bookmark_ != kBookmarkWasApplied;
170 : }
171 :
172 0 : bool Scanner::BookmarkScope::HasBeenApplied() {
173 0 : return bookmark_ == kBookmarkWasApplied;
174 : }
175 :
176 : // LineTerminator: 'JS_Line_Terminator' in point.properties
177 : // ES#sec-line-terminators lists exactly 4 code points:
178 : // LF (U+000A), CR (U+000D), LS(U+2028), PS(U+2029)
179 0 : bool Scanner::IsLineTerminator(uc32 c) {
180 343813909 : if (c == 0x000A || c == 0x000D) {
181 : return true;
182 : }
183 337684875 : if (c == 0x2028 || c == 0x2029) {
184 : ++use_counts_[v8::Isolate::UseCounterFeature::
185 116 : kLineOrParagraphSeparatorAsLineTerminator];
186 0 : return true;
187 : }
188 : return false;
189 : }
190 :
191 : // ----------------------------------------------------------------------------
192 : // Scanner
193 :
194 2786057 : Scanner::Scanner(UnicodeCache* unicode_cache, int* use_counts)
195 : : unicode_cache_(unicode_cache),
196 : octal_pos_(Location::invalid()),
197 : octal_message_(MessageTemplate::kNone),
198 : found_html_comment_(false),
199 : allow_harmony_bigint_(false),
200 8358171 : use_counts_(use_counts) {}
201 :
202 2786055 : void Scanner::Initialize(Utf16CharacterStream* source, bool is_module) {
203 : DCHECK_NOT_NULL(source);
204 2786055 : source_ = source;
205 2786055 : is_module_ = is_module;
206 : // Need to capture identifiers in order to recognize "get" and "set"
207 : // in object literals.
208 2786055 : Init();
209 2786055 : has_line_terminator_before_next_ = true;
210 2786055 : Scan();
211 2786054 : }
212 :
213 : template <bool capture_raw, bool unicode>
214 18132107 : uc32 Scanner::ScanHexNumber(int expected_length) {
215 : DCHECK_LE(expected_length, 4); // prevent overflow
216 :
217 18132107 : int begin = source_pos() - 2;
218 : uc32 x = 0;
219 54464327 : for (int i = 0; i < expected_length; i++) {
220 36343656 : int d = HexValue(c0_);
221 36343656 : if (d < 0) {
222 : ReportScannerError(Location(begin, begin + expected_length + 2),
223 : unicode
224 : ? MessageTemplate::kInvalidUnicodeEscapeSequence
225 11436 : : MessageTemplate::kInvalidHexEscapeSequence);
226 : return -1;
227 : }
228 36332220 : x = x * 16 + d;
229 36332220 : Advance<capture_raw>();
230 : }
231 :
232 : return x;
233 : }
234 :
235 : template <bool capture_raw>
236 39536 : uc32 Scanner::ScanUnlimitedLengthHexNumber(int max_value, int beg_pos) {
237 : uc32 x = 0;
238 37256 : int d = HexValue(c0_);
239 37256 : if (d < 0) return -1;
240 :
241 150690 : while (d >= 0) {
242 121514 : x = x * 16 + d;
243 121514 : if (x > max_value) {
244 : ReportScannerError(Location(beg_pos, source_pos() + 1),
245 : MessageTemplate::kUndefinedUnicodeCodePoint);
246 : return -1;
247 : }
248 119234 : Advance<capture_raw>();
249 119234 : d = HexValue(c0_);
250 : }
251 :
252 : return x;
253 : }
254 :
255 :
256 : // Ensure that tokens can be stored in a byte.
257 : STATIC_ASSERT(Token::NUM_TOKENS <= 0x100);
258 :
259 : // Table of one-character tokens, by character (0x00..0x7f only).
260 : static const byte one_char_tokens[] = {
261 : Token::ILLEGAL,
262 : Token::ILLEGAL,
263 : Token::ILLEGAL,
264 : Token::ILLEGAL,
265 : Token::ILLEGAL,
266 : Token::ILLEGAL,
267 : Token::ILLEGAL,
268 : Token::ILLEGAL,
269 : Token::ILLEGAL,
270 : Token::ILLEGAL,
271 : Token::ILLEGAL,
272 : Token::ILLEGAL,
273 : Token::ILLEGAL,
274 : Token::ILLEGAL,
275 : Token::ILLEGAL,
276 : Token::ILLEGAL,
277 : Token::ILLEGAL,
278 : Token::ILLEGAL,
279 : Token::ILLEGAL,
280 : Token::ILLEGAL,
281 : Token::ILLEGAL,
282 : Token::ILLEGAL,
283 : Token::ILLEGAL,
284 : Token::ILLEGAL,
285 : Token::ILLEGAL,
286 : Token::ILLEGAL,
287 : Token::ILLEGAL,
288 : Token::ILLEGAL,
289 : Token::ILLEGAL,
290 : Token::ILLEGAL,
291 : Token::ILLEGAL,
292 : Token::ILLEGAL,
293 : Token::ILLEGAL,
294 : Token::ILLEGAL,
295 : Token::ILLEGAL,
296 : Token::ILLEGAL,
297 : Token::ILLEGAL,
298 : Token::ILLEGAL,
299 : Token::ILLEGAL,
300 : Token::ILLEGAL,
301 : Token::LPAREN, // 0x28
302 : Token::RPAREN, // 0x29
303 : Token::ILLEGAL,
304 : Token::ILLEGAL,
305 : Token::COMMA, // 0x2c
306 : Token::ILLEGAL,
307 : Token::ILLEGAL,
308 : Token::ILLEGAL,
309 : Token::ILLEGAL,
310 : Token::ILLEGAL,
311 : Token::ILLEGAL,
312 : Token::ILLEGAL,
313 : Token::ILLEGAL,
314 : Token::ILLEGAL,
315 : Token::ILLEGAL,
316 : Token::ILLEGAL,
317 : Token::ILLEGAL,
318 : Token::ILLEGAL,
319 : Token::COLON, // 0x3a
320 : Token::SEMICOLON, // 0x3b
321 : Token::ILLEGAL,
322 : Token::ILLEGAL,
323 : Token::ILLEGAL,
324 : Token::CONDITIONAL, // 0x3f
325 : Token::ILLEGAL,
326 : Token::ILLEGAL,
327 : Token::ILLEGAL,
328 : Token::ILLEGAL,
329 : Token::ILLEGAL,
330 : Token::ILLEGAL,
331 : Token::ILLEGAL,
332 : Token::ILLEGAL,
333 : Token::ILLEGAL,
334 : Token::ILLEGAL,
335 : Token::ILLEGAL,
336 : Token::ILLEGAL,
337 : Token::ILLEGAL,
338 : Token::ILLEGAL,
339 : Token::ILLEGAL,
340 : Token::ILLEGAL,
341 : Token::ILLEGAL,
342 : Token::ILLEGAL,
343 : Token::ILLEGAL,
344 : Token::ILLEGAL,
345 : Token::ILLEGAL,
346 : Token::ILLEGAL,
347 : Token::ILLEGAL,
348 : Token::ILLEGAL,
349 : Token::ILLEGAL,
350 : Token::ILLEGAL,
351 : Token::ILLEGAL,
352 : Token::LBRACK, // 0x5b
353 : Token::ILLEGAL,
354 : Token::RBRACK, // 0x5d
355 : Token::ILLEGAL,
356 : Token::ILLEGAL,
357 : Token::ILLEGAL,
358 : Token::ILLEGAL,
359 : Token::ILLEGAL,
360 : Token::ILLEGAL,
361 : Token::ILLEGAL,
362 : Token::ILLEGAL,
363 : Token::ILLEGAL,
364 : Token::ILLEGAL,
365 : Token::ILLEGAL,
366 : Token::ILLEGAL,
367 : Token::ILLEGAL,
368 : Token::ILLEGAL,
369 : Token::ILLEGAL,
370 : Token::ILLEGAL,
371 : Token::ILLEGAL,
372 : Token::ILLEGAL,
373 : Token::ILLEGAL,
374 : Token::ILLEGAL,
375 : Token::ILLEGAL,
376 : Token::ILLEGAL,
377 : Token::ILLEGAL,
378 : Token::ILLEGAL,
379 : Token::ILLEGAL,
380 : Token::ILLEGAL,
381 : Token::ILLEGAL,
382 : Token::ILLEGAL,
383 : Token::ILLEGAL,
384 : Token::LBRACE, // 0x7b
385 : Token::ILLEGAL,
386 : Token::RBRACE, // 0x7d
387 : Token::BIT_NOT, // 0x7e
388 : Token::ILLEGAL
389 : };
390 :
391 :
392 634541110 : Token::Value Scanner::Next() {
393 493550321 : if (next_.token == Token::EOS) {
394 2865 : next_.location.beg_pos = current_.location.beg_pos;
395 2865 : next_.location.end_pos = current_.location.end_pos;
396 : }
397 493550321 : current_ = next_;
398 493550321 : if (V8_UNLIKELY(next_next_.token != Token::UNINITIALIZED)) {
399 86271368 : next_ = next_next_;
400 86271368 : next_next_.token = Token::UNINITIALIZED;
401 86271368 : next_next_.contextual_token = Token::UNINITIALIZED;
402 86271368 : has_line_terminator_before_next_ = has_line_terminator_after_next_;
403 86271368 : return current_.token;
404 : }
405 407278953 : has_line_terminator_before_next_ = false;
406 407278953 : has_multiline_comment_before_next_ = false;
407 407278953 : if (static_cast<unsigned>(c0_) <= 0x7f) {
408 405119359 : Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]);
409 405119359 : if (token != Token::ILLEGAL) {
410 : int pos = source_pos();
411 140990789 : next_.token = token;
412 140990789 : next_.contextual_token = Token::UNINITIALIZED;
413 140990789 : next_.location.beg_pos = pos;
414 140990789 : next_.location.end_pos = pos + 1;
415 140990789 : next_.literal_chars = nullptr;
416 140990789 : next_.raw_literal_chars = nullptr;
417 140990789 : next_.invalid_template_escape_message = MessageTemplate::kNone;
418 140990789 : Advance();
419 140990824 : return current_.token;
420 : }
421 : }
422 266288164 : Scan();
423 266289648 : return current_.token;
424 : }
425 :
426 :
427 86564020 : Token::Value Scanner::PeekAhead() {
428 : DCHECK(next_.token != Token::DIV);
429 : DCHECK(next_.token != Token::ASSIGN_DIV);
430 :
431 86564020 : if (next_next_.token != Token::UNINITIALIZED) {
432 : return next_next_.token;
433 : }
434 86272960 : TokenDesc prev = current_;
435 : bool has_line_terminator_before_next =
436 86272960 : has_line_terminator_before_next_ || has_multiline_comment_before_next_;
437 86272960 : Next();
438 : has_line_terminator_after_next_ =
439 86272989 : has_line_terminator_before_next_ || has_multiline_comment_before_next_;
440 86272989 : has_line_terminator_before_next_ = has_line_terminator_before_next;
441 86272989 : Token::Value ret = next_.token;
442 86272989 : next_next_ = next_;
443 86272989 : next_ = current_;
444 86272989 : current_ = prev;
445 86272989 : return ret;
446 : }
447 :
448 :
449 7444 : Token::Value Scanner::SkipWhiteSpace() {
450 : int start_position = source_pos();
451 :
452 : while (true) {
453 : while (true) {
454 : // Don't skip behind the end of input.
455 17155 : if (c0_ == kEndOfInput) break;
456 :
457 : // Advance as long as character is a WhiteSpace or LineTerminator.
458 : // Remember if the latter is the case.
459 16881 : if (IsLineTerminator(c0_)) {
460 3088 : has_line_terminator_before_next_ = true;
461 27586 : } else if (!unicode_cache_->IsWhiteSpace(c0_)) {
462 : break;
463 : }
464 13433 : Advance();
465 : }
466 :
467 : // If there is an HTML comment end '-->' at the beginning of a
468 : // line (with only whitespace in front of it), we treat the rest
469 : // of the line as a comment. This is in line with the way
470 : // SpiderMonkey handles it.
471 3722 : if (c0_ != '-' || !has_line_terminator_before_next_) break;
472 :
473 0 : Advance();
474 0 : if (c0_ != '-') {
475 : PushBack('-'); // undo Advance()
476 : break;
477 : }
478 :
479 0 : Advance();
480 0 : if (c0_ != '>') {
481 : PushBack2('-', '-'); // undo 2x Advance();
482 : break;
483 : }
484 :
485 : // Treat the rest of the line as a comment.
486 0 : Token::Value token = SkipSingleHTMLComment();
487 0 : if (token == Token::ILLEGAL) {
488 : return token;
489 : }
490 13433 : }
491 :
492 : // Return whether or not we skipped any characters.
493 3722 : if (source_pos() == start_position) {
494 : return Token::ILLEGAL;
495 : }
496 :
497 3502 : return Token::WHITESPACE;
498 : }
499 :
500 197 : Token::Value Scanner::SkipSingleHTMLComment() {
501 192 : if (is_module_) {
502 : ReportScannerError(source_pos(), MessageTemplate::kHtmlCommentInModule);
503 : return Token::ILLEGAL;
504 : }
505 187 : return SkipSingleLineComment();
506 : }
507 :
508 5328985 : Token::Value Scanner::SkipSingleLineComment() {
509 5328985 : Advance();
510 :
511 : // The line terminator at the end of the line is not considered
512 : // to be part of the single-line comment; it is recognized
513 : // separately by the lexical grammar and becomes part of the
514 : // stream of input elements for the syntactic grammar (see
515 : // ECMA-262, section 7.4).
516 550934367 : while (c0_ != kEndOfInput && !IsLineTerminator(c0_)) {
517 267473937 : Advance();
518 : }
519 :
520 5328985 : return Token::WHITESPACE;
521 : }
522 :
523 :
524 2881 : Token::Value Scanner::SkipSourceURLComment() {
525 2881 : TryToParseSourceURLComment();
526 7317 : while (c0_ != kEndOfInput && !IsLineTerminator(c0_)) {
527 624 : Advance();
528 : }
529 :
530 2881 : return Token::WHITESPACE;
531 : }
532 :
533 :
534 2881 : void Scanner::TryToParseSourceURLComment() {
535 : // Magic comments are of the form: //[#@]\s<name>=\s*<value>\s*.* and this
536 : // function will just return if it cannot parse a magic comment.
537 5823 : if (c0_ == kEndOfInput || !unicode_cache_->IsWhiteSpace(c0_)) return;
538 2871 : Advance();
539 : LiteralBuffer name;
540 88590 : while (c0_ != kEndOfInput &&
541 59040 : !unicode_cache_->IsWhiteSpaceOrLineTerminator(c0_) && c0_ != '=') {
542 26659 : name.AddChar(c0_);
543 26659 : Advance();
544 : }
545 2871 : if (!name.is_one_byte()) return;
546 : Vector<const uint8_t> name_literal = name.one_byte_literal();
547 : LiteralBuffer* value;
548 2871 : if (name_literal == STATIC_CHAR_VECTOR("sourceURL")) {
549 2710 : value = &source_url_;
550 161 : } else if (name_literal == STATIC_CHAR_VECTOR("sourceMappingURL")) {
551 130 : value = &source_mapping_url_;
552 : } else {
553 : return;
554 : }
555 2840 : if (c0_ != '=')
556 : return;
557 2830 : Advance();
558 : value->Reset();
559 5700 : while (c0_ != kEndOfInput && unicode_cache_->IsWhiteSpace(c0_)) {
560 20 : Advance();
561 : }
562 61931 : while (c0_ != kEndOfInput && !IsLineTerminator(c0_)) {
563 : // Disallowed characters.
564 29462 : if (c0_ == '"' || c0_ == '\'') {
565 : value->Reset();
566 : return;
567 : }
568 58884 : if (unicode_cache_->IsWhiteSpace(c0_)) {
569 : break;
570 : }
571 29402 : value->AddChar(c0_);
572 29402 : Advance();
573 : }
574 : // Allow whitespace at the end.
575 3177 : while (c0_ != kEndOfInput && !IsLineTerminator(c0_)) {
576 140 : if (!unicode_cache_->IsWhiteSpace(c0_)) {
577 : value->Reset();
578 : break;
579 : }
580 50 : Advance();
581 : }
582 : }
583 :
584 :
585 428620 : Token::Value Scanner::SkipMultiLineComment() {
586 : DCHECK_EQ(c0_, '*');
587 428620 : Advance();
588 :
589 28992364 : while (c0_ != kEndOfInput) {
590 : uc32 ch = c0_;
591 28563742 : Advance();
592 57127482 : if (c0_ != kEndOfInput && IsLineTerminator(ch)) {
593 : // Following ECMA-262, section 7.4, a comment containing
594 : // a newline will make the comment count as a line-terminator.
595 785645 : has_multiline_comment_before_next_ = true;
596 : }
597 : // If we have reached the end of the multi-line comment, we
598 : // consume the '/' and insert a whitespace. This way all
599 : // multi-line comments are treated as whitespace.
600 28563742 : if (ch == '*' && c0_ == '/') {
601 428618 : c0_ = ' ';
602 428618 : return Token::WHITESPACE;
603 : }
604 : }
605 :
606 : // Unterminated multi-line comment.
607 : return Token::ILLEGAL;
608 : }
609 :
610 111 : Token::Value Scanner::ScanHtmlComment() {
611 : // Check for <!-- comments.
612 : DCHECK_EQ(c0_, '!');
613 75 : Advance();
614 75 : if (c0_ != '-') {
615 : PushBack('!'); // undo Advance()
616 : return Token::LT;
617 : }
618 :
619 57 : Advance();
620 57 : if (c0_ != '-') {
621 : PushBack2('-', '!'); // undo 2x Advance()
622 18 : return Token::LT;
623 : }
624 :
625 39 : found_html_comment_ = true;
626 39 : return SkipSingleHTMLComment();
627 : }
628 :
629 1129083520 : void Scanner::Scan() {
630 269112928 : next_.literal_chars = nullptr;
631 269112928 : next_.raw_literal_chars = nullptr;
632 269112928 : next_.invalid_template_escape_message = MessageTemplate::kNone;
633 : Token::Value token;
634 585527940 : do {
635 : // Remember the position of the next token
636 585529686 : next_.location.beg_pos = source_pos();
637 :
638 585529686 : switch (c0_) {
639 : case ' ':
640 : case '\t':
641 250630691 : Advance();
642 : token = Token::WHITESPACE;
643 250630697 : break;
644 :
645 : case '\n':
646 60022304 : Advance();
647 60022302 : has_line_terminator_before_next_ = true;
648 : token = Token::WHITESPACE;
649 60022302 : break;
650 :
651 : case '"':
652 : case '\'':
653 10890649 : token = ScanString();
654 10890648 : break;
655 :
656 : case '<':
657 : // < <= << <<= <!--
658 1246241 : Advance();
659 1246241 : if (c0_ == '=') {
660 : token = Select(Token::LTE);
661 1149980 : } else if (c0_ == '<') {
662 : token = Select('=', Token::ASSIGN_SHL, Token::SHL);
663 805257 : } else if (c0_ == '!') {
664 75 : token = ScanHtmlComment();
665 : } else {
666 : token = Token::LT;
667 : }
668 : break;
669 :
670 : case '>':
671 : // > >= >> >>= >>> >>>=
672 690396 : Advance();
673 690396 : if (c0_ == '=') {
674 : token = Select(Token::GTE);
675 573459 : } else if (c0_ == '>') {
676 : // >> >>= >>> >>>=
677 305764 : Advance();
678 305764 : if (c0_ == '=') {
679 : token = Select(Token::ASSIGN_SAR);
680 300260 : } else if (c0_ == '>') {
681 : token = Select('=', Token::ASSIGN_SHR, Token::SHR);
682 : } else {
683 : token = Token::SAR;
684 : }
685 : } else {
686 : token = Token::GT;
687 : }
688 : break;
689 :
690 : case '=':
691 : // = == === =>
692 23348296 : Advance();
693 23348296 : if (c0_ == '=') {
694 : token = Select('=', Token::EQ_STRICT, Token::EQ);
695 21184024 : } else if (c0_ == '>') {
696 : token = Select(Token::ARROW);
697 : } else {
698 : token = Token::ASSIGN;
699 : }
700 : break;
701 :
702 : case '!':
703 : // ! != !==
704 1966575 : Advance();
705 1966575 : if (c0_ == '=') {
706 : token = Select('=', Token::NE_STRICT, Token::NE);
707 : } else {
708 : token = Token::NOT;
709 : }
710 : break;
711 :
712 : case '+':
713 : // + ++ +=
714 5530921 : Advance();
715 5530922 : if (c0_ == '+') {
716 : token = Select(Token::INC);
717 4276305 : } else if (c0_ == '=') {
718 : token = Select(Token::ASSIGN_ADD);
719 : } else {
720 : token = Token::ADD;
721 : }
722 : break;
723 :
724 : case '-':
725 : // - -- --> -=
726 1017807 : Advance();
727 1017807 : if (c0_ == '-') {
728 102203 : Advance();
729 102409 : if (c0_ == '>' && HasAnyLineTerminatorBeforeNext()) {
730 : // For compatibility with SpiderMonkey, we skip lines that
731 : // start with an HTML comment end '-->'.
732 153 : token = SkipSingleHTMLComment();
733 : } else {
734 : token = Token::DEC;
735 : }
736 915604 : } else if (c0_ == '=') {
737 : token = Select(Token::ASSIGN_SUB);
738 : } else {
739 : token = Token::SUB;
740 : }
741 : break;
742 :
743 : case '*':
744 : // * *=
745 528397 : Advance();
746 528397 : if (c0_ == '*') {
747 : token = Select('=', Token::ASSIGN_EXP, Token::EXP);
748 520689 : } else if (c0_ == '=') {
749 : token = Select(Token::ASSIGN_MUL);
750 : } else {
751 : token = Token::MUL;
752 : }
753 : break;
754 :
755 : case '%':
756 : // % %=
757 : token = Select('=', Token::ASSIGN_MOD, Token::MOD);
758 1224374 : break;
759 :
760 : case '/':
761 : // / // /* /=
762 6087037 : Advance();
763 6087037 : if (c0_ == '/') {
764 5331679 : Advance();
765 5331679 : if (c0_ == '#' || c0_ == '@') {
766 2881 : Advance();
767 2881 : token = SkipSourceURLComment();
768 : } else {
769 : PushBack(c0_);
770 5328798 : token = SkipSingleLineComment();
771 : }
772 755358 : } else if (c0_ == '*') {
773 428620 : token = SkipMultiLineComment();
774 326738 : } else if (c0_ == '=') {
775 : token = Select(Token::ASSIGN_DIV);
776 : } else {
777 : token = Token::DIV;
778 : }
779 : break;
780 :
781 : case '&':
782 : // & && &=
783 1189124 : Advance();
784 1189124 : if (c0_ == '&') {
785 : token = Select(Token::AND);
786 595495 : } else if (c0_ == '=') {
787 : token = Select(Token::ASSIGN_BIT_AND);
788 : } else {
789 : token = Token::BIT_AND;
790 : }
791 : break;
792 :
793 : case '|':
794 : // | || |=
795 1038846 : Advance();
796 1038846 : if (c0_ == '|') {
797 : token = Select(Token::OR);
798 423543 : } else if (c0_ == '=') {
799 : token = Select(Token::ASSIGN_BIT_OR);
800 : } else {
801 : token = Token::BIT_OR;
802 : }
803 : break;
804 :
805 : case '^':
806 : // ^ ^=
807 : token = Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);
808 19592 : break;
809 :
810 : case '.':
811 : // . Number
812 17338558 : Advance();
813 34677114 : if (IsDecimalDigit(c0_)) {
814 2993 : token = ScanNumber(true);
815 : } else {
816 : token = Token::PERIOD;
817 17335564 : if (c0_ == '.') {
818 116910 : Advance();
819 116910 : if (c0_ == '.') {
820 116190 : Advance();
821 : token = Token::ELLIPSIS;
822 : } else {
823 : PushBack('.');
824 : }
825 : }
826 : }
827 : break;
828 :
829 : case ':':
830 : token = Select(Token::COLON);
831 1985691 : break;
832 :
833 : case ';':
834 : token = Select(Token::SEMICOLON);
835 47132 : break;
836 :
837 : case ',':
838 : token = Select(Token::COMMA);
839 489491 : break;
840 :
841 : case '(':
842 : token = Select(Token::LPAREN);
843 6553532 : break;
844 :
845 : case ')':
846 : token = Select(Token::RPAREN);
847 396915 : break;
848 :
849 : case '[':
850 : token = Select(Token::LBRACK);
851 673629 : break;
852 :
853 : case ']':
854 : token = Select(Token::RBRACK);
855 132525 : break;
856 :
857 : case '{':
858 : token = Select(Token::LBRACE);
859 8357810 : break;
860 :
861 : case '}':
862 : token = Select(Token::RBRACE);
863 10331664 : break;
864 :
865 : case '?':
866 : token = Select(Token::CONDITIONAL);
867 225986 : break;
868 :
869 : case '~':
870 : token = Select(Token::BIT_NOT);
871 2898 : break;
872 :
873 : case '`':
874 70715 : token = ScanTemplateStart();
875 70715 : break;
876 :
877 : default:
878 173491888 : if (c0_ == kEndOfInput) {
879 : token = Token::EOS;
880 342372018 : } else if (unicode_cache_->IsIdentifierStart(c0_)) {
881 141650187 : token = ScanIdentifierOrKeyword();
882 59071724 : } else if (IsDecimalDigit(c0_)) {
883 29532140 : token = ScanNumber(false);
884 : } else {
885 3722 : token = SkipWhiteSpace();
886 3722 : if (token == Token::ILLEGAL) {
887 220 : Advance();
888 : }
889 : }
890 : break;
891 : }
892 :
893 : // Continue scanning for tokens as long as we're just skipping
894 : // whitespace.
895 : } while (token == Token::WHITESPACE);
896 :
897 269111182 : next_.location.end_pos = source_pos();
898 269111182 : if (Token::IsContextualKeyword(token)) {
899 4314433 : next_.token = Token::IDENTIFIER;
900 4314433 : next_.contextual_token = token;
901 : } else {
902 264796749 : next_.token = token;
903 264796749 : next_.contextual_token = Token::UNINITIALIZED;
904 : }
905 :
906 : #ifdef DEBUG
907 : SanityCheckTokenDesc(current_);
908 : SanityCheckTokenDesc(next_);
909 : SanityCheckTokenDesc(next_next_);
910 : #endif
911 269111182 : }
912 :
913 : #ifdef DEBUG
914 : void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const {
915 : // Most tokens should not have literal_chars or even raw_literal chars.
916 : // The rules are:
917 : // - UNINITIALIZED: we don't care.
918 : // - TEMPLATE_*: need both literal + raw literal chars.
919 : // - IDENTIFIERS, STRINGS, etc.: need a literal, but no raw literal.
920 : // - all others: should have neither.
921 : // Furthermore, only TEMPLATE_* tokens can have a
922 : // invalid_template_escape_message.
923 :
924 : switch (token.token) {
925 : case Token::UNINITIALIZED:
926 : // token.literal_chars & other members might be garbage. That's ok.
927 : break;
928 : case Token::TEMPLATE_SPAN:
929 : case Token::TEMPLATE_TAIL:
930 : DCHECK_NOT_NULL(token.raw_literal_chars);
931 : DCHECK_NOT_NULL(token.literal_chars);
932 : break;
933 : case Token::ESCAPED_KEYWORD:
934 : case Token::ESCAPED_STRICT_RESERVED_WORD:
935 : case Token::FUTURE_STRICT_RESERVED_WORD:
936 : case Token::IDENTIFIER:
937 : case Token::NUMBER:
938 : case Token::BIGINT:
939 : case Token::REGEXP_LITERAL:
940 : case Token::SMI:
941 : case Token::STRING:
942 : DCHECK_NOT_NULL(token.literal_chars);
943 : DCHECK_NULL(token.raw_literal_chars);
944 : DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone);
945 : break;
946 : default:
947 : DCHECK_NULL(token.literal_chars);
948 : DCHECK_NULL(token.raw_literal_chars);
949 : DCHECK_EQ(token.invalid_template_escape_message, MessageTemplate::kNone);
950 : break;
951 : }
952 :
953 : DCHECK_IMPLIES(token.token != Token::IDENTIFIER,
954 : token.contextual_token == Token::UNINITIALIZED);
955 : DCHECK_IMPLIES(token.contextual_token != Token::UNINITIALIZED,
956 : token.token == Token::IDENTIFIER &&
957 : Token::IsContextualKeyword(token.contextual_token));
958 : DCHECK(!Token::IsContextualKeyword(token.token));
959 : }
960 : #endif // DEBUG
961 :
962 70932 : void Scanner::SeekForward(int pos) {
963 : // After this call, we will have the token at the given position as
964 : // the "next" token. The "current" token will be invalid.
965 70942 : if (pos == next_.location.beg_pos) return;
966 : int current_pos = source_pos();
967 : DCHECK_EQ(next_.location.end_pos, current_pos);
968 : // Positions inside the lookahead token aren't supported.
969 : DCHECK(pos >= current_pos);
970 35461 : if (pos != current_pos) {
971 35456 : source_->Seek(pos);
972 35456 : Advance();
973 : // This function is only called to seek to the location
974 : // of the end of a function (at the "}" token). It doesn't matter
975 : // whether there was a line terminator in the part we skip.
976 35456 : has_line_terminator_before_next_ = false;
977 35456 : has_multiline_comment_before_next_ = false;
978 : }
979 35461 : Scan();
980 : }
981 :
982 :
983 : template <bool capture_raw, bool in_template_literal>
984 37724623 : bool Scanner::ScanEscape() {
985 18878359 : uc32 c = c0_;
986 18878359 : Advance<capture_raw>();
987 :
988 : // Skip escaped newlines.
989 37706736 : if (!in_template_literal && c0_ != kEndOfInput && IsLineTerminator(c)) {
990 : // Allow escaped CR+LF newlines in multiline string literals.
991 10999 : if (IsCarriageReturn(c) && IsLineFeed(c0_)) Advance<capture_raw>();
992 : return true;
993 : }
994 :
995 18867360 : switch (c) {
996 : case '\'': // fall through
997 : case '"' : // fall through
998 : case '\\': break;
999 47 : case 'b' : c = '\b'; break;
1000 91 : case 'f' : c = '\f'; break;
1001 585034 : case 'n' : c = '\n'; break;
1002 631 : case 'r' : c = '\r'; break;
1003 322 : case 't' : c = '\t'; break;
1004 : case 'u' : {
1005 68270 : c = ScanUnicodeEscape<capture_raw>();
1006 68270 : if (c < 0) return false;
1007 : break;
1008 : }
1009 : case 'v':
1010 : c = '\v';
1011 43 : break;
1012 : case 'x': {
1013 18085453 : c = ScanHexNumber<capture_raw>(2);
1014 18085453 : if (c < 0) return false;
1015 : break;
1016 : }
1017 : case '0': // Fall through.
1018 : case '1': // fall through
1019 : case '2': // fall through
1020 : case '3': // fall through
1021 : case '4': // fall through
1022 : case '5': // fall through
1023 : case '6': // fall through
1024 : case '7':
1025 5674 : c = ScanOctalEscape<capture_raw>(c, 2);
1026 5674 : break;
1027 : }
1028 :
1029 : // Other escaped characters are interpreted as their non-escaped version.
1030 : AddLiteralChar(c);
1031 : return true;
1032 : }
1033 :
1034 :
1035 : template <bool capture_raw>
1036 11061 : uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
1037 5674 : uc32 x = c - '0';
1038 : int i = 0;
1039 8766 : for (; i < length; i++) {
1040 8178 : int d = c0_ - '0';
1041 8178 : if (d < 0 || d > 7) break;
1042 3110 : int nx = x * 8 + d;
1043 3110 : if (nx >= 256) break;
1044 : x = nx;
1045 3092 : Advance<capture_raw>();
1046 : }
1047 : // Anything except '\0' is an octal escape sequence, illegal in strict mode.
1048 : // Remember the position of octal escape sequences so that an error
1049 : // can be reported later (in strict mode).
1050 : // We don't report the error immediately, because the octal escape can
1051 : // occur before the "use strict" directive.
1052 5674 : if (c != '0' || i > 0 || c0_ == '8' || c0_ == '9') {
1053 5387 : octal_pos_ = Location(source_pos() - i - 1, source_pos() - 1);
1054 5387 : octal_message_ = MessageTemplate::kStrictOctalEscape;
1055 : }
1056 5674 : return x;
1057 : }
1058 :
1059 :
1060 336381459 : Token::Value Scanner::ScanString() {
1061 10890648 : uc32 quote = c0_;
1062 : Advance<false, false>(); // consume quote
1063 :
1064 : LiteralScope literal(this);
1065 : while (true) {
1066 161235859 : if (c0_ > kMaxAscii) {
1067 14021 : HandleLeadSurrogate();
1068 14021 : break;
1069 : }
1070 161221838 : if (c0_ == kEndOfInput || c0_ == '\n' || c0_ == '\r') return Token::ILLEGAL;
1071 161221715 : if (c0_ == quote) {
1072 : literal.Complete();
1073 : Advance<false, false>();
1074 10187677 : return Token::STRING;
1075 : }
1076 151034037 : char c = static_cast<char>(c0_);
1077 151034037 : if (c == '\\') break;
1078 : Advance<false, false>();
1079 : AddLiteralChar(c);
1080 : }
1081 :
1082 45852011 : while (c0_ != quote && c0_ != kEndOfInput && !IsLineTerminator(c0_)) {
1083 22575410 : uc32 c = c0_;
1084 22575410 : Advance();
1085 22575410 : if (c == '\\') {
1086 18853377 : if (c0_ == kEndOfInput || !ScanEscape<false, false>()) {
1087 : return Token::ILLEGAL;
1088 : }
1089 : } else {
1090 : AddLiteralChar(c);
1091 : }
1092 : }
1093 701181 : if (c0_ != quote) return Token::ILLEGAL;
1094 : literal.Complete();
1095 :
1096 701171 : Advance(); // consume quote
1097 701171 : return Token::STRING;
1098 : }
1099 :
1100 :
1101 1677156 : Token::Value Scanner::ScanTemplateSpan() {
1102 : // When scanning a TemplateSpan, we are looking for the following construct:
1103 : // TEMPLATE_SPAN ::
1104 : // ` LiteralChars* ${
1105 : // | } LiteralChars* ${
1106 : //
1107 : // TEMPLATE_TAIL ::
1108 : // ` LiteralChars* `
1109 : // | } LiteralChar* `
1110 : //
1111 : // A TEMPLATE_SPAN should always be followed by an Expression, while a
1112 : // TEMPLATE_TAIL terminates a TemplateLiteral and does not need to be
1113 : // followed by an Expression.
1114 :
1115 : // These scoped helpers save and restore the original error state, so that we
1116 : // can specially treat invalid escape sequences in templates (which are
1117 : // handled by the parser).
1118 137771 : ErrorState scanner_error_state(&scanner_error_, &scanner_error_location_);
1119 137771 : ErrorState octal_error_state(&octal_message_, &octal_pos_);
1120 :
1121 : Token::Value result = Token::TEMPLATE_SPAN;
1122 : LiteralScope literal(this);
1123 : StartRawLiteral();
1124 : const bool capture_raw = true;
1125 : const bool in_template_literal = true;
1126 : while (true) {
1127 1426003 : uc32 c = c0_;
1128 1426003 : Advance<capture_raw>();
1129 1426003 : if (c == '`') {
1130 : result = Token::TEMPLATE_TAIL;
1131 : ReduceRawLiteralLength(1);
1132 : break;
1133 1368525 : } else if (c == '$' && c0_ == '{') {
1134 78785 : Advance<capture_raw>(); // Consume '{'
1135 : ReduceRawLiteralLength(2);
1136 : break;
1137 1289740 : } else if (c == '\\') {
1138 50160 : if (c0_ != kEndOfInput && IsLineTerminator(c0_)) {
1139 : // The TV of LineContinuation :: \ LineTerminatorSequence is the empty
1140 : // code unit sequence.
1141 94 : uc32 lastChar = c0_;
1142 94 : Advance<capture_raw>();
1143 94 : if (lastChar == '\r') {
1144 : ReduceRawLiteralLength(1); // Remove \r
1145 56 : if (c0_ == '\n') {
1146 28 : Advance<capture_raw>(); // Adds \n
1147 : } else {
1148 : AddRawLiteralChar('\n');
1149 : }
1150 : }
1151 : } else {
1152 24991 : bool success = ScanEscape<capture_raw, in_template_literal>();
1153 : USE(success);
1154 : DCHECK_EQ(!success, has_error());
1155 : // For templates, invalid escape sequence checking is handled in the
1156 : // parser.
1157 : scanner_error_state.MoveErrorTo(&next_);
1158 : octal_error_state.MoveErrorTo(&next_);
1159 : }
1160 1264655 : } else if (c < 0) {
1161 : // Unterminated template literal
1162 : PushBack(c);
1163 : break;
1164 : } else {
1165 : // The TRV of LineTerminatorSequence :: <CR> is the CV 0x000A.
1166 : // The TRV of LineTerminatorSequence :: <CR><LF> is the sequence
1167 : // consisting of the CV 0x000A.
1168 1263147 : if (c == '\r') {
1169 : ReduceRawLiteralLength(1); // Remove \r
1170 570 : if (c0_ == '\n') {
1171 528 : Advance<capture_raw>(); // Adds \n
1172 : } else {
1173 : AddRawLiteralChar('\n');
1174 : }
1175 : c = '\n';
1176 : }
1177 : AddLiteralChar(c);
1178 : }
1179 : }
1180 : literal.Complete();
1181 137771 : next_.location.end_pos = source_pos();
1182 137771 : next_.token = result;
1183 137771 : next_.contextual_token = Token::UNINITIALIZED;
1184 :
1185 137771 : return result;
1186 : }
1187 :
1188 :
1189 70715 : Token::Value Scanner::ScanTemplateStart() {
1190 : DCHECK_EQ(next_next_.token, Token::UNINITIALIZED);
1191 : DCHECK_EQ(c0_, '`');
1192 70715 : next_.location.beg_pos = source_pos();
1193 70715 : Advance(); // Consume `
1194 70715 : return ScanTemplateSpan();
1195 : }
1196 :
1197 1678478 : Handle<String> Scanner::SourceUrl(Isolate* isolate) const {
1198 : Handle<String> tmp;
1199 3356956 : if (source_url_.length() > 0) tmp = source_url_.Internalize(isolate);
1200 1678478 : return tmp;
1201 : }
1202 :
1203 1678476 : Handle<String> Scanner::SourceMappingUrl(Isolate* isolate) const {
1204 : Handle<String> tmp;
1205 3356952 : if (source_mapping_url_.length() > 0)
1206 100 : tmp = source_mapping_url_.Internalize(isolate);
1207 1678476 : return tmp;
1208 : }
1209 :
1210 0 : void Scanner::ScanDecimalDigits() {
1211 8558468 : while (IsDecimalDigit(c0_))
1212 1772850 : AddLiteralCharAdvance();
1213 0 : }
1214 :
1215 :
1216 168234930 : Token::Value Scanner::ScanNumber(bool seen_period) {
1217 : DCHECK(IsDecimalDigit(c0_)); // the first digit of the number or the fraction
1218 :
1219 : enum {
1220 : DECIMAL,
1221 : DECIMAL_WITH_LEADING_ZERO,
1222 : HEX,
1223 : OCTAL,
1224 : IMPLICIT_OCTAL,
1225 : BINARY
1226 : } kind = DECIMAL;
1227 :
1228 : LiteralScope literal(this);
1229 29535133 : bool at_start = !seen_period;
1230 : int start_pos = source_pos(); // For reporting octal positions.
1231 29535133 : if (seen_period) {
1232 : // we have already seen a decimal point of the float
1233 : AddLiteralChar('.');
1234 : ScanDecimalDigits(); // we know we have at least one digit
1235 :
1236 : } else {
1237 : // if the first character is '0' we must check for octals and hex
1238 29532140 : if (c0_ == '0') {
1239 11459899 : AddLiteralCharAdvance();
1240 :
1241 : // either 0, 0exxx, 0Exxx, 0.xxx, a hex number, a binary number or
1242 : // an octal number.
1243 11459899 : if (c0_ == 'x' || c0_ == 'X') {
1244 : // hex number
1245 : kind = HEX;
1246 228713 : AddLiteralCharAdvance();
1247 457426 : if (!IsHexDigit(c0_)) {
1248 : // we must have at least one hex digit after 'x'/'X'
1249 : return Token::ILLEGAL;
1250 : }
1251 1541530 : while (IsHexDigit(c0_)) {
1252 542064 : AddLiteralCharAdvance();
1253 : }
1254 11231186 : } else if (c0_ == 'o' || c0_ == 'O') {
1255 : kind = OCTAL;
1256 81 : AddLiteralCharAdvance();
1257 162 : if (!IsOctalDigit(c0_)) {
1258 : // we must have at least one octal digit after 'o'/'O'
1259 : return Token::ILLEGAL;
1260 : }
1261 420 : while (IsOctalDigit(c0_)) {
1262 138 : AddLiteralCharAdvance();
1263 : }
1264 11231105 : } else if (c0_ == 'b' || c0_ == 'B') {
1265 : kind = BINARY;
1266 71 : AddLiteralCharAdvance();
1267 142 : if (!IsBinaryDigit(c0_)) {
1268 : // we must have at least one binary digit after 'b'/'B'
1269 : return Token::ILLEGAL;
1270 : }
1271 420 : while (IsBinaryDigit(c0_)) {
1272 148 : AddLiteralCharAdvance();
1273 : }
1274 11373317 : } else if ('0' <= c0_ && c0_ <= '7') {
1275 : // (possible) octal number
1276 : kind = IMPLICIT_OCTAL;
1277 : while (true) {
1278 284033 : if (c0_ == '8' || c0_ == '9') {
1279 : at_start = false;
1280 : kind = DECIMAL_WITH_LEADING_ZERO;
1281 : break;
1282 : }
1283 284027 : if (c0_ < '0' || '7' < c0_) {
1284 : // Octal literal finished.
1285 141744 : octal_pos_ = Location(start_pos, source_pos());
1286 141744 : octal_message_ = MessageTemplate::kStrictOctalLiteral;
1287 141744 : break;
1288 : }
1289 142283 : AddLiteralCharAdvance();
1290 : }
1291 11089284 : } else if (c0_ == '8' || c0_ == '9') {
1292 : kind = DECIMAL_WITH_LEADING_ZERO;
1293 : }
1294 : }
1295 :
1296 : // Parse decimal digits and allow trailing fractional part.
1297 29532110 : if (kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO) {
1298 29161528 : if (at_start) {
1299 : uint64_t value = 0;
1300 165629966 : while (IsDecimalDigit(c0_)) {
1301 53653458 : value = 10 * value + (c0_ - '0');
1302 :
1303 : uc32 first_char = c0_;
1304 : Advance<false, false>();
1305 : AddLiteralChar(first_char);
1306 : }
1307 :
1308 87453759 : if (next_.literal_chars->one_byte_literal().length() <= 10 &&
1309 58186451 : value <= Smi::kMaxValue && c0_ != '.' &&
1310 55542282 : (c0_ == kEndOfInput || !unicode_cache_->IsIdentifierStart(c0_))) {
1311 27854418 : next_.smi_value_ = static_cast<uint32_t>(value);
1312 : literal.Complete();
1313 27854418 : HandleLeadSurrogate();
1314 :
1315 27854417 : if (kind == DECIMAL_WITH_LEADING_ZERO) {
1316 35308 : octal_pos_ = Location(start_pos, source_pos());
1317 35308 : octal_message_ = MessageTemplate::kStrictDecimalWithLeadingZero;
1318 : }
1319 : return Token::SMI;
1320 : }
1321 1307107 : HandleLeadSurrogate();
1322 : }
1323 :
1324 : ScanDecimalDigits(); // optional
1325 1307113 : if (c0_ == '.') {
1326 : seen_period = true;
1327 1181088 : AddLiteralCharAdvance();
1328 : ScanDecimalDigits(); // optional
1329 : }
1330 : }
1331 : }
1332 :
1333 : bool is_bigint = false;
1334 3361419 : if (allow_harmony_bigint() && c0_ == 'n' && !seen_period &&
1335 71 : (kind == DECIMAL || kind == HEX || kind == OCTAL || kind == BINARY)) {
1336 : is_bigint = true;
1337 25 : Advance();
1338 1680663 : } else if (c0_ == 'e' || c0_ == 'E') {
1339 : // scan exponent, if any
1340 : DCHECK(kind != HEX); // 'e'/'E' must be scanned as part of the hex number
1341 15220 : if (!(kind == DECIMAL || kind == DECIMAL_WITH_LEADING_ZERO))
1342 : return Token::ILLEGAL;
1343 : // scan exponent
1344 15220 : AddLiteralCharAdvance();
1345 15220 : if (c0_ == '+' || c0_ == '-')
1346 9190 : AddLiteralCharAdvance();
1347 30436 : if (!IsDecimalDigit(c0_)) {
1348 : // we must have at least one decimal digit after 'e'/'E'
1349 : return Token::ILLEGAL;
1350 : }
1351 : ScanDecimalDigits();
1352 : }
1353 :
1354 : // The source character immediately following a numeric literal must
1355 : // not be an identifier start or a decimal digit; see ECMA-262
1356 : // section 7.8.3, page 17 (note that we read only one decimal digit
1357 : // if the value is 0).
1358 5041974 : if (IsDecimalDigit(c0_) ||
1359 3332774 : (c0_ != kEndOfInput && unicode_cache_->IsIdentifierStart(c0_)))
1360 : return Token::ILLEGAL;
1361 :
1362 : literal.Complete();
1363 :
1364 1680033 : if (kind == DECIMAL_WITH_LEADING_ZERO) {
1365 6 : octal_pos_ = Location(start_pos, source_pos());
1366 6 : octal_message_ = MessageTemplate::kStrictDecimalWithLeadingZero;
1367 : }
1368 1680033 : return is_bigint ? Token::BIGINT : Token::NUMBER;
1369 : }
1370 :
1371 :
1372 15970 : uc32 Scanner::ScanIdentifierUnicodeEscape() {
1373 15970 : Advance();
1374 15970 : if (c0_ != 'u') return -1;
1375 15640 : Advance();
1376 15640 : return ScanUnicodeEscape<false>();
1377 : }
1378 :
1379 :
1380 : template <bool capture_raw>
1381 103055 : uc32 Scanner::ScanUnicodeEscape() {
1382 : // Accept both \uxxxx and \u{xxxxxx}. In the latter case, the number of
1383 : // hex digits between { } is arbitrary. \ and u have already been read.
1384 83910 : if (c0_ == '{') {
1385 37256 : int begin = source_pos() - 2;
1386 37256 : Advance<capture_raw>();
1387 37256 : uc32 cp = ScanUnlimitedLengthHexNumber<capture_raw>(0x10ffff, begin);
1388 37256 : if (cp < 0 || c0_ != '}') {
1389 : ReportScannerError(source_pos(),
1390 : MessageTemplate::kInvalidUnicodeEscapeSequence);
1391 : return -1;
1392 : }
1393 27016 : Advance<capture_raw>();
1394 27016 : return cp;
1395 : }
1396 : const bool unicode = true;
1397 46654 : return ScanHexNumber<capture_raw, unicode>(4);
1398 : }
1399 :
1400 :
1401 : // ----------------------------------------------------------------------------
1402 : // Keyword Matcher
1403 :
1404 : #define KEYWORDS(KEYWORD_GROUP, KEYWORD) \
1405 : KEYWORD_GROUP('a') \
1406 : KEYWORD("arguments", Token::ARGUMENTS) \
1407 : KEYWORD("as", Token::AS) \
1408 : KEYWORD("async", Token::ASYNC) \
1409 : KEYWORD("await", Token::AWAIT) \
1410 : KEYWORD("anonymous", Token::ANONYMOUS) \
1411 : KEYWORD_GROUP('b') \
1412 : KEYWORD("break", Token::BREAK) \
1413 : KEYWORD_GROUP('c') \
1414 : KEYWORD("case", Token::CASE) \
1415 : KEYWORD("catch", Token::CATCH) \
1416 : KEYWORD("class", Token::CLASS) \
1417 : KEYWORD("const", Token::CONST) \
1418 : KEYWORD("constructor", Token::CONSTRUCTOR) \
1419 : KEYWORD("continue", Token::CONTINUE) \
1420 : KEYWORD_GROUP('d') \
1421 : KEYWORD("debugger", Token::DEBUGGER) \
1422 : KEYWORD("default", Token::DEFAULT) \
1423 : KEYWORD("delete", Token::DELETE) \
1424 : KEYWORD("do", Token::DO) \
1425 : KEYWORD_GROUP('e') \
1426 : KEYWORD("else", Token::ELSE) \
1427 : KEYWORD("enum", Token::ENUM) \
1428 : KEYWORD("eval", Token::EVAL) \
1429 : KEYWORD("export", Token::EXPORT) \
1430 : KEYWORD("extends", Token::EXTENDS) \
1431 : KEYWORD_GROUP('f') \
1432 : KEYWORD("false", Token::FALSE_LITERAL) \
1433 : KEYWORD("finally", Token::FINALLY) \
1434 : KEYWORD("for", Token::FOR) \
1435 : KEYWORD("from", Token::FROM) \
1436 : KEYWORD("function", Token::FUNCTION) \
1437 : KEYWORD_GROUP('g') \
1438 : KEYWORD("get", Token::GET) \
1439 : KEYWORD_GROUP('i') \
1440 : KEYWORD("if", Token::IF) \
1441 : KEYWORD("implements", Token::FUTURE_STRICT_RESERVED_WORD) \
1442 : KEYWORD("import", Token::IMPORT) \
1443 : KEYWORD("in", Token::IN) \
1444 : KEYWORD("instanceof", Token::INSTANCEOF) \
1445 : KEYWORD("interface", Token::FUTURE_STRICT_RESERVED_WORD) \
1446 : KEYWORD_GROUP('l') \
1447 : KEYWORD("let", Token::LET) \
1448 : KEYWORD_GROUP('m') \
1449 : KEYWORD("meta", Token::META) \
1450 : KEYWORD_GROUP('n') \
1451 : KEYWORD("name", Token::NAME) \
1452 : KEYWORD("new", Token::NEW) \
1453 : KEYWORD("null", Token::NULL_LITERAL) \
1454 : KEYWORD_GROUP('o') \
1455 : KEYWORD("of", Token::OF) \
1456 : KEYWORD_GROUP('p') \
1457 : KEYWORD("package", Token::FUTURE_STRICT_RESERVED_WORD) \
1458 : KEYWORD("private", Token::FUTURE_STRICT_RESERVED_WORD) \
1459 : KEYWORD("protected", Token::FUTURE_STRICT_RESERVED_WORD) \
1460 : KEYWORD("prototype", Token::PROTOTYPE) \
1461 : KEYWORD("public", Token::FUTURE_STRICT_RESERVED_WORD) \
1462 : KEYWORD_GROUP('r') \
1463 : KEYWORD("return", Token::RETURN) \
1464 : KEYWORD_GROUP('s') \
1465 : KEYWORD("sent", Token::SENT) \
1466 : KEYWORD("set", Token::SET) \
1467 : KEYWORD("static", Token::STATIC) \
1468 : KEYWORD("super", Token::SUPER) \
1469 : KEYWORD("switch", Token::SWITCH) \
1470 : KEYWORD_GROUP('t') \
1471 : KEYWORD("target", Token::TARGET) \
1472 : KEYWORD("this", Token::THIS) \
1473 : KEYWORD("throw", Token::THROW) \
1474 : KEYWORD("true", Token::TRUE_LITERAL) \
1475 : KEYWORD("try", Token::TRY) \
1476 : KEYWORD("typeof", Token::TYPEOF) \
1477 : KEYWORD_GROUP('u') \
1478 : KEYWORD("undefined", Token::UNDEFINED) \
1479 : KEYWORD_GROUP('v') \
1480 : KEYWORD("var", Token::VAR) \
1481 : KEYWORD("void", Token::VOID) \
1482 : KEYWORD_GROUP('w') \
1483 : KEYWORD("while", Token::WHILE) \
1484 : KEYWORD("with", Token::WITH) \
1485 : KEYWORD_GROUP('y') \
1486 : KEYWORD("yield", Token::YIELD) \
1487 : KEYWORD_GROUP('_') \
1488 : KEYWORD("__proto__", Token::PROTO_UNDERSCORED)
1489 :
1490 103459274 : static Token::Value KeywordOrIdentifierToken(const uint8_t* input,
1491 : int input_length) {
1492 : DCHECK_GE(input_length, 1);
1493 : const int kMinLength = 2;
1494 : const int kMaxLength = 11;
1495 103459274 : if (input_length < kMinLength || input_length > kMaxLength) {
1496 : return Token::IDENTIFIER;
1497 : }
1498 86427967 : switch (input[0]) {
1499 : default:
1500 : #define KEYWORD_GROUP_CASE(ch) \
1501 : break; \
1502 : case ch:
1503 : #define KEYWORD(keyword, token) \
1504 : { \
1505 : /* 'keyword' is a char array, so sizeof(keyword) is */ \
1506 : /* strlen(keyword) plus 1 for the NUL char. */ \
1507 : const int keyword_length = sizeof(keyword) - 1; \
1508 : STATIC_ASSERT(keyword_length >= kMinLength); \
1509 : STATIC_ASSERT(keyword_length <= kMaxLength); \
1510 : DCHECK_EQ(input[0], keyword[0]); \
1511 : DCHECK(token == Token::FUTURE_STRICT_RESERVED_WORD || \
1512 : 0 == strncmp(keyword, Token::String(token), sizeof(keyword))); \
1513 : if (input_length == keyword_length && input[1] == keyword[1] && \
1514 : (keyword_length <= 2 || input[2] == keyword[2]) && \
1515 : (keyword_length <= 3 || input[3] == keyword[3]) && \
1516 : (keyword_length <= 4 || input[4] == keyword[4]) && \
1517 : (keyword_length <= 5 || input[5] == keyword[5]) && \
1518 : (keyword_length <= 6 || input[6] == keyword[6]) && \
1519 : (keyword_length <= 7 || input[7] == keyword[7]) && \
1520 : (keyword_length <= 8 || input[8] == keyword[8]) && \
1521 : (keyword_length <= 9 || input[9] == keyword[9]) && \
1522 : (keyword_length <= 10 || input[10] == keyword[10])) { \
1523 : return token; \
1524 : } \
1525 : }
1526 2575394 : KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD)
1527 : }
1528 41862043 : return Token::IDENTIFIER;
1529 : }
1530 :
1531 :
1532 1897250098 : Token::Value Scanner::ScanIdentifierOrKeyword() {
1533 : DCHECK(unicode_cache_->IsIdentifierStart(c0_));
1534 : LiteralScope literal(this);
1535 283300734 : if (IsInRange(c0_, 'a', 'z') || c0_ == '_') {
1536 602307269 : do {
1537 602307098 : char first_char = static_cast<char>(c0_);
1538 : Advance<false, false>();
1539 : AddLiteralChar(first_char);
1540 1204614538 : } while (IsInRange(c0_, 'a', 'z') || c0_ == '_');
1541 :
1542 249358170 : if (IsDecimalDigit(c0_) || IsInRange(c0_, 'A', 'Z') || c0_ == '_' ||
1543 : c0_ == '$') {
1544 : // Identifier starting with lowercase.
1545 24445634 : char first_char = static_cast<char>(c0_);
1546 : Advance<false, false>();
1547 : AddLiteralChar(first_char);
1548 294804102 : while (IsAsciiIdentifier(c0_)) {
1549 122956417 : char first_char = static_cast<char>(c0_);
1550 : Advance<false, false>();
1551 : AddLiteralChar(first_char);
1552 : }
1553 24445634 : if (c0_ <= kMaxAscii && c0_ != '\\') {
1554 : literal.Complete();
1555 24445636 : return Token::IDENTIFIER;
1556 : }
1557 103458040 : } else if (c0_ <= kMaxAscii && c0_ != '\\') {
1558 : // Only a-z+ or _: could be a keyword or identifier.
1559 103445080 : Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
1560 : Token::Value token =
1561 103444535 : KeywordOrIdentifierToken(chars.start(), chars.length());
1562 206889086 : if (token == Token::IDENTIFIER ||
1563 147965980 : token == Token::FUTURE_STRICT_RESERVED_WORD ||
1564 : Token::IsContextualKeyword(token))
1565 : literal.Complete();
1566 : return token;
1567 : }
1568 :
1569 13503 : HandleLeadSurrogate();
1570 13746864 : } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '_' || c0_ == '$') {
1571 128089118 : do {
1572 128089116 : char first_char = static_cast<char>(c0_);
1573 : Advance<false, false>();
1574 : AddLiteralChar(first_char);
1575 128089118 : } while (IsAsciiIdentifier(c0_));
1576 :
1577 13743962 : if (c0_ <= kMaxAscii && c0_ != '\\') {
1578 : literal.Complete();
1579 13743915 : return Token::IDENTIFIER;
1580 : }
1581 :
1582 47 : HandleLeadSurrogate();
1583 2904 : } else if (c0_ == '\\') {
1584 : // Scan identifier start character.
1585 2712 : uc32 c = ScanIdentifierUnicodeEscape();
1586 : // Only allow legal identifier start characters.
1587 8136 : if (c < 0 ||
1588 7786 : c == '\\' || // No recursive escapes.
1589 2362 : !unicode_cache_->IsIdentifierStart(c)) {
1590 : return Token::ILLEGAL;
1591 : }
1592 : AddLiteralChar(c);
1593 2323 : return ScanIdentifierSuffix(&literal, true);
1594 : } else {
1595 : uc32 first_char = c0_;
1596 192 : Advance();
1597 : AddLiteralChar(first_char);
1598 : }
1599 :
1600 : // Scan the rest of the identifier characters.
1601 28610 : while (c0_ != kEndOfInput && unicode_cache_->IsIdentifierPart(c0_)) {
1602 13814 : if (c0_ != '\\') {
1603 : uc32 next_char = c0_;
1604 616 : Advance();
1605 : AddLiteralChar(next_char);
1606 : continue;
1607 : }
1608 : // Fallthrough if no longer able to complete keyword.
1609 13198 : return ScanIdentifierSuffix(&literal, false);
1610 : }
1611 :
1612 1090 : if (next_.literal_chars->is_one_byte()) {
1613 : Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
1614 : Token::Value token =
1615 124 : KeywordOrIdentifierToken(chars.start(), chars.length());
1616 248 : if (token == Token::IDENTIFIER ||
1617 124 : token == Token::FUTURE_STRICT_RESERVED_WORD ||
1618 : Token::IsContextualKeyword(token))
1619 : literal.Complete();
1620 : return token;
1621 : }
1622 : literal.Complete();
1623 421 : return Token::IDENTIFIER;
1624 : }
1625 :
1626 :
1627 15521 : Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal,
1628 52937 : bool escaped) {
1629 : // Scan the rest of the identifier characters.
1630 152177 : while (c0_ != kEndOfInput && unicode_cache_->IsIdentifierPart(c0_)) {
1631 53515 : if (c0_ == '\\') {
1632 13258 : uc32 c = ScanIdentifierUnicodeEscape();
1633 : escaped = true;
1634 : // Only allow legal identifier part characters.
1635 39774 : if (c < 0 ||
1636 39214 : c == '\\' ||
1637 12698 : !unicode_cache_->IsIdentifierPart(c)) {
1638 : return Token::ILLEGAL;
1639 : }
1640 : AddLiteralChar(c);
1641 : } else {
1642 : AddLiteralChar(c0_);
1643 40257 : Advance();
1644 : }
1645 : }
1646 : literal->Complete();
1647 :
1648 14943 : if (escaped && next_.literal_chars->is_one_byte()) {
1649 14608 : Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal();
1650 : Token::Value token =
1651 14608 : KeywordOrIdentifierToken(chars.start(), chars.length());
1652 : /* TODO(adamk): YIELD should be handled specially. */
1653 28365 : if (token == Token::IDENTIFIER || Token::IsContextualKeyword(token)) {
1654 : return token;
1655 26914 : } else if (token == Token::FUTURE_STRICT_RESERVED_WORD ||
1656 23502 : token == Token::LET || token == Token::STATIC) {
1657 : return Token::ESCAPED_STRICT_RESERVED_WORD;
1658 : } else {
1659 7925 : return Token::ESCAPED_KEYWORD;
1660 : }
1661 : }
1662 : return Token::IDENTIFIER;
1663 : }
1664 :
1665 188122 : bool Scanner::ScanRegExpPattern() {
1666 : DCHECK(next_next_.token == Token::UNINITIALIZED);
1667 : DCHECK(next_.token == Token::DIV || next_.token == Token::ASSIGN_DIV);
1668 :
1669 : // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags
1670 : bool in_character_class = false;
1671 94061 : bool seen_equal = (next_.token == Token::ASSIGN_DIV);
1672 :
1673 : // Previous token is either '/' or '/=', in the second case, the
1674 : // pattern starts at =.
1675 94061 : next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1);
1676 94061 : next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0);
1677 :
1678 : // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5,
1679 : // the scanner should pass uninterpreted bodies to the RegExp
1680 : // constructor.
1681 : LiteralScope literal(this);
1682 94061 : if (seen_equal) {
1683 : AddLiteralChar('=');
1684 : }
1685 :
1686 937913 : while (c0_ != '/' || in_character_class) {
1687 1687948 : if (c0_ == kEndOfInput || IsLineTerminator(c0_)) {
1688 : return false;
1689 : }
1690 843857 : if (c0_ == '\\') { // Escape sequence.
1691 102166 : AddLiteralCharAdvance();
1692 204327 : if (c0_ == kEndOfInput || IsLineTerminator(c0_)) {
1693 : return false;
1694 : }
1695 102161 : AddLiteralCharAdvance();
1696 : // If the escape allows more characters, i.e., \x??, \u????, or \c?,
1697 : // only "safe" characters are allowed (letters, digits, underscore),
1698 : // otherwise the escape isn't valid and the invalid character has
1699 : // its normal meaning. I.e., we can just continue scanning without
1700 : // worrying whether the following characters are part of the escape
1701 : // or not, since any '/', '\\' or '[' is guaranteed to not be part
1702 : // of the escape sequence.
1703 :
1704 : // TODO(896): At some point, parse RegExps more thoroughly to capture
1705 : // octal esacpes in strict mode.
1706 : } else { // Unescaped character.
1707 741691 : if (c0_ == '[') in_character_class = true;
1708 741691 : if (c0_ == ']') in_character_class = false;
1709 741691 : AddLiteralCharAdvance();
1710 : }
1711 : }
1712 93822 : Advance(); // consume '/'
1713 :
1714 : literal.Complete();
1715 93822 : next_.token = Token::REGEXP_LITERAL;
1716 93822 : next_.contextual_token = Token::UNINITIALIZED;
1717 93822 : return true;
1718 : }
1719 :
1720 :
1721 186765 : Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() {
1722 : DCHECK(next_.token == Token::REGEXP_LITERAL);
1723 :
1724 : // Scan regular expression flags.
1725 : int flags = 0;
1726 392441 : while (c0_ != kEndOfInput && unicode_cache_->IsIdentifierPart(c0_)) {
1727 : RegExp::Flags flag = RegExp::kNone;
1728 57049 : switch (c0_) {
1729 : case 'g':
1730 : flag = RegExp::kGlobal;
1731 : break;
1732 : case 'i':
1733 : flag = RegExp::kIgnoreCase;
1734 3937 : break;
1735 : case 'm':
1736 : flag = RegExp::kMultiline;
1737 6028 : break;
1738 : case 's':
1739 30 : if (FLAG_harmony_regexp_dotall) {
1740 : flag = RegExp::kDotAll;
1741 : } else {
1742 : return Nothing<RegExp::Flags>();
1743 : }
1744 : break;
1745 : case 'u':
1746 : flag = RegExp::kUnicode;
1747 16999 : break;
1748 : case 'y':
1749 : flag = RegExp::kSticky;
1750 91 : break;
1751 : default:
1752 : return Nothing<RegExp::Flags>();
1753 : }
1754 56529 : if (flags & flag) {
1755 : return Nothing<RegExp::Flags>();
1756 : }
1757 56390 : Advance();
1758 56390 : flags |= flag;
1759 : }
1760 :
1761 93053 : next_.location.end_pos = source_pos();
1762 93053 : return Just(RegExp::Flags(flags));
1763 : }
1764 :
1765 113320097 : const AstRawString* Scanner::CurrentSymbol(
1766 113320097 : AstValueFactory* ast_value_factory) const {
1767 113320097 : if (is_literal_one_byte()) {
1768 113280003 : return ast_value_factory->GetOneByteString(literal_one_byte_string());
1769 : }
1770 40270 : return ast_value_factory->GetTwoByteString(literal_two_byte_string());
1771 : }
1772 :
1773 62607 : const AstRawString* Scanner::NextSymbol(
1774 62607 : AstValueFactory* ast_value_factory) const {
1775 62607 : if (is_next_literal_one_byte()) {
1776 60473 : return ast_value_factory->GetOneByteString(next_literal_one_byte_string());
1777 : }
1778 2134 : return ast_value_factory->GetTwoByteString(next_literal_two_byte_string());
1779 : }
1780 :
1781 62557 : const AstRawString* Scanner::CurrentRawSymbol(
1782 62557 : AstValueFactory* ast_value_factory) const {
1783 62557 : if (is_raw_literal_one_byte()) {
1784 62536 : return ast_value_factory->GetOneByteString(raw_literal_one_byte_string());
1785 : }
1786 21 : return ast_value_factory->GetTwoByteString(raw_literal_two_byte_string());
1787 : }
1788 :
1789 :
1790 2633604 : double Scanner::DoubleValue() {
1791 : DCHECK(is_literal_one_byte());
1792 : return StringToDouble(
1793 : unicode_cache_,
1794 : literal_one_byte_string(),
1795 2633604 : ALLOW_HEX | ALLOW_OCTAL | ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
1796 : }
1797 :
1798 25 : const char* Scanner::CurrentLiteralAsCString(Zone* zone) const {
1799 : DCHECK(is_literal_one_byte());
1800 : Vector<const uint8_t> vector = literal_one_byte_string();
1801 : int length = vector.length();
1802 25 : char* buffer = zone->NewArray<char>(length + 1);
1803 25 : memcpy(buffer, vector.start(), length);
1804 25 : buffer[length] = '\0';
1805 25 : return buffer;
1806 : }
1807 :
1808 8375565 : bool Scanner::IsDuplicateSymbol(DuplicateFinder* duplicate_finder,
1809 : AstValueFactory* ast_value_factory) const {
1810 : DCHECK_NOT_NULL(duplicate_finder);
1811 : DCHECK_NOT_NULL(ast_value_factory);
1812 8375565 : const AstRawString* string = CurrentSymbol(ast_value_factory);
1813 16751129 : return !duplicate_finder->known_symbols_.insert(string).second;
1814 : }
1815 :
1816 157 : void Scanner::SeekNext(size_t position) {
1817 : // Use with care: This cleanly resets most, but not all scanner state.
1818 : // TODO(vogelheim): Fix this, or at least DCHECK the relevant conditions.
1819 :
1820 : // To re-scan from a given character position, we need to:
1821 : // 1, Reset the current_, next_ and next_next_ tokens
1822 : // (next_ + next_next_ will be overwrittem by Next(),
1823 : // current_ will remain unchanged, so overwrite it fully.)
1824 : current_ = {{0, 0},
1825 : nullptr,
1826 : nullptr,
1827 : 0,
1828 : Token::UNINITIALIZED,
1829 : MessageTemplate::kNone,
1830 : {0, 0},
1831 157 : Token::UNINITIALIZED};
1832 157 : next_.token = Token::UNINITIALIZED;
1833 157 : next_.contextual_token = Token::UNINITIALIZED;
1834 157 : next_next_.token = Token::UNINITIALIZED;
1835 157 : next_next_.contextual_token = Token::UNINITIALIZED;
1836 : // 2, reset the source to the desired position,
1837 157 : source_->Seek(position);
1838 : // 3, re-scan, by scanning the look-ahead char + 1 token (next_).
1839 157 : c0_ = source_->Advance();
1840 157 : Next();
1841 : DCHECK_EQ(next_.location.beg_pos, static_cast<int>(position));
1842 157 : }
1843 :
1844 : } // namespace internal
1845 : } // namespace v8
|