Chromium Code Reviews| Index: src/parser.cc |
| diff --git a/src/parser.cc b/src/parser.cc |
| index dff7de9e6b25c9c9370c866ab5bd4f52646852a6..a7708e181f44e6b425a2bfaf4be3624eb35407d9 100644 |
| --- a/src/parser.cc |
| +++ b/src/parser.cc |
| @@ -1270,7 +1270,7 @@ Module* Parser::ParseModule(bool* ok) { |
| } |
| -Module* Parser::ParseModuleUrl(bool* ok) { |
| +Module* Parser::ParseModuleSpecifier(bool* ok) { |
| // Module: |
| // String |
| @@ -1299,6 +1299,44 @@ Module* Parser::ParseModuleUrl(bool* ok) { |
| } |
| +void* Parser::ParseModuleDeclarationClause( |
| + ZoneList<const AstRawString*>* names, bool* ok) { |
| + // Handles both imports and exports: |
| + // |
| + // ImportOrExportClause : |
| + // '{' '}' |
| + // '{' ImportOrExportsList '}' |
| + // '{' ImportOrExportsList ',' '}' |
| + // |
| + // ImportOrExportsList : |
| + // ImportOrExportSpecifier |
| + // ImportOrExportsList ',' ImportOrExportSpecifier |
| + // |
| + // ImportOrExportSpecifier : |
| + // IdentifierName |
| + // IdentifierName 'as' IdentifierName |
| + |
| + Expect(Token::LBRACE, CHECK_OK); |
| + |
| + while (peek() != Token::RBRACE) { |
| + const AstRawString* name = ParseIdentifierName(CHECK_OK); |
| + names->Add(name, zone()); |
| + const AstRawString* export_name = NULL; |
| + if (CheckContextualKeyword(CStrVector("as"))) { |
| + export_name = ParseIdentifierName(CHECK_OK); |
| + } |
| + // TODO(ES6): Return the export_name as well as the name. |
| + USE(export_name); |
| + if (peek() == Token::RBRACE) break; |
| + Expect(Token::COMMA, CHECK_OK); |
| + } |
| + |
| + Expect(Token::RBRACE, CHECK_OK); |
| + |
| + return 0; |
| +} |
| + |
| + |
| Statement* Parser::ParseImportDeclaration(bool* ok) { |
| // ImportDeclaration: |
| // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleUrl ';' |
| @@ -1318,10 +1356,10 @@ Statement* Parser::ParseImportDeclaration(bool* ok) { |
| } |
| ExpectContextualKeyword(CStrVector("from"), CHECK_OK); |
| - Module* module = ParseModuleUrl(CHECK_OK); |
| + Module* module = ParseModuleSpecifier(CHECK_OK); |
| ExpectSemicolon(CHECK_OK); |
| - // TODO(ES6): Do something with ParseModuleUrl's return value. |
| + // TODO(ES6): Do something with ParseModuleSpecifier's return value. |
| USE(module); |
| for (int i = 0; i < names.length(); ++i) { |
| @@ -1332,36 +1370,85 @@ Statement* Parser::ParseImportDeclaration(bool* ok) { |
| } |
| +Statement* Parser::ParseExportDefault(bool* ok) { |
| + // Supports the following productions, starting after the 'default' token: |
| + // 'export' 'default' FunctionDeclaration |
| + // 'export' 'default' ClassDeclaration |
| + // 'export' 'default' AssignmentExpression[In] ';' |
| + // |
| + // TODO(ES6): Allow FunctionDeclaration[Default] and |
| + // ClassDeclaration[Default]. |
| + |
| + Statement* result = NULL; |
| + switch (peek()) { |
| + case Token::FUNCTION: |
|
arv (Not doing code reviews)
2015/01/28 02:57:19
This is going to be problematic. export default su
adamk
2015/01/28 18:05:04
That's the TODO above about FunctionDeclaration[De
|
| + result = ParseFunctionDeclaration(NULL, CHECK_OK); |
| + break; |
| + |
| + case Token::CLASS: |
| + result = ParseClassDeclaration(NULL, CHECK_OK); |
|
arv (Not doing code reviews)
2015/01/28 02:57:19
Same here
|
| + break; |
| + |
| + default: { |
| + int pos = peek_position(); |
| + Expression* expr = ParseAssignmentExpression(true, CHECK_OK); |
| + ExpectSemicolon(CHECK_OK); |
| + result = factory()->NewExpressionStatement(expr, pos); |
| + break; |
| + } |
| + } |
| + |
| + // TODO(ES6): Add default export to scope_->interface() |
| + |
| + return result; |
| +} |
| + |
| + |
| Statement* Parser::ParseExportDeclaration(bool* ok) { |
| // ExportDeclaration: |
| - // 'export' Identifier (',' Identifier)* ';' |
| - // 'export' VariableDeclaration |
| - // 'export' FunctionDeclaration |
| - // 'export' GeneratorDeclaration |
| - // 'export' ModuleDeclaration |
| - // |
| - // TODO(ES6): implement current syntax |
| + // 'export' '*' 'from' ModuleSpecifier ';' |
| + // 'export' ExportClause ('from' ModuleSpecifier)? ';' |
| + // 'export' VariableStatement |
| + // 'export' Declaration |
| + // 'export' 'default' ... (handled in ParseExportDefault) |
| + int pos = peek_position(); |
| Expect(Token::EXPORT, CHECK_OK); |
| Statement* result = NULL; |
| ZoneList<const AstRawString*> names(1, zone()); |
| + bool is_export_from = false; |
| switch (peek()) { |
| - case Token::IDENTIFIER: { |
| - int pos = position(); |
| - const AstRawString* name = |
| - ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
| - names.Add(name, zone()); |
| - while (peek() == Token::COMMA) { |
| - Consume(Token::COMMA); |
| - name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
| - names.Add(name, zone()); |
| - } |
| + case Token::DEFAULT: |
| + Consume(Token::DEFAULT); |
| + return ParseExportDefault(ok); |
| + |
| + case Token::MUL: { |
| + Consume(Token::MUL); |
| + ExpectContextualKeyword(CStrVector("from"), CHECK_OK); |
| + Module* module = ParseModuleSpecifier(CHECK_OK); |
| ExpectSemicolon(CHECK_OK); |
| + // TODO(ES6): Do something with the return value |
| + // of ParseModuleSpecifier. |
| + USE(module); |
| + is_export_from = true; |
| result = factory()->NewEmptyStatement(pos); |
| break; |
| } |
| + case Token::LBRACE: |
| + ParseModuleDeclarationClause(&names, CHECK_OK); |
| + if (CheckContextualKeyword(CStrVector("from"))) { |
| + Module* module = ParseModuleSpecifier(CHECK_OK); |
| + // TODO(ES6): Do something with the return value |
| + // of ParseModuleSpecifier. |
| + USE(module); |
| + is_export_from = true; |
| + } |
| + ExpectSemicolon(CHECK_OK); |
| + result = factory()->NewEmptyStatement(pos); |
| + break; |
| + |
| case Token::FUNCTION: |
| result = ParseFunctionDeclaration(&names, CHECK_OK); |
| break; |
| @@ -1395,24 +1482,28 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { |
| } |
| } |
| - // Extract declared names into export declarations and interface. |
| - Interface* interface = scope_->interface(); |
| - for (int i = 0; i < names.length(); ++i) { |
| + // TODO(ES6): Handle 'export from' once imports are properly implemented. |
| + // For now we just drop such exports on the floor. |
| + if (!is_export_from) { |
| + // Extract declared names into export declarations and interface. |
| + Interface* interface = scope_->interface(); |
| + for (int i = 0; i < names.length(); ++i) { |
| #ifdef DEBUG |
| - if (FLAG_print_interface_details) |
| - PrintF("# Export %.*s ", names[i]->length(), names[i]->raw_data()); |
| + if (FLAG_print_interface_details) |
| + PrintF("# Export %.*s ", names[i]->length(), names[i]->raw_data()); |
| #endif |
| - Interface* inner = Interface::NewUnknown(zone()); |
| - interface->Add(names[i], inner, zone(), CHECK_OK); |
| - if (!*ok) |
| - return NULL; |
| - VariableProxy* proxy = NewUnresolved(names[i], LET, inner); |
| - USE(proxy); |
| - // TODO(rossberg): Rethink whether we actually need to store export |
| - // declarations (for compilation?). |
| - // ExportDeclaration* declaration = |
| - // factory()->NewExportDeclaration(proxy, scope_, position); |
| - // scope_->AddDeclaration(declaration); |
| + Interface* inner = Interface::NewUnknown(zone()); |
| + interface->Add(names[i], inner, zone(), CHECK_OK); |
| + if (!*ok) |
| + return NULL; |
| + VariableProxy* proxy = NewUnresolved(names[i], LET, inner); |
| + USE(proxy); |
| + // TODO(rossberg): Rethink whether we actually need to store export |
| + // declarations (for compilation?). |
| + // ExportDeclaration* declaration = |
| + // factory()->NewExportDeclaration(proxy, scope_, position); |
| + // scope_->AddDeclaration(declaration); |
| + } |
| } |
| DCHECK(result != NULL); |