Commit 41eb990a authored by keuchel@chromium.org's avatar keuchel@chromium.org

Fix pre-parsing function declarations.

The preparser has been out of sync with the parser. As a reminder, we have the
following grammer for harmony mode

 Block ::
   { SourceElement* }
 SourceElement ::
   Statement
   FunctionDeclaration
   LetDeclaration

instead of

 Block ::
   { Statement* }
 SourceElement ::
   Statement
   FunctionDeclaration

The extension to allow FunctionDeclarations in statement positions in
non-strict code is still active.

Review URL: http://codereview.chromium.org/7983006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9363 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 63b6874e
......@@ -1103,14 +1103,16 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder {
Statement* Parser::ParseSourceElement(ZoneStringList* labels,
bool* ok) {
// (Ecma 262 5th Edition, clause 14):
// SourceElement:
// Statement
// FunctionDeclaration
//
// In harmony mode we allow additionally the following productions
// SourceElement:
// LetDeclaration
if (peek() == Token::FUNCTION) {
// FunctionDeclaration is only allowed in the context of SourceElements
// (Ecma 262 5th Edition, clause 14):
// SourceElement:
// Statement
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
return ParseFunctionDeclaration(ok);
} else if (peek() == Token::LET) {
return ParseVariableStatement(kSourceElement, ok);
......@@ -1124,7 +1126,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
int end_token,
bool* ok) {
// SourceElements ::
// (Statement)* <end_token>
// (SourceElement)* <end_token>
// Allocate a target stack to use for this set of source
// elements. This way, all scripts and functions get their own
......@@ -1295,8 +1297,13 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
}
case Token::FUNCTION: {
// In strict mode, FunctionDeclaration is only allowed in the context
// of SourceElements.
// FunctionDeclaration is only allowed in the context of SourceElements
// (Ecma 262 5th Edition, clause 14):
// SourceElement:
// Statement
// FunctionDeclaration
// Common language extension is to allow function declaration in place
// of any statement. This language extension is disabled in strict mode.
if (top_scope_->is_strict_mode()) {
ReportMessageAt(scanner().peek_location(), "strict_function",
Vector<const char*>::empty());
......@@ -1555,6 +1562,11 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
// The harmony mode uses source elements instead of statements.
//
// Block ::
// '{' SourceElement* '}'
// Construct block expecting 16 statements.
Block* body = new(zone()) Block(isolate(), labels, 16, false);
Scope* saved_scope = top_scope_;
......
......@@ -117,7 +117,18 @@ void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
PreParser::Statement PreParser::ParseSourceElement(bool* ok) {
// (Ecma 262 5th Edition, clause 14):
// SourceElement:
// Statement
// FunctionDeclaration
//
// In harmony mode we allow additionally the following productions
// SourceElement:
// LetDeclaration
switch (peek()) {
case i::Token::FUNCTION:
return ParseFunctionDeclaration(ok);
case i::Token::LET:
return ParseVariableStatement(kSourceElement, ok);
default:
......@@ -225,8 +236,19 @@ PreParser::Statement PreParser::ParseStatement(bool* ok) {
case i::Token::TRY:
return ParseTryStatement(ok);
case i::Token::FUNCTION:
return ParseFunctionDeclaration(ok);
case i::Token::FUNCTION: {
i::Scanner::Location start_location = scanner_->peek_location();
Statement statement = ParseFunctionDeclaration(CHECK_OK);
i::Scanner::Location end_location = scanner_->location();
if (strict_mode()) {
ReportMessageAt(start_location.beg_pos, end_location.end_pos,
"strict_function", NULL);
*ok = false;
return Statement::Default();
} else {
return statement;
}
}
case i::Token::DEBUGGER:
return ParseDebuggerStatement(ok);
......@@ -271,14 +293,10 @@ PreParser::Statement PreParser::ParseBlock(bool* ok) {
//
Expect(i::Token::LBRACE, CHECK_OK);
while (peek() != i::Token::RBRACE) {
i::Scanner::Location start_location = scanner_->peek_location();
Statement statement = ParseSourceElement(CHECK_OK);
i::Scanner::Location end_location = scanner_->location();
if (strict_mode() && statement.IsFunctionDeclaration()) {
ReportMessageAt(start_location.beg_pos, end_location.end_pos,
"strict_function", NULL);
*ok = false;
return Statement::Default();
if (harmony_block_scoping_) {
ParseSourceElement(CHECK_OK);
} else {
ParseStatement(CHECK_OK);
}
}
Expect(i::Token::RBRACE, ok);
......@@ -375,15 +393,7 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(bool* ok) {
if (peek() == i::Token::COLON &&
(!strict_mode() || !expr.AsIdentifier().IsFutureReserved())) {
Consume(i::Token::COLON);
i::Scanner::Location start_location = scanner_->peek_location();
Statement statement = ParseStatement(CHECK_OK);
if (strict_mode() && statement.IsFunctionDeclaration()) {
i::Scanner::Location end_location = scanner_->location();
ReportMessageAt(start_location.beg_pos, end_location.end_pos,
"strict_function", NULL);
*ok = false;
}
return Statement::Default();
return ParseStatement(ok);
}
// Preparsing is disabled for extensions (because the extension details
// aren't passed to lazily compiled functions), so we don't
......@@ -513,15 +523,7 @@ PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
Expect(i::Token::DEFAULT, CHECK_OK);
Expect(i::Token::COLON, CHECK_OK);
} else {
i::Scanner::Location start_location = scanner_->peek_location();
Statement statement = ParseStatement(CHECK_OK);
if (strict_mode() && statement.IsFunctionDeclaration()) {
i::Scanner::Location end_location = scanner_->location();
ReportMessageAt(start_location.beg_pos, end_location.end_pos,
"strict_function", NULL);
*ok = false;
return Statement::Default();
}
ParseStatement(CHECK_OK);
}
token = peek();
}
......
......@@ -47,19 +47,70 @@ if (true) {
assertEquals(undefined, y);
}
// Invalid declarations are early errors in harmony mode and thus should trigger
// an exception in eval code during parsing, before even compiling or executing
// the code. Thus the generated function is not called here.
function TestLocalThrows(str, expect) {
assertThrows("(function(){" + str + "})()", expect);
assertThrows("(function(){" + str + "})", expect);
}
function TestLocalDoesNotThrow(str) {
assertDoesNotThrow("(function(){" + str + "})()");
}
// Unprotected statement
// Test let declarations statement positions.
TestLocalThrows("if (true) let x;", SyntaxError);
TestLocalThrows("if (true) {} else let x;", SyntaxError);
TestLocalThrows("do let x; while (false)", SyntaxError);
TestLocalThrows("while (false) let x;", SyntaxError);
TestLocalThrows("label: let x;", SyntaxError);
TestLocalThrows("for (;false;) let x;", SyntaxError);
TestLocalThrows("switch (true) { case true: let x; }", SyntaxError);
TestLocalThrows("switch (true) { default: let x; }", SyntaxError);
// Test var declarations statement positions.
TestLocalDoesNotThrow("if (true) var x;");
TestLocalDoesNotThrow("if (true) {} else var x;");
TestLocalDoesNotThrow("do var x; while (false)");
TestLocalDoesNotThrow("while (false) var x;");
TestLocalDoesNotThrow("label: var x;");
TestLocalDoesNotThrow("for (;false;) var x;");
TestLocalDoesNotThrow("switch (true) { case true: var x; }");
TestLocalDoesNotThrow("switch (true) { default: var x; }");
// Test function declarations in source element and
// non-strict statement positions.
function f() {
// Non-strict source element positions.
function g0() {
"use strict";
// Strict source element positions.
function h() { }
{
function h1() { }
}
}
{
function g1() { }
}
// Non-strict statement positions.
if (true) function g2() { }
if (true) {} else function g3() { }
do function g4() { } while (false)
while (false) function g5() { }
label: function g6() { }
for (;false;) function g7() { }
switch (true) { case true: function g8() { } }
switch (true) { default: function g9() { } }
}
f();
// Test function declarations in statement position in strict mode.
TestLocalThrows("function f() { 'use strict'; if (true) function g() {}", SyntaxError);
TestLocalThrows("function f() { 'use strict'; if (true) {} else function g() {}", SyntaxError);
TestLocalThrows("function f() { 'use strict'; do function g() {} while (false)", SyntaxError);
TestLocalThrows("function f() { 'use strict'; while (false) function g() {}", SyntaxError);
TestLocalThrows("function f() { 'use strict'; label: function g() {}", SyntaxError);
TestLocalThrows("function f() { 'use strict'; for (;false;) function g() {}", SyntaxError);
TestLocalThrows("function f() { 'use strict'; switch (true) { case true: function g() {} }", SyntaxError);
TestLocalThrows("function f() { 'use strict'; switch (true) { default: function g() {} }", SyntaxError);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment