Chromium Code Reviews| 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>(); |