| Index: src/scanner-base.cc
|
| ===================================================================
|
| --- src/scanner-base.cc (revision 6800)
|
| +++ src/scanner-base.cc (working copy)
|
| @@ -64,7 +64,8 @@
|
| // ----------------------------------------------------------------------------
|
| // Scanner
|
|
|
| -Scanner::Scanner() { }
|
| +Scanner::Scanner()
|
| + : octal_pos_(kNoOctalLocation) { }
|
|
|
|
|
| uc32 Scanner::ScanHexEscape(uc32 c, int length) {
|
| @@ -99,7 +100,8 @@
|
| // ECMA-262. Other JS VMs support them.
|
| uc32 Scanner::ScanOctalEscape(uc32 c, int length) {
|
| uc32 x = c - '0';
|
| - for (int i = 0; i < length; i++) {
|
| + int i = 0;
|
| + for (; i < length; i++) {
|
| int d = c0_ - '0';
|
| if (d < 0 || d > 7) break;
|
| int nx = x * 8 + d;
|
| @@ -107,6 +109,12 @@
|
| x = nx;
|
| Advance();
|
| }
|
| + // Anything excelt '\0' is an octal escape sequence, illegal in strict mode.
|
| + // Remember the position of octal escape sequences so that better error
|
| + // can be reported later (in strict mode).
|
| + if (c != '0' || i > 0) {
|
| + octal_pos_ = source_pos() - i - 1; // Already advanced
|
| + }
|
| return x;
|
| }
|
|
|
| @@ -601,7 +609,11 @@
|
| kind = DECIMAL;
|
| break;
|
| }
|
| - if (c0_ < '0' || '7' < c0_) break;
|
| + if (c0_ < '0' || '7' < c0_) {
|
| + // Octal literal finished.
|
| + octal_pos_ = next_.location.beg_pos;
|
| + break;
|
| + }
|
| AddLiteralCharAdvance();
|
| }
|
| }
|
| @@ -731,11 +743,18 @@
|
|
|
| while (c0_ != '/' || in_character_class) {
|
| if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
|
| - if (c0_ == '\\') { // escaped character
|
| + if (c0_ == '\\') { // Escape sequence.
|
| AddLiteralCharAdvance();
|
| if (ScannerConstants::kIsLineTerminator.get(c0_) || c0_ < 0) return false;
|
| AddLiteralCharAdvance();
|
| - } else { // unescaped character
|
| + // If the escape allows more characters, i.e., \x??, \u????, or \c?,
|
| + // only "safe" characters are allowed (letters, digits, underscore),
|
| + // otherwise the escape isn't valid and the invalid character has
|
| + // its normal meaning. I.e., we can just continue scanning without
|
| + // worrying whether the following characters are part of the escape
|
| + // or not, since any '/', '\\' or '[' is guaranteed to not be part
|
| + // of the escape sequence.
|
| + } else { // Unescaped character.
|
| if (c0_ == '[') in_character_class = true;
|
| if (c0_ == ']') in_character_class = false;
|
| AddLiteralCharAdvance();
|
| @@ -777,25 +796,27 @@
|
| { "break", KEYWORD_PREFIX, Token::BREAK },
|
| { NULL, C, Token::ILLEGAL },
|
| { NULL, D, Token::ILLEGAL },
|
| - { "else", KEYWORD_PREFIX, Token::ELSE },
|
| + { NULL, E, Token::ILLEGAL },
|
| { NULL, F, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| { NULL, I, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| + { "let", KEYWORD_PREFIX, Token::FUTURE_RESERVED_WORD },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| - { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| { NULL, N, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| + { NULL, P, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| - { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| { "return", KEYWORD_PREFIX, Token::RETURN },
|
| - { "switch", KEYWORD_PREFIX, Token::SWITCH },
|
| + { NULL, S, Token::ILLEGAL },
|
| { NULL, T, Token::ILLEGAL },
|
| { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| { NULL, V, Token::ILLEGAL },
|
| - { NULL, W, Token::ILLEGAL }
|
| + { NULL, W, Token::ILLEGAL },
|
| + { NULL, UNMATCHABLE, Token::ILLEGAL },
|
| + { "yield", KEYWORD_PREFIX, Token::FUTURE_RESERVED_WORD }
|
| };
|
|
|
|
|
| @@ -803,7 +824,7 @@
|
| switch (state_) {
|
| case INITIAL: {
|
| // matching the first character is the only state with significant fanout.
|
| - // Match only lower-case letters in range 'b'..'w'.
|
| + // Match only lower-case letters in range 'b'..'y'.
|
| unsigned int offset = input - kFirstCharRangeMin;
|
| if (offset < kFirstCharRangeLength) {
|
| state_ = first_states_[offset].state;
|
| @@ -831,6 +852,8 @@
|
| break;
|
| case C:
|
| if (MatchState(input, 'a', CA)) return;
|
| + if (MatchKeywordStart(input, "class", 1,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| if (MatchState(input, 'o', CO)) return;
|
| break;
|
| case CA:
|
| @@ -853,6 +876,18 @@
|
| if (MatchKeywordStart(input, "default", 2, Token::DEFAULT)) return;
|
| if (MatchKeywordStart(input, "delete", 2, Token::DELETE)) return;
|
| break;
|
| + case E:
|
| + if (MatchKeywordStart(input, "else", 1, Token::ELSE)) return;
|
| + if (MatchKeywordStart(input, "enum", 1,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + if (MatchState(input, 'x', EX)) return;
|
| + break;
|
| + case EX:
|
| + if (MatchKeywordStart(input, "export", 2,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + if (MatchKeywordStart(input, "extends", 2,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + break;
|
| case F:
|
| if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
|
| if (MatchKeywordStart(input, "finally", 1, Token::FINALLY)) return;
|
| @@ -861,10 +896,22 @@
|
| break;
|
| case I:
|
| if (MatchKeyword(input, 'f', KEYWORD_MATCHED, Token::IF)) return;
|
| + if (MatchState(input, 'm', IM)) return;
|
| if (MatchKeyword(input, 'n', IN, Token::IN)) return;
|
| break;
|
| + case IM:
|
| + if (MatchState(input, 'p', IMP)) return;
|
| + break;
|
| + case IMP:
|
| + if (MatchKeywordStart(input, "implements", 3,
|
| + Token::FUTURE_RESERVED_WORD )) return;
|
| + if (MatchKeywordStart(input, "import", 3,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + break;
|
| case IN:
|
| token_ = Token::IDENTIFIER;
|
| + if (MatchKeywordStart(input, "interface", 2,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) return;
|
| break;
|
| case N:
|
| @@ -872,6 +919,27 @@
|
| if (MatchKeywordStart(input, "new", 1, Token::NEW)) return;
|
| if (MatchKeywordStart(input, "null", 1, Token::NULL_LITERAL)) return;
|
| break;
|
| + case P:
|
| + if (MatchKeywordStart(input, "package", 1,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + if (MatchState(input, 'r', PR)) return;
|
| + if (MatchKeywordStart(input, "public", 1,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + break;
|
| + case PR:
|
| + if (MatchKeywordStart(input, "private", 2,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + if (MatchKeywordStart(input, "protected", 2,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + break;
|
| + case S:
|
| + if (MatchKeywordStart(input, "static", 1,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + if (MatchKeywordStart(input, "super", 1,
|
| + Token::FUTURE_RESERVED_WORD)) return;
|
| + if (MatchKeywordStart(input, "switch", 1,
|
| + Token::SWITCH)) return;
|
| + break;
|
| case T:
|
| if (MatchState(input, 'h', TH)) return;
|
| if (MatchState(input, 'r', TR)) return;
|
|
|