Revision: 6653
Author: [email protected]
Date: Fri Feb  4 10:36:37 2011
Log: Issue 117 - strict mode and future reserved words
http://code.google.com/p/v8/source/detail?r=6653

Modified:
 /branches/bleeding_edge/src/messages.js
 /branches/bleeding_edge/src/parser.cc
 /branches/bleeding_edge/src/parser.h
 /branches/bleeding_edge/src/preparser.cc
 /branches/bleeding_edge/src/preparser.h
 /branches/bleeding_edge/src/scanner-base.cc
 /branches/bleeding_edge/src/scanner-base.h
 /branches/bleeding_edge/src/token.h
 /branches/bleeding_edge/test/mjsunit/strict-mode.js

=======================================
--- /branches/bleeding_edge/src/messages.js     Thu Feb  3 06:02:13 2011
+++ /branches/bleeding_edge/src/messages.js     Fri Feb  4 10:36:37 2011
@@ -147,6 +147,7 @@
       unexpected_token_number:      ["Unexpected number"],
       unexpected_token_string:      ["Unexpected string"],
       unexpected_token_identifier:  ["Unexpected identifier"],
+ unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
       unexpected_eos:               ["Unexpected end of input"],
malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"], unterminated_regexp: ["Invalid regular expression: missing /"],
@@ -221,6 +222,7 @@
strict_lhs_assignment: ["Assignment to eval or arguments is not allowed in strict mode"], strict_lhs_postfix: ["Postfix increment/decrement may not have eval or arguments operand in strict mode"], strict_lhs_prefix: ["Prefix increment/decrement may not have eval or arguments operand in strict mode"], + strict_reserved_word: ["Use of future reserved word in strict mode"],
     };
   }
   var message_type = %MessageGetType(message);
=======================================
--- /branches/bleeding_edge/src/parser.cc       Fri Feb  4 10:15:49 2011
+++ /branches/bleeding_edge/src/parser.cc       Fri Feb  4 10:36:37 2011
@@ -759,7 +759,9 @@
     FunctionLiteralType type =
         info->is_expression() ? EXPRESSION : DECLARATION;
     bool ok = true;
-    result = ParseFunctionLiteral(name, RelocInfo::kNoPosition, type, &ok);
+    result = ParseFunctionLiteral(name,
+ false, // Strict mode name already checked.
+                                  RelocInfo::kNoPosition, type, &ok);
     // Make sure the results agree.
     ASSERT(ok == (result != NULL));
     // The only errors should be stack overflows.
@@ -1448,8 +1450,10 @@
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
   Expect(Token::FUNCTION, CHECK_OK);
   int function_token_position = scanner().location().beg_pos;
-  Handle<String> name = ParseIdentifier(CHECK_OK);
+  bool is_reserved = false;
+ Handle<String> name = ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
   FunctionLiteral* fun = ParseFunctionLiteral(name,
+                                              is_reserved,
                                               function_token_position,
                                               DECLARATION,
                                               CHECK_OK);
@@ -1708,7 +1712,7 @@
   // ExpressionStatement | LabelledStatement ::
   //   Expression ';'
   //   Identifier ':' Statement
-  bool starts_with_idenfifier = (peek() == Token::IDENTIFIER);
+  bool starts_with_idenfifier = peek_any_identifier();
   Expression* expr = ParseExpression(true, CHECK_OK);
   if (peek() == Token::COLON && starts_with_idenfifier && expr &&
       expr->AsVariableProxy() != NULL &&
@@ -2697,9 +2701,12 @@
     Expect(Token::FUNCTION, CHECK_OK);
     int function_token_position = scanner().location().beg_pos;
     Handle<String> name;
-    if (peek() == Token::IDENTIFIER) name = ParseIdentifier(CHECK_OK);
-    result = ParseFunctionLiteral(name, function_token_position,
-                                  NESTED, CHECK_OK);
+    bool is_reserved_name = false;
+    if (peek_any_identifier()) {
+        name = ParseIdentifierOrReservedWord(&is_reserved_name, CHECK_OK);
+    }
+    result = ParseFunctionLiteral(name, is_reserved_name,
+ function_token_position, NESTED, CHECK_OK);
   } else {
     result = ParsePrimaryExpression(CHECK_OK);
   }
