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