OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Features shared by parsing and pre-parsing scanners. | 5 // Features shared by parsing and pre-parsing scanners. |
6 | 6 |
7 #include "src/parsing/scanner.h" | 7 #include "src/parsing/scanner.h" |
8 | 8 |
9 #include <stdint.h> | 9 #include <stdint.h> |
10 | 10 |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 } | 253 } |
254 has_line_terminator_before_next_ = false; | 254 has_line_terminator_before_next_ = false; |
255 has_multiline_comment_before_next_ = false; | 255 has_multiline_comment_before_next_ = false; |
256 if (static_cast<unsigned>(c0_) <= 0x7f) { | 256 if (static_cast<unsigned>(c0_) <= 0x7f) { |
257 Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]); | 257 Token::Value token = static_cast<Token::Value>(one_char_tokens[c0_]); |
258 if (token != Token::ILLEGAL) { | 258 if (token != Token::ILLEGAL) { |
259 int pos = source_pos(); | 259 int pos = source_pos(); |
260 next_.token = token; | 260 next_.token = token; |
261 next_.location.beg_pos = pos; | 261 next_.location.beg_pos = pos; |
262 next_.location.end_pos = pos + 1; | 262 next_.location.end_pos = pos + 1; |
| 263 next_.literal_chars = nullptr; |
| 264 next_.raw_literal_chars = nullptr; |
263 Advance(); | 265 Advance(); |
264 return current_.token; | 266 return current_.token; |
265 } | 267 } |
266 } | 268 } |
267 Scan(); | 269 Scan(); |
268 return current_.token; | 270 return current_.token; |
269 } | 271 } |
270 | 272 |
271 | 273 |
272 Token::Value Scanner::PeekAhead() { | 274 Token::Value Scanner::PeekAhead() { |
| 275 DCHECK(next_.token != Token::DIV); |
| 276 DCHECK(next_.token != Token::ASSIGN_DIV); |
| 277 |
273 if (next_next_.token != Token::UNINITIALIZED) { | 278 if (next_next_.token != Token::UNINITIALIZED) { |
274 return next_next_.token; | 279 return next_next_.token; |
275 } | 280 } |
276 TokenDesc prev = current_; | 281 TokenDesc prev = current_; |
277 bool has_line_terminator_before_next = | 282 bool has_line_terminator_before_next = |
278 has_line_terminator_before_next_ || has_multiline_comment_before_next_; | 283 has_line_terminator_before_next_ || has_multiline_comment_before_next_; |
279 Next(); | 284 Next(); |
280 has_line_terminator_after_next_ = | 285 has_line_terminator_after_next_ = |
281 has_line_terminator_before_next_ || has_multiline_comment_before_next_; | 286 has_line_terminator_before_next_ || has_multiline_comment_before_next_; |
282 has_line_terminator_before_next_ = has_line_terminator_before_next; | 287 has_line_terminator_before_next_ = has_line_terminator_before_next; |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 } | 729 } |
725 break; | 730 break; |
726 } | 731 } |
727 | 732 |
728 // Continue scanning for tokens as long as we're just skipping | 733 // Continue scanning for tokens as long as we're just skipping |
729 // whitespace. | 734 // whitespace. |
730 } while (token == Token::WHITESPACE); | 735 } while (token == Token::WHITESPACE); |
731 | 736 |
732 next_.location.end_pos = source_pos(); | 737 next_.location.end_pos = source_pos(); |
733 next_.token = token; | 738 next_.token = token; |
| 739 |
| 740 #ifdef DEBUG |
| 741 SanityCheckTokenDesc(current_); |
| 742 SanityCheckTokenDesc(next_); |
| 743 SanityCheckTokenDesc(next_next_); |
| 744 #endif |
734 } | 745 } |
735 | 746 |
| 747 #ifdef DEBUG |
| 748 void Scanner::SanityCheckTokenDesc(const TokenDesc& token) const { |
| 749 // Most tokens should not have literal_chars or even raw_literal chars. |
| 750 // The rules are: |
| 751 // - UNINITIALIZED: we don't care. |
| 752 // - TEMPLATE_*: need both literal + raw literal chars. |
| 753 // - IDENTIFIERS, STRINGS, etc.: need a literal, but no raw literal. |
| 754 // - all others: should have neither. |
| 755 |
| 756 switch (token.token) { |
| 757 case Token::UNINITIALIZED: |
| 758 // token.literal_chars & other members might be garbage. That's ok. |
| 759 break; |
| 760 case Token::TEMPLATE_SPAN: |
| 761 case Token::TEMPLATE_TAIL: |
| 762 DCHECK_NOT_NULL(token.raw_literal_chars); |
| 763 DCHECK_NOT_NULL(token.literal_chars); |
| 764 break; |
| 765 case Token::ESCAPED_KEYWORD: |
| 766 case Token::ESCAPED_STRICT_RESERVED_WORD: |
| 767 case Token::FUTURE_STRICT_RESERVED_WORD: |
| 768 case Token::IDENTIFIER: |
| 769 case Token::NUMBER: |
| 770 case Token::REGEXP_LITERAL: |
| 771 case Token::SMI: |
| 772 case Token::STRING: |
| 773 DCHECK_NOT_NULL(token.literal_chars); |
| 774 DCHECK_NULL(token.raw_literal_chars); |
| 775 break; |
| 776 default: |
| 777 DCHECK_NULL(token.literal_chars); |
| 778 DCHECK_NULL(token.raw_literal_chars); |
| 779 break; |
| 780 } |
| 781 } |
| 782 #endif // DEBUG |
736 | 783 |
737 void Scanner::SeekForward(int pos) { | 784 void Scanner::SeekForward(int pos) { |
738 // After this call, we will have the token at the given position as | 785 // After this call, we will have the token at the given position as |
739 // the "next" token. The "current" token will be invalid. | 786 // the "next" token. The "current" token will be invalid. |
740 if (pos == next_.location.beg_pos) return; | 787 if (pos == next_.location.beg_pos) return; |
741 int current_pos = source_pos(); | 788 int current_pos = source_pos(); |
742 DCHECK_EQ(next_.location.end_pos, current_pos); | 789 DCHECK_EQ(next_.location.end_pos, current_pos); |
743 // Positions inside the lookahead token aren't supported. | 790 // Positions inside the lookahead token aren't supported. |
744 DCHECK(pos >= current_pos); | 791 DCHECK(pos >= current_pos); |
745 if (pos != current_pos) { | 792 if (pos != current_pos) { |
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
947 } | 994 } |
948 } | 995 } |
949 literal.Complete(); | 996 literal.Complete(); |
950 next_.location.end_pos = source_pos(); | 997 next_.location.end_pos = source_pos(); |
951 next_.token = result; | 998 next_.token = result; |
952 return result; | 999 return result; |
953 } | 1000 } |
954 | 1001 |
955 | 1002 |
956 Token::Value Scanner::ScanTemplateStart() { | 1003 Token::Value Scanner::ScanTemplateStart() { |
| 1004 DCHECK(next_next_.token == Token::UNINITIALIZED); |
957 DCHECK(c0_ == '`'); | 1005 DCHECK(c0_ == '`'); |
958 next_.location.beg_pos = source_pos(); | 1006 next_.location.beg_pos = source_pos(); |
959 Advance(); // Consume ` | 1007 Advance(); // Consume ` |
960 return ScanTemplateSpan(); | 1008 return ScanTemplateSpan(); |
961 } | 1009 } |
962 | 1010 |
963 | 1011 |
964 Token::Value Scanner::ScanTemplateContinuation() { | 1012 Token::Value Scanner::ScanTemplateContinuation() { |
965 DCHECK_EQ(next_.token, Token::RBRACE); | 1013 DCHECK_EQ(next_.token, Token::RBRACE); |
966 next_.location.beg_pos = source_pos() - 1; // We already consumed } | 1014 next_.location.beg_pos = source_pos() - 1; // We already consumed } |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1209 KEYWORD_GROUP('v') \ | 1257 KEYWORD_GROUP('v') \ |
1210 KEYWORD("var", Token::VAR) \ | 1258 KEYWORD("var", Token::VAR) \ |
1211 KEYWORD("void", Token::VOID) \ | 1259 KEYWORD("void", Token::VOID) \ |
1212 KEYWORD_GROUP('w') \ | 1260 KEYWORD_GROUP('w') \ |
1213 KEYWORD("while", Token::WHILE) \ | 1261 KEYWORD("while", Token::WHILE) \ |
1214 KEYWORD("with", Token::WITH) \ | 1262 KEYWORD("with", Token::WITH) \ |
1215 KEYWORD_GROUP('y') \ | 1263 KEYWORD_GROUP('y') \ |
1216 KEYWORD("yield", Token::YIELD) | 1264 KEYWORD("yield", Token::YIELD) |
1217 | 1265 |
1218 static Token::Value KeywordOrIdentifierToken(const uint8_t* input, | 1266 static Token::Value KeywordOrIdentifierToken(const uint8_t* input, |
1219 int input_length, bool escaped) { | 1267 int input_length) { |
1220 DCHECK(input_length >= 1); | 1268 DCHECK(input_length >= 1); |
1221 const int kMinLength = 2; | 1269 const int kMinLength = 2; |
1222 const int kMaxLength = 10; | 1270 const int kMaxLength = 10; |
1223 if (input_length < kMinLength || input_length > kMaxLength) { | 1271 if (input_length < kMinLength || input_length > kMaxLength) { |
1224 return Token::IDENTIFIER; | 1272 return Token::IDENTIFIER; |
1225 } | 1273 } |
1226 switch (input[0]) { | 1274 switch (input[0]) { |
1227 default: | 1275 default: |
1228 #define KEYWORD_GROUP_CASE(ch) \ | 1276 #define KEYWORD_GROUP_CASE(ch) \ |
1229 break; \ | 1277 break; \ |
1230 case ch: | 1278 case ch: |
1231 #define KEYWORD(keyword, token) \ | 1279 #define KEYWORD(keyword, token) \ |
1232 { \ | 1280 { \ |
1233 /* 'keyword' is a char array, so sizeof(keyword) is */ \ | 1281 /* 'keyword' is a char array, so sizeof(keyword) is */ \ |
1234 /* strlen(keyword) plus 1 for the NUL char. */ \ | 1282 /* strlen(keyword) plus 1 for the NUL char. */ \ |
1235 const int keyword_length = sizeof(keyword) - 1; \ | 1283 const int keyword_length = sizeof(keyword) - 1; \ |
1236 STATIC_ASSERT(keyword_length >= kMinLength); \ | 1284 STATIC_ASSERT(keyword_length >= kMinLength); \ |
1237 STATIC_ASSERT(keyword_length <= kMaxLength); \ | 1285 STATIC_ASSERT(keyword_length <= kMaxLength); \ |
1238 if (input_length == keyword_length && input[1] == keyword[1] && \ | 1286 if (input_length == keyword_length && input[1] == keyword[1] && \ |
1239 (keyword_length <= 2 || input[2] == keyword[2]) && \ | 1287 (keyword_length <= 2 || input[2] == keyword[2]) && \ |
1240 (keyword_length <= 3 || input[3] == keyword[3]) && \ | 1288 (keyword_length <= 3 || input[3] == keyword[3]) && \ |
1241 (keyword_length <= 4 || input[4] == keyword[4]) && \ | 1289 (keyword_length <= 4 || input[4] == keyword[4]) && \ |
1242 (keyword_length <= 5 || input[5] == keyword[5]) && \ | 1290 (keyword_length <= 5 || input[5] == keyword[5]) && \ |
1243 (keyword_length <= 6 || input[6] == keyword[6]) && \ | 1291 (keyword_length <= 6 || input[6] == keyword[6]) && \ |
1244 (keyword_length <= 7 || input[7] == keyword[7]) && \ | 1292 (keyword_length <= 7 || input[7] == keyword[7]) && \ |
1245 (keyword_length <= 8 || input[8] == keyword[8]) && \ | 1293 (keyword_length <= 8 || input[8] == keyword[8]) && \ |
1246 (keyword_length <= 9 || input[9] == keyword[9])) { \ | 1294 (keyword_length <= 9 || input[9] == keyword[9])) { \ |
1247 if (escaped) { \ | |
1248 /* TODO(adamk): YIELD should be handled specially. */ \ | |
1249 return (token == Token::FUTURE_STRICT_RESERVED_WORD || \ | |
1250 token == Token::LET || token == Token::STATIC) \ | |
1251 ? Token::ESCAPED_STRICT_RESERVED_WORD \ | |
1252 : Token::ESCAPED_KEYWORD; \ | |
1253 } \ | |
1254 return token; \ | 1295 return token; \ |
1255 } \ | 1296 } \ |
1256 } | 1297 } |
1257 KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) | 1298 KEYWORDS(KEYWORD_GROUP_CASE, KEYWORD) |
1258 } | 1299 } |
1259 return Token::IDENTIFIER; | 1300 return Token::IDENTIFIER; |
1260 } | 1301 } |
1261 | 1302 |
1262 | 1303 |
1263 bool Scanner::IdentifierIsFutureStrictReserved( | 1304 bool Scanner::IdentifierIsFutureStrictReserved( |
1264 const AstRawString* string) const { | 1305 const AstRawString* string) const { |
1265 // Keywords are always 1-byte strings. | 1306 // Keywords are always 1-byte strings. |
1266 if (!string->is_one_byte()) return false; | 1307 if (!string->is_one_byte()) return false; |
1267 if (string->IsOneByteEqualTo("let") || string->IsOneByteEqualTo("static") || | 1308 if (string->IsOneByteEqualTo("let") || string->IsOneByteEqualTo("static") || |
1268 string->IsOneByteEqualTo("yield")) { | 1309 string->IsOneByteEqualTo("yield")) { |
1269 return true; | 1310 return true; |
1270 } | 1311 } |
1271 return Token::FUTURE_STRICT_RESERVED_WORD == | 1312 return Token::FUTURE_STRICT_RESERVED_WORD == |
1272 KeywordOrIdentifierToken(string->raw_data(), string->length(), false); | 1313 KeywordOrIdentifierToken(string->raw_data(), string->length()); |
1273 } | 1314 } |
1274 | 1315 |
1275 | 1316 |
1276 Token::Value Scanner::ScanIdentifierOrKeyword() { | 1317 Token::Value Scanner::ScanIdentifierOrKeyword() { |
1277 DCHECK(unicode_cache_->IsIdentifierStart(c0_)); | 1318 DCHECK(unicode_cache_->IsIdentifierStart(c0_)); |
1278 LiteralScope literal(this); | 1319 LiteralScope literal(this); |
1279 if (IsInRange(c0_, 'a', 'z')) { | 1320 if (IsInRange(c0_, 'a', 'z')) { |
1280 do { | 1321 do { |
1281 char first_char = static_cast<char>(c0_); | 1322 char first_char = static_cast<char>(c0_); |
1282 Advance<false, false>(); | 1323 Advance<false, false>(); |
(...skipping 10 matching lines...) Expand all Loading... |
1293 char first_char = static_cast<char>(c0_); | 1334 char first_char = static_cast<char>(c0_); |
1294 Advance<false, false>(); | 1335 Advance<false, false>(); |
1295 AddLiteralChar(first_char); | 1336 AddLiteralChar(first_char); |
1296 } | 1337 } |
1297 if (c0_ <= kMaxAscii && c0_ != '\\') { | 1338 if (c0_ <= kMaxAscii && c0_ != '\\') { |
1298 literal.Complete(); | 1339 literal.Complete(); |
1299 return Token::IDENTIFIER; | 1340 return Token::IDENTIFIER; |
1300 } | 1341 } |
1301 } else if (c0_ <= kMaxAscii && c0_ != '\\') { | 1342 } else if (c0_ <= kMaxAscii && c0_ != '\\') { |
1302 // Only a-z+: could be a keyword or identifier. | 1343 // Only a-z+: could be a keyword or identifier. |
1303 literal.Complete(); | |
1304 Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); | 1344 Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); |
1305 return KeywordOrIdentifierToken(chars.start(), chars.length(), false); | 1345 Token::Value token = |
| 1346 KeywordOrIdentifierToken(chars.start(), chars.length()); |
| 1347 if (token == Token::IDENTIFIER || |
| 1348 token == Token::FUTURE_STRICT_RESERVED_WORD) |
| 1349 literal.Complete(); |
| 1350 return token; |
1306 } | 1351 } |
1307 | 1352 |
1308 HandleLeadSurrogate(); | 1353 HandleLeadSurrogate(); |
1309 } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '_' || c0_ == '$') { | 1354 } else if (IsInRange(c0_, 'A', 'Z') || c0_ == '_' || c0_ == '$') { |
1310 do { | 1355 do { |
1311 char first_char = static_cast<char>(c0_); | 1356 char first_char = static_cast<char>(c0_); |
1312 Advance<false, false>(); | 1357 Advance<false, false>(); |
1313 AddLiteralChar(first_char); | 1358 AddLiteralChar(first_char); |
1314 } while (IsAsciiIdentifier(c0_)); | 1359 } while (IsAsciiIdentifier(c0_)); |
1315 | 1360 |
(...skipping 25 matching lines...) Expand all Loading... |
1341 if (c0_ != '\\') { | 1386 if (c0_ != '\\') { |
1342 uc32 next_char = c0_; | 1387 uc32 next_char = c0_; |
1343 Advance(); | 1388 Advance(); |
1344 AddLiteralChar(next_char); | 1389 AddLiteralChar(next_char); |
1345 continue; | 1390 continue; |
1346 } | 1391 } |
1347 // Fallthrough if no longer able to complete keyword. | 1392 // Fallthrough if no longer able to complete keyword. |
1348 return ScanIdentifierSuffix(&literal, false); | 1393 return ScanIdentifierSuffix(&literal, false); |
1349 } | 1394 } |
1350 | 1395 |
1351 literal.Complete(); | |
1352 | |
1353 if (next_.literal_chars->is_one_byte()) { | 1396 if (next_.literal_chars->is_one_byte()) { |
1354 Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); | 1397 Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); |
1355 return KeywordOrIdentifierToken(chars.start(), chars.length(), false); | 1398 Token::Value token = |
| 1399 KeywordOrIdentifierToken(chars.start(), chars.length()); |
| 1400 if (token == Token::IDENTIFIER) literal.Complete(); |
| 1401 return token; |
1356 } | 1402 } |
| 1403 literal.Complete(); |
1357 return Token::IDENTIFIER; | 1404 return Token::IDENTIFIER; |
1358 } | 1405 } |
1359 | 1406 |
1360 | 1407 |
1361 Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal, | 1408 Token::Value Scanner::ScanIdentifierSuffix(LiteralScope* literal, |
1362 bool escaped) { | 1409 bool escaped) { |
1363 // Scan the rest of the identifier characters. | 1410 // Scan the rest of the identifier characters. |
1364 while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) { | 1411 while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) { |
1365 if (c0_ == '\\') { | 1412 if (c0_ == '\\') { |
1366 uc32 c = ScanIdentifierUnicodeEscape(); | 1413 uc32 c = ScanIdentifierUnicodeEscape(); |
1367 escaped = true; | 1414 escaped = true; |
1368 // Only allow legal identifier part characters. | 1415 // Only allow legal identifier part characters. |
1369 if (c < 0 || | 1416 if (c < 0 || |
1370 c == '\\' || | 1417 c == '\\' || |
1371 !unicode_cache_->IsIdentifierPart(c)) { | 1418 !unicode_cache_->IsIdentifierPart(c)) { |
1372 return Token::ILLEGAL; | 1419 return Token::ILLEGAL; |
1373 } | 1420 } |
1374 AddLiteralChar(c); | 1421 AddLiteralChar(c); |
1375 } else { | 1422 } else { |
1376 AddLiteralChar(c0_); | 1423 AddLiteralChar(c0_); |
1377 Advance(); | 1424 Advance(); |
1378 } | 1425 } |
1379 } | 1426 } |
1380 literal->Complete(); | 1427 literal->Complete(); |
1381 | 1428 |
1382 if (escaped && next_.literal_chars->is_one_byte()) { | 1429 if (escaped && next_.literal_chars->is_one_byte()) { |
1383 Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); | 1430 Vector<const uint8_t> chars = next_.literal_chars->one_byte_literal(); |
1384 return KeywordOrIdentifierToken(chars.start(), chars.length(), true); | 1431 Token::Value token = |
| 1432 KeywordOrIdentifierToken(chars.start(), chars.length()); |
| 1433 /* TODO(adamk): YIELD should be handled specially. */ |
| 1434 if (token == Token::IDENTIFIER) { |
| 1435 return Token::IDENTIFIER; |
| 1436 } else if (token == Token::FUTURE_STRICT_RESERVED_WORD || |
| 1437 token == Token::LET || token == Token::STATIC) { |
| 1438 return Token::ESCAPED_STRICT_RESERVED_WORD; |
| 1439 } else { |
| 1440 return Token::ESCAPED_KEYWORD; |
| 1441 } |
1385 } | 1442 } |
1386 return Token::IDENTIFIER; | 1443 return Token::IDENTIFIER; |
1387 } | 1444 } |
1388 | 1445 |
| 1446 bool Scanner::ScanRegExpPattern() { |
| 1447 DCHECK(next_next_.token == Token::UNINITIALIZED); |
| 1448 DCHECK(next_.token == Token::DIV || next_.token == Token::ASSIGN_DIV); |
1389 | 1449 |
1390 bool Scanner::ScanRegExpPattern(bool seen_equal) { | |
1391 // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags | 1450 // Scan: ('/' | '/=') RegularExpressionBody '/' RegularExpressionFlags |
1392 bool in_character_class = false; | 1451 bool in_character_class = false; |
| 1452 bool seen_equal = (next_.token == Token::ASSIGN_DIV); |
1393 | 1453 |
1394 // Previous token is either '/' or '/=', in the second case, the | 1454 // Previous token is either '/' or '/=', in the second case, the |
1395 // pattern starts at =. | 1455 // pattern starts at =. |
1396 next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1); | 1456 next_.location.beg_pos = source_pos() - (seen_equal ? 2 : 1); |
1397 next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0); | 1457 next_.location.end_pos = source_pos() - (seen_equal ? 1 : 0); |
1398 | 1458 |
1399 // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5, | 1459 // Scan regular expression body: According to ECMA-262, 3rd, 7.8.5, |
1400 // the scanner should pass uninterpreted bodies to the RegExp | 1460 // the scanner should pass uninterpreted bodies to the RegExp |
1401 // constructor. | 1461 // constructor. |
1402 LiteralScope literal(this); | 1462 LiteralScope literal(this); |
(...skipping 19 matching lines...) Expand all Loading... |
1422 // octal esacpes in strict mode. | 1482 // octal esacpes in strict mode. |
1423 } else { // Unescaped character. | 1483 } else { // Unescaped character. |
1424 if (c0_ == '[') in_character_class = true; | 1484 if (c0_ == '[') in_character_class = true; |
1425 if (c0_ == ']') in_character_class = false; | 1485 if (c0_ == ']') in_character_class = false; |
1426 AddLiteralCharAdvance(); | 1486 AddLiteralCharAdvance(); |
1427 } | 1487 } |
1428 } | 1488 } |
1429 Advance(); // consume '/' | 1489 Advance(); // consume '/' |
1430 | 1490 |
1431 literal.Complete(); | 1491 literal.Complete(); |
1432 | 1492 next_.token = Token::REGEXP_LITERAL; |
1433 return true; | 1493 return true; |
1434 } | 1494 } |
1435 | 1495 |
1436 | 1496 |
1437 Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() { | 1497 Maybe<RegExp::Flags> Scanner::ScanRegExpFlags() { |
| 1498 DCHECK(next_.token == Token::REGEXP_LITERAL); |
| 1499 |
1438 // Scan regular expression flags. | 1500 // Scan regular expression flags. |
1439 LiteralScope literal(this); | |
1440 int flags = 0; | 1501 int flags = 0; |
1441 while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) { | 1502 while (c0_ >= 0 && unicode_cache_->IsIdentifierPart(c0_)) { |
1442 RegExp::Flags flag = RegExp::kNone; | 1503 RegExp::Flags flag = RegExp::kNone; |
1443 switch (c0_) { | 1504 switch (c0_) { |
1444 case 'g': | 1505 case 'g': |
1445 flag = RegExp::kGlobal; | 1506 flag = RegExp::kGlobal; |
1446 break; | 1507 break; |
1447 case 'i': | 1508 case 'i': |
1448 flag = RegExp::kIgnoreCase; | 1509 flag = RegExp::kIgnoreCase; |
1449 break; | 1510 break; |
1450 case 'm': | 1511 case 'm': |
1451 flag = RegExp::kMultiline; | 1512 flag = RegExp::kMultiline; |
1452 break; | 1513 break; |
1453 case 'u': | 1514 case 'u': |
1454 flag = RegExp::kUnicode; | 1515 flag = RegExp::kUnicode; |
1455 break; | 1516 break; |
1456 case 'y': | 1517 case 'y': |
1457 flag = RegExp::kSticky; | 1518 flag = RegExp::kSticky; |
1458 break; | 1519 break; |
1459 default: | 1520 default: |
1460 return Nothing<RegExp::Flags>(); | 1521 return Nothing<RegExp::Flags>(); |
1461 } | 1522 } |
1462 if (flags & flag) return Nothing<RegExp::Flags>(); | 1523 if (flags & flag) { |
1463 AddLiteralCharAdvance(); | 1524 return Nothing<RegExp::Flags>(); |
| 1525 } |
| 1526 Advance(); |
1464 flags |= flag; | 1527 flags |= flag; |
1465 } | 1528 } |
1466 literal.Complete(); | |
1467 | 1529 |
1468 next_.location.end_pos = source_pos(); | 1530 next_.location.end_pos = source_pos(); |
1469 return Just(RegExp::Flags(flags)); | 1531 return Just(RegExp::Flags(flags)); |
1470 } | 1532 } |
1471 | 1533 |
1472 | 1534 |
1473 const AstRawString* Scanner::CurrentSymbol(AstValueFactory* ast_value_factory) { | 1535 const AstRawString* Scanner::CurrentSymbol(AstValueFactory* ast_value_factory) { |
1474 if (is_literal_one_byte()) { | 1536 if (is_literal_one_byte()) { |
1475 return ast_value_factory->GetOneByteString(literal_one_byte_string()); | 1537 return ast_value_factory->GetOneByteString(literal_one_byte_string()); |
1476 } | 1538 } |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1703 backing_store_.Add(static_cast<uint8_t>((one_byte_length >> 7) | 0x80u)); | 1765 backing_store_.Add(static_cast<uint8_t>((one_byte_length >> 7) | 0x80u)); |
1704 } | 1766 } |
1705 backing_store_.Add(static_cast<uint8_t>(one_byte_length & 0x7f)); | 1767 backing_store_.Add(static_cast<uint8_t>(one_byte_length & 0x7f)); |
1706 | 1768 |
1707 backing_store_.AddBlock(bytes); | 1769 backing_store_.AddBlock(bytes); |
1708 return backing_store_.EndSequence().start(); | 1770 return backing_store_.EndSequence().start(); |
1709 } | 1771 } |
1710 | 1772 |
1711 } // namespace internal | 1773 } // namespace internal |
1712 } // namespace v8 | 1774 } // namespace v8 |
OLD | NEW |