@@ -2768,6 +2775,11 @@
     case Token::IDENTIFIER:
       return ReportMessage("unexpected_token_identifier",
                            Vector<const char*>::empty());
+    case Token::FUTURE_RESERVED_WORD:
+      return ReportMessage(temp_scope_->StrictMode() ?
+                               "unexpected_strict_reserved" :
+                               "unexpected_token_identifier",
+                           Vector<const char*>::empty());
     default:
       const char* name = Token::String(token);
       ASSERT(name != NULL);
@@ -2823,7 +2835,8 @@
       result = new Literal(Factory::false_value());
       break;

-    case Token::IDENTIFIER: {
+    case Token::IDENTIFIER:
+    case Token::FUTURE_RESERVED_WORD: {
       Handle<String> name = ParseIdentifier(CHECK_OK);
       if (fni_ != NULL) fni_->PushVariableName(name);
       result = top_scope_->NewUnresolved(name, inside_with());
@@ -3230,6 +3243,7 @@
   Token::Value next = Next();
   bool is_keyword = Token::IsKeyword(next);
   if (next == Token::IDENTIFIER || next == Token::NUMBER ||
+      next == Token::FUTURE_RESERVED_WORD ||
       next == Token::STRING || is_keyword) {
     Handle<String> name;
     if (is_keyword) {
@@ -3239,6 +3253,7 @@
     }
     FunctionLiteral* value =
         ParseFunctionLiteral(name,
+                             false,   // reserved words are allowed here
                              RelocInfo::kNoPosition,
                              DECLARATION,
                              CHECK_OK);
@@ -3281,6 +3296,7 @@
     Scanner::Location loc = scanner().peek_location();

     switch (next) {
+      case Token::FUTURE_RESERVED_WORD:
       case Token::IDENTIFIER: {
         bool is_getter = false;
         bool is_setter = false;
@@ -3429,6 +3445,7 @@


 FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
+                                              bool name_is_reserved,
                                               int function_token_position,
                                               FunctionLiteralType type,
                                               bool* ok) {
@@ -3462,10 +3479,13 @@
     int start_pos = scanner().location().beg_pos;
     Scanner::Location name_loc = Scanner::NoLocation();
     Scanner::Location dupe_loc = Scanner::NoLocation();
+    Scanner::Location reserved_loc = Scanner::NoLocation();

     bool done = (peek() == Token::RPAREN);
     while (!done) {
-      Handle<String> param_name = ParseIdentifier(CHECK_OK);
+      bool is_reserved = false;
+      Handle<String> param_name =
+          ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);

       // Store locations for possible future error reports.
       if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
@@ -3474,6 +3494,9 @@
       if (!dupe_loc.IsValid() && top_scope_->IsDeclared(param_name)) {
         dupe_loc = scanner().location();
       }
+      if (!reserved_loc.IsValid() && is_reserved) {
+        reserved_loc = scanner().location();
+      }

Variable* parameter = top_scope_->DeclareLocal(param_name, Variable::VAR);
       top_scope_->AddParameter(parameter);
@@ -3554,7 +3577,8 @@
         int position = function_token_position != RelocInfo::kNoPosition
             ? function_token_position
             : (start_pos > 0 ? start_pos - 1 : start_pos);
-        ReportMessageAt(Scanner::Location(position, start_pos),
+ Scanner::Location location = Scanner::Location(position, start_pos);
+        ReportMessageAt(location,
"strict_function_name", Vector<const char*>::empty());
         *ok = false;
         return NULL;
@@ -3571,6 +3595,22 @@
         *ok = false;
         return NULL;
       }
+      if (name_is_reserved) {
+        int position = function_token_position != RelocInfo::kNoPosition
+            ? function_token_position
+            : (start_pos > 0 ? start_pos - 1 : start_pos);
+ Scanner::Location location = Scanner::Location(position, start_pos);
+        ReportMessageAt(location, "strict_reserved_word",
+                        Vector<const char*>::empty());
+        *ok = false;
+        return NULL;
+      }
+      if (reserved_loc.IsValid()) {
+        ReportMessageAt(reserved_loc, "strict_reserved_word",
+                        Vector<const char*>::empty());
+        *ok = false;
+        return NULL;
+      }
       CheckOctalLiteral(start_pos, end_pos, CHECK_OK);
     }

@@ -3640,6 +3680,13 @@
   // We have a valid intrinsics call or a call to a builtin.
   return new CallRuntime(name, function, args);
 }
+
+
+bool Parser::peek_any_identifier() {
+  Token::Value next = peek();
+  return next == Token::IDENTIFIER ||
+         next == Token::FUTURE_RESERVED_WORD;
+}


 void Parser::Consume(Token::Value token) {
@@ -3701,7 +3748,22 @@


 Handle<String> Parser::ParseIdentifier(bool* ok) {
-  Expect(Token::IDENTIFIER, ok);
+  bool is_reserved;
+  return ParseIdentifierOrReservedWord(&is_reserved, ok);
+}
+
+
+Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
+                                                     bool* ok) {
+  *is_reserved = false;
+  if (temp_scope_->StrictMode()) {
+    Expect(Token::IDENTIFIER, ok);
+  } else {
+    if (!Check(Token::IDENTIFIER)) {
+      Expect(Token::FUTURE_RESERVED_WORD, ok);
+      *is_reserved = true;
+    }
+  }
   if (!*ok) return Handle<String>();
   return GetSymbol(ok);
 }
@@ -3709,7 +3771,9 @@

 Handle<String> Parser::ParseIdentifierName(bool* ok) {
   Token::Value next = Next();
-  if (next != Token::IDENTIFIER && !Token::IsKeyword(next)) {
+  if (next != Token::IDENTIFIER &&
+          next != Token::FUTURE_RESERVED_WORD &&
+          !Token::IsKeyword(next)) {
     ReportUnexpectedToken(next);
     *ok = false;
     return Handle<String>();
@@ -3749,20 +3813,18 @@


 // This function reads an identifier and determines whether or not it
-// is 'get' or 'set'.  The reason for not using ParseIdentifier and
-// checking on the output is that this involves heap allocation which
-// we can't do during preparsing.
+// is 'get' or 'set'.
 Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
                                                  bool* is_set,
                                                  bool* ok) {
-  Expect(Token::IDENTIFIER, ok);
+  Handle<String> result = ParseIdentifier(ok);
   if (!*ok) return Handle<String>();
   if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
     const char* token = scanner().literal_ascii_string().start();
     *is_get = strncmp(token, "get", 3) == 0;
     *is_set = !*is_get && strncmp(token, "set", 3) == 0;
   }
-  return GetSymbol(ok);
+  return result;
 }


@@ -3904,6 +3966,7 @@
           message = "unexpected_token_string";
           break;
         case Token::IDENTIFIER:
+        case Token::FUTURE_RESERVED_WORD:
           message = "unexpected_token_identifier";
           break;
         default:
=======================================
--- /branches/bleeding_edge/src/parser.h        Fri Feb  4 10:15:49 2011
+++ /branches/bleeding_edge/src/parser.h        Fri Feb  4 10:36:37 2011
@@ -548,6 +548,7 @@

   ZoneList<Expression*>* ParseArguments(bool* ok);
   FunctionLiteral* ParseFunctionLiteral(Handle<String> var_name,
+                                        bool name_is_reserved,
                                         int function_token_position,
                                         FunctionLiteralType type,
                                         bool* ok);
@@ -576,6 +577,8 @@
     }
     return scanner().Next();
   }
+
+  bool peek_any_identifier();

   INLINE(void Consume(Token::Value token));
   void Expect(Token::Value token, bool* ok);
@@ -610,6 +613,7 @@
   Literal* GetLiteralNumber(double value);

   Handle<String> ParseIdentifier(bool* ok);
+ Handle<String> ParseIdentifierOrReservedWord(bool* is_reserved, bool* ok);
   Handle<String> ParseIdentifierName(bool* ok);
   Handle<String> ParseIdentifierOrGetOrSet(bool* is_get,
                                            bool* is_set,
=======================================
--- /branches/bleeding_edge/src/preparser.cc    Fri Jan 14 02:50:13 2011
+++ /branches/bleeding_edge/src/preparser.cc    Fri Feb  4 10:36:37 2011
@@ -83,6 +83,7 @@
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
                            "unexpected_token_string", NULL);
   case i::Token::IDENTIFIER:
+  case i::Token::FUTURE_RESERVED_WORD:
return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
                            "unexpected_token_identifier", NULL);
   default:
@@ -790,7 +791,7 @@
   Expression result = kUnknownExpression;
   if (peek() == i::Token::FUNCTION) {
     Consume(i::Token::FUNCTION);
-    if (peek() == i::Token::IDENTIFIER) {
+    if (peek_any_identifier()) {
       ParseIdentifier(CHECK_OK);
     }
     result = ParseFunctionLiteral(CHECK_OK);
@@ -858,7 +859,8 @@
       break;
     }

-    case i::Token::IDENTIFIER: {
+    case i::Token::IDENTIFIER:
+    case i::Token::FUTURE_RESERVED_WORD: {
       ParseIdentifier(CHECK_OK);
       result = kIdentifierExpression;
       break;
@@ -946,7 +948,8 @@
   while (peek() != i::Token::RBRACE) {
     i::Token::Value next = peek();
     switch (next) {
-      case i::Token::IDENTIFIER: {
+      case i::Token::IDENTIFIER:
+      case i::Token::FUTURE_RESERVED_WORD: {
         bool is_getter = false;
         bool is_setter = false;
         ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
@@ -954,6 +957,7 @@
             i::Token::Value name = Next();
             bool is_keyword = i::Token::IsKeyword(name);
             if (name != i::Token::IDENTIFIER &&
+                name != i::Token::FUTURE_RESERVED_WORD &&
                 name != i::Token::NUMBER &&
                 name != i::Token::STRING &&
                 !is_keyword) {
@@ -1151,7 +1155,9 @@


 PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
-  Expect(i::Token::IDENTIFIER, ok);
+  if (!Check(i::Token::FUTURE_RESERVED_WORD)) {
+    Expect(i::Token::IDENTIFIER, ok);
+  }
   if (!*ok) return kUnknownIdentifier;
   return GetIdentifierSymbol();
 }
@@ -1166,7 +1172,8 @@
i::StrLength(keyword)));
     return kUnknownExpression;
   }
-  if (next == i::Token::IDENTIFIER) {
+  if (next == i::Token::IDENTIFIER ||
+      next == i::Token::FUTURE_RESERVED_WORD) {
     return GetIdentifierSymbol();
   }
   *ok = false;
@@ -1175,19 +1182,23 @@


 // This function reads an identifier and determines whether or not it
-// is 'get' or 'set'.  The reason for not using ParseIdentifier and
-// checking on the output is that this involves heap allocation which
-// we can't do during preparsing.
+// is 'get' or 'set'.
 PreParser::Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
                                                            bool* is_set,
                                                            bool* ok) {
-  Expect(i::Token::IDENTIFIER, CHECK_OK);
+  PreParser::Identifier result = ParseIdentifier(CHECK_OK);
   if (scanner_->is_literal_ascii() && scanner_->literal_length() == 3) {
     const char* token = scanner_->literal_ascii_string().start();
     *is_get = strncmp(token, "get", 3) == 0;
     *is_set = !*is_get && strncmp(token, "set", 3) == 0;
   }
-  return GetIdentifierSymbol();
+  return result;
+}
+
+bool PreParser::peek_any_identifier() {
+  i::Token::Value next = peek();
+  return next == i::Token::IDENTIFIER ||
+         next == i::Token::FUTURE_RESERVED_WORD;
 }

 #undef CHECK_OK
=======================================
--- /branches/bleeding_edge/src/preparser.h     Fri Jan 14 02:50:13 2011
+++ /branches/bleeding_edge/src/preparser.h     Fri Feb  4 10:36:37 2011
@@ -242,6 +242,8 @@
     }
     return scanner_->Next();
   }
+
+  bool peek_any_identifier();

   void Consume(i::Token::Value token) { Next(); }

=======================================
--- /branches/bleeding_edge/src/scanner-base.cc Mon Jan 31 14:35:27 2011
+++ /branches/bleeding_edge/src/scanner-base.cc Fri Feb  4 10:36:37 2011
@@ -796,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 },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { "let",    KEYWORD_PREFIX, Token::FUTURE_RESERVED_WORD },
   { NULL,     UNMATCHABLE,    Token::ILLEGAL },
   { NULL,     N,              Token::ILLEGAL },
   { NULL,     UNMATCHABLE,    Token::ILLEGAL },
-  { NULL,     UNMATCHABLE,    Token::ILLEGAL },
+  { NULL,     P,              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 }
 };


@@ -822,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;
@@ -850,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:
@@ -872,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;
@@ -880,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:
@@ -891,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;
=======================================
--- /branches/bleeding_edge/src/scanner-base.h  Mon Jan 31 14:35:27 2011
+++ /branches/bleeding_edge/src/scanner-base.h  Fri Feb  4 10:36:37 2011
@@ -564,10 +564,17 @@
     CON,
     D,
     DE,
+    E,
+    EX,
     F,
     I,
+    IM,
+    IMP,
     IN,
     N,
+    P,
+    PR,
+    S,
     T,
     TH,
     TR,
@@ -583,7 +590,7 @@

   // Range of possible first characters of a keyword.
   static const unsigned int kFirstCharRangeMin = 'b';
-  static const unsigned int kFirstCharRangeMax = 'w';
+  static const unsigned int kFirstCharRangeMax = 'y';
   static const unsigned int kFirstCharRangeLength =
       kFirstCharRangeMax - kFirstCharRangeMin + 1;
   // State map for first keyword character range.
=======================================
--- /branches/bleeding_edge/src/token.h Wed Jan 12 03:56:41 2011
+++ /branches/bleeding_edge/src/token.h Fri Feb  4 10:36:37 2011
@@ -155,38 +155,6 @@
   K(WHILE, "while", 0)                                                  \
   K(WITH, "with", 0)                                                    \
                                                                         \
-  /* Future reserved words (ECMA-262, section 7.5.3, page 14). */       \
-  F(ABSTRACT, "abstract", 0)                                            \
-  F(BOOLEAN, "boolean", 0)                                              \
-  F(BYTE, "byte", 0)                                                    \
-  F(CHAR, "char", 0)                                                    \
-  F(CLASS, "class", 0)                                                  \
-  K(CONST, "const", 0)                                                  \
-  F(DOUBLE, "double", 0)                                                \
-  F(ENUM, "enum", 0)                                                    \
-  F(EXPORT, "export", 0)                                                \
-  F(EXTENDS, "extends", 0)                                              \
-  F(FINAL, "final", 0)                                                  \
-  F(FLOAT, "float", 0)                                                  \
-  F(GOTO, "goto", 0)                                                    \
-  F(IMPLEMENTS, "implements", 0)                                        \
-  F(IMPORT, "import", 0)                                                \
-  F(INT, "int", 0)                                                      \
-  F(INTERFACE, "interface", 0)                                          \
-  F(LONG, "long", 0)                                                    \
-  K(NATIVE, "native", 0)                                                \
-  F(PACKAGE, "package", 0)                                              \
-  F(PRIVATE, "private", 0)                                              \
-  F(PROTECTED, "protected", 0)                                          \
-  F(PUBLIC, "public", 0)                                                \
-  F(SHORT, "short", 0)                                                  \
-  F(STATIC, "static", 0)                                                \
-  F(SUPER, "super", 0)                                                  \
-  F(SYNCHRONIZED, "synchronized", 0)                                    \
-  F(THROWS, "throws", 0)                                                \
-  F(TRANSIENT, "transient", 0)                                          \
-  F(VOLATILE, "volatile", 0)                                            \
-                                                                        \
   /* Literals (ECMA-262, section 7.8, page 16). */                      \
   K(NULL_LITERAL, "null", 0)                                            \
   K(TRUE_LITERAL, "true", 0)                                            \
@@ -197,6 +165,11 @@
   /* Identifiers (not keywords or future reserved words). */            \
   T(IDENTIFIER, NULL, 0)                                                \
                                                                         \
+  /* Future reserved words (ECMA-262, section 7.6.1.2). */              \
+  T(FUTURE_RESERVED_WORD, NULL, 0)                                      \
+  K(CONST, "const", 0)                                                  \
+  K(NATIVE, "native", 0)                                                \
+                                                                        \
   /* Illegal token - not able to scan. */                               \
   T(ILLEGAL, "ILLEGAL", 0)                                              \
                                                                         \
=======================================
--- /branches/bleeding_edge/test/mjsunit/strict-mode.js Mon Jan 31 14:35:27 2011 +++ /branches/bleeding_edge/test/mjsunit/strict-mode.js Fri Feb 4 10:36:37 2011
@@ -271,3 +271,68 @@
   var y = [void arguments, typeof arguments,
            +arguments, -arguments, ~arguments, !arguments];
 })();
