Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 6df216dc32c4d4406086f98fc84e511afcb32b98..6138ae9975a0100b7f3b1830ff097b68be79ac2a 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -1631,6 +1631,7 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context, |
Handle<String> ignore; |
Block* result = ParseVariableDeclarations(var_context, |
+ NULL, |
&ignore, |
CHECK_OK); |
ExpectSemicolon(CHECK_OK); |
@@ -1649,9 +1650,11 @@ 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(VariableDeclarationContext var_context, |
- Handle<String>* out, |
- bool* ok) { |
+Block* Parser::ParseVariableDeclarations( |
+ VariableDeclarationContext var_context, |
+ VariableDeclarationProperties* decl_props, |
+ Handle<String>* out, |
+ bool* ok) { |
// VariableDeclarations :: |
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[','] |
@@ -1789,6 +1792,7 @@ Block* Parser::ParseVariableDeclarations(VariableDeclarationContext var_context, |
} else { |
fni_->RemoveLastFunction(); |
} |
+ if (decl_props != NULL) *decl_props = kHasInitializers; |
} |
// Make sure that 'const x' and 'let x' initialize 'x' to undefined. |
@@ -2369,13 +2373,21 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { |
Statement* init = NULL; |
+ // Create an in-between scope for let-bound iteration variables. |
+ Scope* saved_scope = top_scope_; |
+ Scope* for_scope = NewScope(top_scope_, Scope::BLOCK_SCOPE); |
+ if (top_scope_->is_strict_mode()) { |
+ for_scope->EnableStrictMode(); |
+ } |
+ top_scope_ = for_scope; |
+ |
Expect(Token::FOR, CHECK_OK); |
Expect(Token::LPAREN, CHECK_OK); |
if (peek() != Token::SEMICOLON) { |
if (peek() == Token::VAR || peek() == Token::CONST) { |
Handle<String> name; |
Block* variable_statement = |
- ParseVariableDeclarations(kForStatement, &name, CHECK_OK); |
+ ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK); |
if (peek() == Token::IN && !name.is_null()) { |
VariableProxy* each = top_scope_->NewUnresolved(name); |
@@ -2391,12 +2403,70 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { |
Block* result = new(zone()) Block(isolate(), NULL, 2, false); |
result->AddStatement(variable_statement); |
result->AddStatement(loop); |
+ top_scope_ = saved_scope; |
+ for_scope = for_scope->FinalizeBlockScope(); |
+ ASSERT(for_scope == NULL); |
// Parsed for-in loop w/ variable/const declaration. |
return result; |
} else { |
init = variable_statement; |
} |
+ } else if (peek() == Token::LET) { |
+ Handle<String> name; |
+ VariableDeclarationProperties decl_props = kHasNoInitializers; |
+ Block* variable_statement = |
+ ParseVariableDeclarations(kForStatement, |
+ &decl_props, |
+ &name, |
+ CHECK_OK); |
+ bool accept_IN = !name.is_null() && decl_props != kHasInitializers; |
+ if (peek() == Token::IN && accept_IN) { |
+ // Rewrite a for-in statement of the form |
+ // |
+ // for (let x in e) b |
+ // |
+ // into |
+ // |
+ // <let x' be a temporary variable> |
+ // for (x' in e) { |
+ // let x; |
+ // x = x'; |
+ // b; |
+ // } |
+ |
+ // TODO(keuchel): move temporary variable to block scope |
Lasse Reichstein
2011/10/17 11:49:40
What does this mean? Is the current code not corre
Steven
2011/10/17 12:18:29
This is an optimization. TEMPORARY variables are a
|
+ Variable* temp = top_scope_->DeclarationScope()->NewTemporary(name); |
+ VariableProxy* temp_proxy = new(zone()) VariableProxy(isolate(), temp); |
+ VariableProxy* each = top_scope_->NewUnresolved(name, inside_with()); |
+ ForInStatement* loop = new(zone()) ForInStatement(isolate(), labels); |
+ Target target(&this->target_stack_, loop); |
+ |
+ Expect(Token::IN, CHECK_OK); |
+ Expression* enumerable = ParseExpression(true, CHECK_OK); |
+ Expect(Token::RPAREN, CHECK_OK); |
+ |
+ Statement* body = ParseStatement(NULL, CHECK_OK); |
+ Block* body_block = new(zone()) Block(isolate(), NULL, 3, false); |
+ Assignment* assignment = new(zone()) Assignment(isolate(), |
+ Token::ASSIGN, |
+ each, |
+ temp_proxy, |
+ RelocInfo::kNoPosition); |
+ Statement* assignment_statement = |
+ new(zone()) ExpressionStatement(assignment); |
+ body_block->AddStatement(variable_statement); |
+ body_block->AddStatement(assignment_statement); |
+ body_block->AddStatement(body); |
+ loop->Initialize(temp_proxy, enumerable, body_block); |
+ top_scope_ = saved_scope; |
+ for_scope = for_scope->FinalizeBlockScope(); |
+ body_block->set_block_scope(for_scope); |
+ // Parsed for-in loop w/ let declaration. |
+ return loop; |
+ } else { |
+ init = variable_statement; |
+ } |
} else { |
Expression* expression = ParseExpression(false, CHECK_OK); |
if (peek() == Token::IN) { |
@@ -2418,6 +2488,9 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { |
Statement* body = ParseStatement(NULL, CHECK_OK); |
if (loop) loop->Initialize(expression, enumerable, body); |
+ top_scope_ = saved_scope; |
+ for_scope = for_scope->FinalizeBlockScope(); |
+ ASSERT(for_scope == NULL); |
// Parsed for-in loop. |
return loop; |
@@ -2448,8 +2521,30 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) { |
Expect(Token::RPAREN, CHECK_OK); |
Statement* body = ParseStatement(NULL, CHECK_OK); |
- if (loop) loop->Initialize(init, cond, next, body); |
- return loop; |
+ top_scope_ = saved_scope; |
+ for_scope = for_scope->FinalizeBlockScope(); |
+ if (for_scope != NULL) { |
+ // Rewrite a for statement of the form |
+ // |
+ // for (let x = i; c; n) b |
+ // |
+ // into |
+ // |
+ // { |
+ // let x = i; |
+ // for (; c; n) b |
+ // } |
+ ASSERT(init != NULL); |
+ Block* result = new(zone()) Block(isolate(), NULL, 2, false); |
+ result->AddStatement(init); |
+ result->AddStatement(loop); |
+ result->set_block_scope(for_scope); |
+ if (loop) loop->Initialize(NULL, cond, next, body); |
+ return result; |
+ } else { |
+ if (loop) loop->Initialize(init, cond, next, body); |
+ return loop; |
+ } |
} |