Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 1167f43df519321d34a8a7efad9e085b2af7e548..6886340ef5f8b5612eb92575c6be7e2773d9f93a 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -1093,6 +1093,25 @@ class ThisNamedPropertyAssigmentFinder : public ParserFinder { |
}; |
+Statement* Parser::ParseSourceElement(ZoneStringList* labels, |
+ bool* ok) { |
+ 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 && harmony_block_scoping_) { |
+ return ParseVariableStatement(true, ok); |
Lasse Reichstein
2011/08/12 08:08:33
Please use an enum with meaningful names for the f
Steven
2011/08/16 09:05:32
Done. See the VariableDeclarationContext enum. Als
|
+ } else { |
+ return ParseStatement(labels, ok); |
+ } |
+} |
+ |
+ |
void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, |
int end_token, |
bool* ok) { |
@@ -1116,21 +1135,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor, |
} |
Scanner::Location token_loc = scanner().peek_location(); |
- |
- Statement* stat; |
- 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. |
- stat = ParseFunctionDeclaration(CHECK_OK); |
- } else { |
- stat = ParseStatement(NULL, CHECK_OK); |
- } |
- |
+ Statement* stat = ParseSourceElement(NULL, CHECK_OK); |
if (stat == NULL || stat->IsEmpty()) { |
directive_prologue = false; // End of directive prologue. |
continue; |
@@ -1218,7 +1223,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) { |
case Token::CONST: // fall through |
case Token::VAR: |
- stmt = ParseVariableStatement(ok); |
+ stmt = ParseVariableStatement(false, ok); |
break; |
case Token::SEMICOLON: |
@@ -1325,24 +1330,28 @@ VariableProxy* Parser::Declare(Handle<String> name, |
// to the calling function context. |
// Similarly, strict mode eval scope does not leak variable declarations to |
// the caller's scope so we declare all locals, too. |
- Scope* declaration_scope = top_scope_->DeclarationScope(); |
+ |
+ Scope* declaration_scope = mode == Variable::LET ? top_scope_ |
+ : top_scope_->DeclarationScope(); |
if (declaration_scope->is_function_scope() || |
- declaration_scope->is_strict_mode_eval_scope()) { |
+ declaration_scope->is_strict_mode_eval_scope() || |
+ declaration_scope->is_block_scope()) { |
// Declare the variable in the function scope. |
var = declaration_scope->LocalLookup(name); |
if (var == NULL) { |
// Declare the name. |
var = declaration_scope->DeclareLocal(name, mode); |
} else { |
- // The name was declared before; check for conflicting |
- // re-declarations. If the previous declaration was a const or the |
- // current declaration is a const then we have a conflict. There is |
- // similar code in runtime.cc in the Declare functions. |
- if ((mode == Variable::CONST) || (var->mode() == Variable::CONST)) { |
- // We only have vars and consts in declarations. |
+ // The name was declared before; check for conflicting re-declarations. |
+ // We have a conflict if either of the declarations is not a var. There |
+ // is similar code in runtime.cc in the Declare functions. |
+ if ((mode != Variable::VAR) || (var->mode() != Variable::VAR)) { |
+ // We only have vars, consts and lets in declarations. |
ASSERT(var->mode() == Variable::VAR || |
- var->mode() == Variable::CONST); |
- const char* type = (var->mode() == Variable::VAR) ? "var" : "const"; |
+ var->mode() == Variable::CONST || |
+ var->mode() == Variable::LET); |
+ const char* type = (var->mode() == Variable::VAR) ? "var" : |
+ (var->mode() == Variable::CONST) ? "const" : "let"; |
Handle<String> type_string = |
isolate()->factory()->NewStringFromUtf8(CStrVector(type), TENURED); |
Expression* expression = |
@@ -1485,7 +1494,8 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) { |
// Even if we're not at the top-level of the global or a function |
// scope, we treat is as such and introduce the function with it's |
// initial value upon entering the corresponding scope. |
- Declare(name, Variable::VAR, fun, true, CHECK_OK); |
+ Variable::Mode mode = harmony_block_scoping_ ? Variable::LET : Variable::VAR; |
+ Declare(name, mode, fun, true, CHECK_OK); |
return EmptyStatement(); |
} |
@@ -1540,7 +1550,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { |
InitializationBlockFinder block_finder(top_scope_, target_stack_); |
while (peek() != Token::RBRACE) { |
- Statement* stat = ParseStatement(NULL, CHECK_OK); |
+ Statement* stat = ParseSourceElement(NULL, CHECK_OK); |
Lasse Reichstein
2011/08/12 08:08:33
Will this enable function declarations inside bloc
Steven
2011/08/16 09:05:32
The proposal allows local function declarations in
|
if (stat && !stat->IsEmpty()) { |
body->AddStatement(stat); |
block_finder.Update(stat); |
@@ -1566,12 +1576,13 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) { |
} |
-Block* Parser::ParseVariableStatement(bool* ok) { |
+Block* Parser::ParseVariableStatement(bool accept_LET, bool* ok) { |
// VariableStatement :: |
// VariableDeclarations ';' |
Handle<String> ignore; |
- Block* result = ParseVariableDeclarations(true, &ignore, CHECK_OK); |
+ Block* result = ParseVariableDeclarations(accept_LET, true, |
+ &ignore, CHECK_OK); |
ExpectSemicolon(CHECK_OK); |
return result; |
} |
@@ -1588,7 +1599,8 @@ bool Parser::IsEvalOrArguments(Handle<String> string) { |
// *var is untouched; in particular, it is the caller's responsibility |
// to initialize it properly. This mechanism is used for the parsing |
// of 'for-in' loops. |
-Block* Parser::ParseVariableDeclarations(bool accept_IN, |
+Block* Parser::ParseVariableDeclarations(bool accept_LET, |
+ bool accept_IN, |
Handle<String>* out, |
bool* ok) { |
// VariableDeclarations :: |
@@ -1608,6 +1620,14 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, |
} |
mode = Variable::CONST; |
is_const = true; |
+ } else if (peek() == Token::LET) { |
+ Consume(Token::LET); |
+ if (!accept_LET) { |
+ ReportMessage("unprotected_let", Vector<const char*>::empty()); |
+ *ok = false; |
+ return NULL; |
+ } |
+ mode = Variable::LET; |
} else { |
UNREACHABLE(); // by current callers |
} |
@@ -2346,7 +2366,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { |
if (peek() == Token::VAR || peek() == Token::CONST) { |
Handle<String> name; |
Block* variable_statement = |
- ParseVariableDeclarations(false, &name, CHECK_OK); |
+ ParseVariableDeclarations(true, false, &name, CHECK_OK); |
if (peek() == Token::IN && !name.is_null()) { |
VariableProxy* each = top_scope_->NewUnresolved(name, inside_with()); |
@@ -2993,6 +3013,14 @@ void Parser::ReportUnexpectedToken(Token::Value token) { |
case Token::FUTURE_RESERVED_WORD: |
return ReportMessage("unexpected_reserved", |
Vector<const char*>::empty()); |
+ case Token::LET: |
+ if (harmony_block_scoping_) { |
+ const char* name = Token::String(token); |
+ ASSERT(name != NULL); |
+ return ReportMessage("unexpected_token", |
+ Vector<const char*>(&name, 1)); |
+ } |
+ // FALLTHROUGH |
case Token::FUTURE_STRICT_RESERVED_WORD: |
return ReportMessage(top_scope_->is_strict_mode() ? |
"unexpected_strict_reserved" : |
@@ -3055,6 +3083,14 @@ Expression* Parser::ParsePrimaryExpression(bool* ok) { |
isolate(), isolate()->factory()->false_value()); |
break; |
+ case Token::LET: |
+ if (harmony_block_scoping_) { |
+ Token::Value tok = Next(); |
+ ReportUnexpectedToken(tok); |
+ *ok = false; |
+ return NULL; |
+ } |
+ // FALLTHROUGH |
case Token::IDENTIFIER: |
case Token::FUTURE_STRICT_RESERVED_WORD: { |
Handle<String> name = ParseIdentifier(CHECK_OK); |
@@ -3519,6 +3555,12 @@ Expression* Parser::ParseObjectLiteral(bool* ok) { |
// Location of the property name token |
Scanner::Location loc = scanner().peek_location(); |
+ if (harmony_block_scoping_ && next == Token::LET) { |
+ // Go into FUTURE_STRICT_RESERVED_WORD case where |
+ // ParseIdentifierNameOrGetOrSet will handle the LET |
+ // token like a FUTURE_STRICT_RESERVED_WORD. |
+ next = Token::FUTURE_STRICT_RESERVED_WORD; |
Lasse Reichstein
2011/08/12 08:08:33
Why not just add a case for Token::LET next to Tok
Steven
2011/08/16 09:05:32
Now obsolete, since the scanner now produces the c
|
+ } |
switch (next) { |
case Token::FUTURE_RESERVED_WORD: |
case Token::FUTURE_STRICT_RESERVED_WORD: |
@@ -3706,7 +3748,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(Handle<String> function_name, |
int num_parameters = 0; |
// Function declarations are hoisted. |
- Scope* scope = (type == FunctionLiteral::DECLARATION) |
+ Scope* scope = (type == FunctionLiteral::DECLARATION && |
+ !harmony_block_scoping_) |
Lasse Reichstein
2011/08/12 08:08:33
If harmony_block_scoping_ is set, function declara
Steven
2011/08/16 09:05:32
Yes, function declarations are then also expected
|
? NewScope(top_scope_->DeclarationScope(), Scope::FUNCTION_SCOPE, false) |
: NewScope(top_scope_, Scope::FUNCTION_SCOPE, inside_with()); |
ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8); |
@@ -3946,7 +3989,8 @@ bool Parser::peek_any_identifier() { |
Token::Value next = peek(); |
return next == Token::IDENTIFIER || |
next == Token::FUTURE_RESERVED_WORD || |
- next == Token::FUTURE_STRICT_RESERVED_WORD; |
+ next == Token::FUTURE_STRICT_RESERVED_WORD || |
+ (next == Token::LET && !harmony_block_scoping_); |
} |
@@ -4014,7 +4058,11 @@ Handle<String> Parser::ParseIdentifier(bool* ok) { |
if (top_scope_->is_strict_mode()) { |
Expect(Token::IDENTIFIER, ok); |
} else if (!Check(Token::IDENTIFIER)) { |
- Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok); |
+ if (harmony_block_scoping_) { |
+ Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok); |
+ } else if (!Check(Token::FUTURE_STRICT_RESERVED_WORD)) { |
+ Expect(Token::LET, ok); |
+ } |
} |
if (!*ok) return Handle<String>(); |
return GetSymbol(ok); |
@@ -4027,7 +4075,11 @@ 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); |
+ if (harmony_block_scoping_) { |
+ Expect(Token::FUTURE_STRICT_RESERVED_WORD, ok); |
+ } else if (!Check(Token::FUTURE_STRICT_RESERVED_WORD)) { |
+ Expect(Token::LET, ok); |
+ } |
*is_strict_reserved = true; |
} |
if (!*ok) return Handle<String>(); |