+
+// 7.6.1.2 Future Reserved Words
+var future_reserved_words = [
+  "class",
+  "enum",
+  "export",
+  "extends",
+  "import",
+  "super",
+  "implements",
+  "interface",
+  "let",
+  "package",
+  "private",
+  "protected",
+  "public",
+  "static",
+  "yield" ];
+
+function testFutureReservedWord(word) {
+  // Simple use of each reserved word
+  CheckStrictMode("var " + word + " = 1;", SyntaxError);
+
+  // object literal properties
+  eval("var x = { " + word + " : 42 };");
+  eval("var x = { get " + word + " () {} };");
+  eval("var x = { set " + word + " (value) {} };");
+
+  // object literal with string literal property names
+  eval("var x = { '" + word + "' : 42 };");
+  eval("var x = { get '" + word + "' () { } };");
+  eval("var x = { set '" + word + "' (value) { } };");
+  eval("var x = { get '" + word + "' () { 'use strict'; } };");
+  eval("var x = { set '" + word + "' (value) { 'use strict'; } };");
+
+  // Function names and arguments, strict and non-strict contexts
+  CheckStrictMode("function " + word + " () {}", SyntaxError);
+  CheckStrictMode("function foo (" + word + ") {}", SyntaxError);
+ CheckStrictMode("function foo (" + word + ", " + word + ") {}", SyntaxError);
+  CheckStrictMode("function foo (a, " + word + ") {}", SyntaxError);
+  CheckStrictMode("function foo (" + word + ", a) {}", SyntaxError);
+  CheckStrictMode("function foo (a, " + word + ", b) {}", SyntaxError);
+  CheckStrictMode("var foo = function (" + word + ") {}", SyntaxError);
+
+  // Function names and arguments when the body is strict
+  assertThrows("function " + word + " () { 'use strict'; }", SyntaxError);
+ assertThrows("function foo (" + word + ") 'use strict'; {}", SyntaxError); + assertThrows("function foo (" + word + ", " + word + ") { 'use strict'; }", SyntaxError); + assertThrows("function foo (a, " + word + ") { 'use strict'; }", SyntaxError); + assertThrows("function foo (" + word + ", a) { 'use strict'; }", SyntaxError); + assertThrows("function foo (a, " + word + ", b) { 'use strict'; }", SyntaxError); + assertThrows("var foo = function (" + word + ") { 'use strict'; }", SyntaxError);
+
+  // get/set when the body is strict
+  eval("var x = { get " + word + " () { 'use strict'; } };");
+  eval("var x = { set " + word + " (value) { 'use strict'; } };");
+ assertThrows("var x = { get foo(" + word + ") { 'use strict'; } };", SyntaxError); + assertThrows("var x = { set foo(" + word + ") { 'use strict'; } };", SyntaxError);
+}
+
+for (var i = 0; i < future_reserved_words.length; i++) {
+  testFutureReservedWord(future_reserved_words[i]);
+}
+
+

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to