unexpected_token_number: ["Unexpected number"],
unexpected_token_string: ["Unexpected string"],
unexpected_token_identifier: ["Unexpected identifier"],
+ unexpected_reserved: ["Unexpected reserved word"],
unexpected_strict_reserved: ["Unexpected strict mode reserved word"],
unexpected_eos: ["Unexpected end of input"],
malformed_regexp: ["Invalid regular expression: /", "%0", "/: ", "%1"],
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
- bool is_reserved = false;
- Handle<String> name = ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
+ bool is_strict_reserved = false;
+ Handle<String> name = ParseIdentifierOrStrictReservedWord(
+ &is_strict_reserved, CHECK_OK);
FunctionLiteral* fun = ParseFunctionLiteral(name,
- is_reserved,
+ is_strict_reserved,
function_token_position,
DECLARATION,
CHECK_OK);
Expect(Token::FUNCTION, CHECK_OK);
int function_token_position = scanner().location().beg_pos;
Handle<String> name;
- bool is_reserved_name = false;
+ bool is_strict_reserved_name = false;
if (peek_any_identifier()) {
- name = ParseIdentifierOrReservedWord(&is_reserved_name, CHECK_OK);
+ name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved_name,
+ CHECK_OK);
}
- result = ParseFunctionLiteral(name, is_reserved_name,
+ result = ParseFunctionLiteral(name, is_strict_reserved_name,
function_token_position, NESTED, CHECK_OK);
} else {
result = ParsePrimaryExpression(CHECK_OK);
return ReportMessage("unexpected_token_identifier",
Vector<const char*>::empty());
case Token::FUTURE_RESERVED_WORD:
+ return ReportMessage("unexpected_reserved",
+ Vector<const char*>::empty());
+ case Token::FUTURE_STRICT_RESERVED_WORD:
return ReportMessage(top_scope_->is_strict_mode() ?
"unexpected_strict_reserved" :
"unexpected_token_identifier",
break;
case Token::IDENTIFIER:
- case Token::FUTURE_RESERVED_WORD: {
+ case Token::FUTURE_STRICT_RESERVED_WORD: {
Handle<String> name = ParseIdentifier(CHECK_OK);
if (fni_ != NULL) fni_->PushVariableName(name);
result = top_scope_->NewUnresolved(name,
bool is_keyword = Token::IsKeyword(next);
if (next == Token::IDENTIFIER || next == Token::NUMBER ||
next == Token::FUTURE_RESERVED_WORD ||
+ next == Token::FUTURE_STRICT_RESERVED_WORD ||
next == Token::STRING || is_keyword) {
Handle<String> name;
if (is_keyword) {
switch (next) {
case Token::FUTURE_RESERVED_WORD:
+ case Token::FUTURE_STRICT_RESERVED_WORD:
case Token::IDENTIFIER: {
bool is_getter = false;
bool is_setter = false;
Handle<String> id =
- ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+ ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
if (fni_ != NULL) fni_->PushLiteralName(id);
if ((is_getter || is_setter) && peek() != Token::COLON) {
FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> var_name,
- bool name_is_reserved,
+ bool name_is_strict_reserved,
int function_token_position,
FunctionLiteralType type,
bool* ok) {
bool done = (peek() == Token::RPAREN);
while (!done) {
- bool is_reserved = false;
+ bool is_strict_reserved = false;
Handle<String> param_name =
- ParseIdentifierOrReservedWord(&is_reserved, CHECK_OK);
+ ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
+ CHECK_OK);
// Store locations for possible future error reports.
if (!name_loc.IsValid() && IsEvalOrArguments(param_name)) {
has_duplicate_parameters = true;
dupe_loc = scanner().location();
}
- if (!reserved_loc.IsValid() && is_reserved) {
+ if (!reserved_loc.IsValid() && is_strict_reserved) {
reserved_loc = scanner().location();
}
*ok = false;
return NULL;
}
- if (name_is_reserved) {
+ if (name_is_strict_reserved) {
int position = function_token_position != RelocInfo::kNoPosition
? function_token_position
: (start_pos > 0 ? start_pos - 1 : start_pos);
bool Parser::peek_any_identifier() {
Token::Value next = peek();
return next == Token::IDENTIFIER ||
- next == Token::FUTURE_RESERVED_WORD;
+ next == Token::FUTURE_RESERVED_WORD ||
+ next == Token::FUTURE_STRICT_RESERVED_WORD;
}
}
+// Parses and identifier that is valid for the current scope, in particular it
+// fails on strict mode future reserved keywords in a strict scope.
Handle<String> Parser::ParseIdentifier(bool* ok) {
- bool is_reserved;
- return ParseIdentifierOrReservedWord(&is_reserved, ok);
+ if (top_scope_->is_strict_mode()) {
+ Expect(Token::IDENTIFIER, ok);
+ } else if (!Check(Token::IDENTIFIER)) {
+ Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
+ }
+ if (!*ok) return Handle<String>();
+ return GetSymbol(ok);
}
-Handle<String> Parser::ParseIdentifierOrReservedWord(bool* is_reserved,
- bool* ok) {
- *is_reserved = false;
- if (top_scope_->is_strict_mode()) {
- Expect(Token::IDENTIFIER, ok);
- } else {
- if (!Check(Token::IDENTIFIER)) {
- Expect(Token::FUTURE_RESERVED_WORD, ok);
- *is_reserved = true;
- }
+// Parses and identifier or a strict mode future reserved word, and indicate
+// whether it is strict mode future reserved.
+Handle<String> Parser::ParseIdentifierOrStrictReservedWord(
+ bool* is_strict_reserved, bool* ok) {
+ *is_strict_reserved = false;
+ if (!Check(Token::IDENTIFIER)) {
+ Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok);
+ *is_strict_reserved = true;
}
if (!*ok) return Handle<String>();
return GetSymbol(ok);
Handle<String> Parser::ParseIdentifierName(bool* ok) {
Token::Value next = Next();
if (next != Token::IDENTIFIER &&
- next != Token::FUTURE_RESERVED_WORD &&
- !Token::IsKeyword(next)) {
+ next != Token::FUTURE_RESERVED_WORD &&
+ next != Token::FUTURE_STRICT_RESERVED_WORD &&
+ !Token::IsKeyword(next)) {
ReportUnexpectedToken(next);
*ok = false;
return Handle<String>();
}
-// This function reads an identifier and determines whether or not it
+// This function reads an identifier name and determines whether or not it
// is 'get' or 'set'.
-Handle<String> Parser::ParseIdentifierOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok) {
- Handle<String> result = ParseIdentifier(ok);
+Handle<String> Parser::ParseIdentifierNameOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok) {
+ Handle<String> result = ParseIdentifierName(ok);
if (!*ok) return Handle<String>();
if (scanner().is_literal_ascii() && scanner().literal_length() == 3) {
const char* token = scanner().literal_ascii_string().start();
Literal* GetLiteralNumber(double value);
Handle<String> ParseIdentifier(bool* ok);
- Handle<String> ParseIdentifierOrReservedWord(bool* is_reserved, bool* ok);
+ Handle<String> ParseIdentifierOrStrictReservedWord(
+ bool* is_strict_reserved, bool* ok);
Handle<String> ParseIdentifierName(bool* ok);
- Handle<String> ParseIdentifierOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok);
+ Handle<String> ParseIdentifierNameOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok);
// Strict mode validation of LValue expressions
void CheckStrictModeLValue(Expression* expression,
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);
+ case i::Token::FUTURE_RESERVED_WORD:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_reserved", NULL);
+ case i::Token::FUTURE_STRICT_RESERVED_WORD:
+ return ReportMessageAt(source_location.beg_pos, source_location.end_pos,
+ "unexpected_strict_reserved", NULL);
default:
const char* name = i::Token::String(token);
ReportMessageAt(source_location.beg_pos, source_location.end_pos,
// Strict mode violation, using either reserved word or eval/arguments
// as name of strict function.
const char* type = "strict_function_name";
- if (identifier.IsFutureReserved()) {
+ if (identifier.IsFutureStrictReserved()) {
type = "strict_reserved_word";
}
ReportMessageAt(location.beg_pos, location.end_pos, type, NULL);
break;
}
- case i::Token::FUTURE_RESERVED_WORD:
+ case i::Token::FUTURE_RESERVED_WORD: {
+ Next();
+ i::Scanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "reserved_word", NULL);
+ *ok = false;
+ return Expression::Default();
+ }
+
+ case i::Token::FUTURE_STRICT_RESERVED_WORD:
if (strict_mode()) {
Next();
i::Scanner::Location location = scanner_->location();
i::Token::Value next = peek();
switch (next) {
case i::Token::IDENTIFIER:
- case i::Token::FUTURE_RESERVED_WORD: {
+ case i::Token::FUTURE_RESERVED_WORD:
+ case i::Token::FUTURE_STRICT_RESERVED_WORD: {
bool is_getter = false;
bool is_setter = false;
- ParseIdentifierOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
+ ParseIdentifierNameOrGetOrSet(&is_getter, &is_setter, CHECK_OK);
if ((is_getter || is_setter) && peek() != i::Token::COLON) {
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::FUTURE_STRICT_RESERVED_WORD &&
name != i::Token::NUMBER &&
name != i::Token::STRING &&
!is_keyword) {
LogSymbol();
if (scanner_->current_token() == i::Token::FUTURE_RESERVED_WORD) {
return Identifier::FutureReserved();
+ } else if (scanner_->current_token() ==
+ i::Token::FUTURE_STRICT_RESERVED_WORD) {
+ return Identifier::FutureStrictReserved();
}
if (scanner_->is_literal_ascii()) {
// Detect strict-mode poison words.
PreParser::Identifier PreParser::ParseIdentifier(bool* ok) {
- if (!Check(i::Token::FUTURE_RESERVED_WORD)) {
- Expect(i::Token::IDENTIFIER, ok);
- if (!*ok) return Identifier::Default();
+ i::Token::Value next = Next();
+ switch (next) {
+ case i::Token::FUTURE_RESERVED_WORD: {
+ i::Scanner::Location location = scanner_->location();
+ ReportMessageAt(location.beg_pos, location.end_pos,
+ "reserved_word", NULL);
+ *ok = false;
+ }
+ // FALLTHROUGH
+ case i::Token::FUTURE_STRICT_RESERVED_WORD:
+ case i::Token::IDENTIFIER:
+ return GetIdentifierSymbol();
+ default:
+ *ok = false;
+ return Identifier::Default();
}
- return GetIdentifierSymbol();
}
bool* ok) {
const char* type = eval_args_type;
if (identifier.IsFutureReserved()) {
+ type = "reserved_word";
+ } else if (identifier.IsFutureStrictReserved()) {
type = "strict_reserved_word";
}
if (strict_mode()) {
return Identifier::Default();
}
if (next == i::Token::IDENTIFIER ||
- next == i::Token::FUTURE_RESERVED_WORD) {
+ next == i::Token::FUTURE_RESERVED_WORD ||
+ next == i::Token::FUTURE_STRICT_RESERVED_WORD) {
return GetIdentifierSymbol();
}
*ok = false;
// This function reads an identifier and determines whether or not it
// is 'get' or 'set'.
-PreParser::Identifier PreParser::ParseIdentifierOrGetOrSet(bool* is_get,
- bool* is_set,
- bool* ok) {
- Identifier result = ParseIdentifier(ok);
+PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok) {
+ Identifier result = ParseIdentifierName(ok);
if (!*ok) return Identifier::Default();
if (scanner_->is_literal_ascii() &&
scanner_->literal_length() == 3) {
bool PreParser::peek_any_identifier() {
i::Token::Value next = peek();
return next == i::Token::IDENTIFIER ||
- next == i::Token::FUTURE_RESERVED_WORD;
+ next == i::Token::FUTURE_RESERVED_WORD ||
+ next == i::Token::FUTURE_STRICT_RESERVED_WORD;
}
} } // v8::preparser
static Identifier FutureReserved() {
return Identifier(kFutureReservedIdentifier);
}
+ static Identifier FutureStrictReserved() {
+ return Identifier(kFutureStrictReservedIdentifier);
+ }
bool IsEval() { return type_ == kEvalIdentifier; }
bool IsArguments() { return type_ == kArgumentsIdentifier; }
bool IsEvalOrArguments() { return type_ >= kEvalIdentifier; }
bool IsFutureReserved() { return type_ == kFutureReservedIdentifier; }
+ bool IsFutureStrictReserved() {
+ return type_ == kFutureStrictReservedIdentifier;
+ }
bool IsValidStrictVariable() { return type_ == kUnknownIdentifier; }
private:
enum Type {
kUnknownIdentifier,
kFutureReservedIdentifier,
+ kFutureStrictReservedIdentifier,
kEvalIdentifier,
kArgumentsIdentifier
};
Identifier ParseIdentifier(bool* ok);
Identifier ParseIdentifierName(bool* ok);
- Identifier ParseIdentifierOrGetOrSet(bool* is_get, bool* is_set, bool* ok);
+ Identifier ParseIdentifierNameOrGetOrSet(bool* is_get,
+ bool* is_set,
+ bool* ok);
// Logs the currently parsed literal as a symbol in the preparser data.
void LogSymbol();
{ NULL, I, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
- { "let", KEYWORD_PREFIX, Token::FUTURE_RESERVED_WORD },
+ { "let", KEYWORD_PREFIX, Token::FUTURE_STRICT_RESERVED_WORD },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, N, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
{ NULL, V, Token::ILLEGAL },
{ NULL, W, Token::ILLEGAL },
{ NULL, UNMATCHABLE, Token::ILLEGAL },
- { "yield", KEYWORD_PREFIX, Token::FUTURE_RESERVED_WORD }
+ { "yield", KEYWORD_PREFIX, Token::FUTURE_STRICT_RESERVED_WORD }
};
case C:
if (MatchState(input, 'a', CA)) return;
if (MatchKeywordStart(input, "class", 1,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_RESERVED_WORD)) return;
if (MatchState(input, 'o', CO)) return;
break;
case CA:
case E:
if (MatchKeywordStart(input, "else", 1, Token::ELSE)) return;
if (MatchKeywordStart(input, "enum", 1,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_RESERVED_WORD)) return;
if (MatchState(input, 'x', EX)) return;
break;
case EX:
if (MatchKeywordStart(input, "export", 2,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_RESERVED_WORD)) return;
if (MatchKeywordStart(input, "extends", 2,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_RESERVED_WORD)) return;
break;
case F:
if (MatchKeywordStart(input, "false", 1, Token::FALSE_LITERAL)) return;
break;
case IMP:
if (MatchKeywordStart(input, "implements", 3,
- Token::FUTURE_RESERVED_WORD )) return;
+ Token::FUTURE_STRICT_RESERVED_WORD )) return;
if (MatchKeywordStart(input, "import", 3,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_RESERVED_WORD)) return;
break;
case IN:
token_ = Token::IDENTIFIER;
if (MatchKeywordStart(input, "interface", 2,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_STRICT_RESERVED_WORD)) return;
if (MatchKeywordStart(input, "instanceof", 2, Token::INSTANCEOF)) return;
break;
case N:
break;
case P:
if (MatchKeywordStart(input, "package", 1,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_STRICT_RESERVED_WORD)) return;
if (MatchState(input, 'r', PR)) return;
if (MatchKeywordStart(input, "public", 1,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_STRICT_RESERVED_WORD)) return;
break;
case PR:
if (MatchKeywordStart(input, "private", 2,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_STRICT_RESERVED_WORD)) return;
if (MatchKeywordStart(input, "protected", 2,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_STRICT_RESERVED_WORD)) return;
break;
case S:
if (MatchKeywordStart(input, "static", 1,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_STRICT_RESERVED_WORD)) return;
if (MatchKeywordStart(input, "super", 1,
- Token::FUTURE_RESERVED_WORD)) return;
+ Token::FUTURE_RESERVED_WORD)) return;
if (MatchKeywordStart(input, "switch", 1,
- Token::SWITCH)) return;
+ Token::SWITCH)) return;
break;
case T:
if (MatchState(input, 'h', TH)) return;
class KeywordMatcher {
// Incrementally recognize keywords.
//
+// We distinguish between normal future reserved words and words that are
+// considered to be future reserved words only in strict mode as required by
+// ECMA-262 7.6.1.2.
+//
// Recognized as keywords:
// break, case, catch, const*, continue, debugger, default, delete, do,
// else, finally, false, for, function, if, in, instanceof, new, null,
// return, switch, this, throw, true, try, typeof, var, void, while, with.
//
-// Recognized as Future Reserved Keywords (normal and strict mode):
-// class, enum, export, extends, implements, import, interface,
-// let, package, private, private, protected, public, public,
+// Recognized as Future Reserved Keywords:
+// class, enum, export, extends, import, super.
+//
+// Recognized as Future Reserved Keywords (strict mode only):
+// implements, interface, let, package, private, protected, public,
// static, yield.
//
// *: Actually a "future reserved keyword". It's the only one we are
\
/* Future reserved words (ECMA-262, section 7.6.1.2). */ \
T(FUTURE_RESERVED_WORD, NULL, 0) \
+ T(FUTURE_STRICT_RESERVED_WORD, NULL, 0) \
K(CONST, "const", 0) \
\
/* Illegal token - not able to scan. */ \
--- /dev/null
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test proper handling of keywords, future reserved words and
+// future reserved words in strict mode as specific by 7.6.1 and 7.6.2
+// in ECMA-262.
+
+// This code is based on:
+// http://trac.webkit.org/export/89109/trunk/LayoutTests/fast/js/script-tests/keywords-and-reserved_words.js
+
+function isKeyword(x)
+{
+ try {
+ eval("var " + x + ";");
+ } catch(e) {
+ return true;
+ }
+
+ return false;
+}
+
+function isStrictKeyword(x)
+{
+ try {
+ eval("'use strict'; var "+x+";");
+ } catch(e) {
+ return true;
+ }
+
+ return false;
+}
+
+function classifyIdentifier(x)
+{
+ if (isKeyword(x)) {
+ // All non-strict keywords are also keywords in strict code.
+ if (!isStrictKeyword(x)) {
+ return "ERROR";
+ }
+ return "keyword";
+ }
+
+ // Check for strict mode future reserved words.
+ if (isStrictKeyword(x)) {
+ return "strict";
+ }
+
+ return "identifier";
+}
+
+function testKeyword(word) {
+ // Classify word
+ assertEquals("keyword", classifyIdentifier(word));
+
+ // Simple use of a keyword
+ assertThrows("var " + word + " = 1;", SyntaxError);
+ if (word != "this") {
+ assertThrows("typeof (" + word + ");", 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) { } };");
+
+ // Function names and arguments
+ assertThrows("function " + word + " () { }", SyntaxError);
+ assertThrows("function foo (" + word + ") {}", SyntaxError);
+ assertThrows("function foo (a, " + word + ") { }", SyntaxError);
+ assertThrows("function foo (" + word + ", a) { }", SyntaxError);
+ assertThrows("function foo (a, " + word + ", b) { }", SyntaxError);
+ assertThrows("var foo = function (" + word + ") { }", SyntaxError);
+
+ // setter parameter
+ assertThrows("var x = { set foo(" + word + ") { } };", SyntaxError);
+}
+
+// Not keywords - these are all just identifiers.
+var identifiers = [
+ "x", "keyword",
+ "id", "strict",
+ "identifier", "use",
+ // The following are reserved in ES3 but not in ES5.
+ "abstract", "int",
+ "boolean", "long",
+ "byte", "native",
+ "char", "short",
+ "double", "synchronized",
+ "final", "throws",
+ "float", "transient",
+ "goto", "volatile" ];
+
+for (var i = 0; i < identifiers.length; i++) {
+ assertEquals ("identifier", classifyIdentifier(identifiers[i]));
+}
+
+// 7.6.1.1 Keywords
+var keywords = [
+ "break", "in",
+ "case", "instanceof",
+ "catch", "new",
+ "continue", "return",
+ "debugger", "switch",
+ "default", "this",
+ "delete", "throw",
+ "do", "try",
+ "else", "typeof",
+ "finally", "var",
+ "for", "void",
+ "function", "while",
+ "if", "with",
+ // In ES5 "const" is a "future reserved word" but we treat it as a keyword.
+ "const" ];
+
+for (var i = 0; i < keywords.length; i++) {
+ testKeyword(keywords[i]);
+}
+
+// 7.6.1.2 Future Reserved Words (without "const")
+var future_reserved_words = [
+ "class",
+ "enum",
+ "export",
+ "extends",
+ "import",
+ "super" ];
+
+for (var i = 0; i < future_reserved_words.length; i++) {
+ testKeyword(future_reserved_words[i]);
+}
+
+// 7.6.1.2 Future Reserved Words, in strict mode only.
+var future_strict_reserved_words = [
+ "implements",
+ "interface",
+ "let",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "static",
+ "yield" ];
+
+for (var i = 0; i < future_strict_reserved_words.length; i++) {
+ assertEquals ("strict", classifyIdentifier(future_strict_reserved_words[i]));
+}
+
+// More strict mode specific tests can be found in mjsunit/strict-mode.js.
with ({}) {};
})();
+// Incorrectly place 'use strict' directive.
+assertThrows("function foo (x) 'use strict'; {}", SyntaxError);
+
// 'use strict' in non-directive position.
(function UseStrictNonDirective() {
void(0);
+arguments, -arguments, ~arguments, !arguments];
})();
-// 7.6.1.2 Future Reserved Words
-var future_reserved_words = [
- "class",
- "enum",
- "export",
- "extends",
- "import",
- "super",
+// 7.6.1.2 Future Reserved Words in strict mode
+var future_strict_reserved_words = [
"implements",
"interface",
"let",
"static",
"yield" ];
-function testFutureReservedWord(word) {
+function testFutureStrictReservedWord(word) {
// Simple use of each reserved word
CheckStrictMode("var " + word + " = 1;", SyntaxError);
+ CheckStrictMode("typeof (" + word + ");", SyntaxError);
// object literal properties
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'; } };");
// object literal with string literal property names
eval("var x = { '" + word + "' : 42 };");
// 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("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);
+ // setter parameter when the body is strict
+ CheckStrictMode("var x = { set foo(" + word + ") {} };", 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]);
+for (var i = 0; i < future_strict_reserved_words.length; i++) {
+ testFutureStrictReservedWord(future_strict_reserved_words[i]);
}
function testAssignToUndefined(test, should_throw) {
x = {get $id() {}, set $id(value) {}};
""")
+identifier_name_source = """
+ var x = {$id: 42};
+ x = {get $id() {}, set $id(value) {}};
+ x.$id = 42;
+ function foo() { "use strict;" }
+ x = {$id: 42};
+ x = {get $id() {}, set $id(value) {}};
+ x.$id = 42;
+"""
+
+identifier_name = Template("identifier_name-$id", identifier_name_source)
+identifier_name_strict = StrictTemplate("identifier_name_strict-$id",
+ identifier_name_source)
+
# ----------------------------------------------------------------------
# Run tests
# Reserved words just throw the same exception in all cases
# (with "const" being special, as usual).
for reserved_word in reserved_words + strict_reserved_words:
- message = "strict_reserved_word"
- if (reserved_word == "const"): message = "unexpected_token"
+ if (reserved_word in strict_reserved_words):
+ message = "strict_reserved_word"
+ elif (reserved_word == "const"):
+ message = "unexpected_token"
+ else:
+ message = "reserved_word"
arg_name_own({"id":reserved_word}, message)
arg_name_nested({"id":reserved_word}, message)
setter_arg({"id": reserved_word}, message)
postfix_var({"id":reserved_word, "op":"++", "opname":"inc"}, message)
postfix_var({"id":reserved_word, "op":"--", "opname":"dec"}, message)
read_var({"id": reserved_word}, message)
+ identifier_name({"id": reserved_word}, None);
+ identifier_name_strict({"id": reserved_word}, None);
+# Future reserved words in strict mode behave like normal identifiers
+# in a non strict context.
+for reserved_word in strict_reserved_words:
+ non_strict_use({"id": id}, None)