Index: src/parser.cc |
diff --git a/src/parser.cc b/src/parser.cc |
index 9539d3891f02a61d269376629185a01acf905ef5..044e0d2b4f7fab42c60a601b106d6256a9a3a1b3 100644 |
--- a/src/parser.cc |
+++ b/src/parser.cc |
@@ -1299,26 +1299,31 @@ Module* Parser::ParseModuleSpecifier(bool* ok) { |
} |
-void* Parser::ParseModuleDeclarationClause(ZoneList<const AstRawString*>* names, |
- bool* ok) { |
- // Handles both imports and exports: |
- // |
- // ImportOrExportClause : |
+void* Parser::ParseExportClause(ZoneList<const AstRawString*>* names, |
+ Scanner::Location* reserved_loc, bool* ok) { |
+ // ExportClause : |
// '{' '}' |
- // '{' ImportOrExportsList '}' |
- // '{' ImportOrExportsList ',' '}' |
+ // '{' ExportsList '}' |
+ // '{' ExportsList ',' '}' |
// |
- // ImportOrExportsList : |
- // ImportOrExportSpecifier |
- // ImportOrExportsList ',' ImportOrExportSpecifier |
+ // ExportsList : |
+ // ExportSpecifier |
+ // ExportsList ',' ExportSpecifier |
// |
- // ImportOrExportSpecifier : |
+ // ExportSpecifier : |
// IdentifierName |
// IdentifierName 'as' IdentifierName |
Expect(Token::LBRACE, CHECK_OK); |
- while (peek() != Token::RBRACE) { |
+ Token::Value name_tok; |
+ while ((name_tok = peek()) != Token::RBRACE) { |
+ // Keep track of the first reserved word encountered in case our |
+ // caller needs to report an error. |
+ if (!reserved_loc->IsValid() && |
+ !Token::IsIdentifier(name_tok, STRICT, false)) { |
+ *reserved_loc = scanner()->location(); |
+ } |
const AstRawString* name = ParseIdentifierName(CHECK_OK); |
names->Add(name, zone()); |
const AstRawString* export_name = NULL; |
@@ -1337,30 +1342,124 @@ void* Parser::ParseModuleDeclarationClause(ZoneList<const AstRawString*>* names, |
} |
+void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* names, |
+ bool* ok) { |
+ // NamedImports : |
+ // '{' '}' |
+ // '{' ImportsList '}' |
+ // '{' ImportsList ',' '}' |
+ // |
+ // ImportsList : |
+ // ImportSpecifier |
+ // ImportsList ',' ImportSpecifier |
+ // |
+ // ImportSpecifier : |
+ // BindingIdentifier |
+ // IdentifierName 'as' BindingIdentifier |
+ |
+ Expect(Token::LBRACE, CHECK_OK); |
+ |
+ Token::Value name_tok; |
+ while ((name_tok = peek()) != Token::RBRACE) { |
+ const AstRawString* name = ParseIdentifierName(CHECK_OK); |
+ const AstRawString* import_name = NULL; |
+ // In the presence of 'as', the left-side of the 'as' can |
+ // be any IdentifierName. But without 'as', it must be a valid |
+ // BindingIdentiifer. |
+ if (CheckContextualKeyword(CStrVector("as"))) { |
+ import_name = ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
+ } else if (!Token::IsIdentifier(name_tok, STRICT, false)) { |
+ *ok = false; |
+ ReportMessageAt(scanner()->location(), "unexpected_reserved"); |
+ return NULL; |
+ } else if (IsEvalOrArguments(name)) { |
+ *ok = false; |
+ ReportMessageAt(scanner()->location(), "strict_eval_arguments"); |
+ return NULL; |
+ } |
+ // TODO(ES6): Return the import_name as well as the name. |
+ names->Add(name, zone()); |
+ USE(import_name); |
+ if (peek() == Token::RBRACE) break; |
+ Expect(Token::COMMA, CHECK_OK); |
+ } |
+ |
+ Expect(Token::RBRACE, CHECK_OK); |
+ |
+ return NULL; |
+} |
+ |
+ |
Statement* Parser::ParseImportDeclaration(bool* ok) { |
- // ImportDeclaration: |
- // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleUrl ';' |
+ // ImportDeclaration : |
+ // 'import' ImportClause 'from' ModuleSpecifier ';' |
+ // 'import' ModuleSpecifier ';' |
+ // |
+ // ImportClause : |
+ // NameSpaceImport |
+ // NamedImports |
+ // ImportedDefaultBinding |
+ // ImportedDefaultBinding ',' NameSpaceImport |
+ // ImportedDefaultBinding ',' NamedImports |
// |
- // TODO(ES6): implement current syntax |
+ // NameSpaceImport : |
+ // '*' 'as' ImportedBinding |
int pos = peek_position(); |
Expect(Token::IMPORT, CHECK_OK); |
+ |
+ Token::Value tok = peek(); |
+ |
+ // 'import' ModuleSpecifier ';' |
+ if (tok == Token::STRING) { |
+ ParseModuleSpecifier(CHECK_OK); |
+ ExpectSemicolon(CHECK_OK); |
+ return factory()->NewEmptyStatement(pos); |
+ } |
+ |
+ // Parse ImportedDefaultBinding if present. |
+ const AstRawString* imported_default_binding = NULL; |
+ if (tok != Token::MUL && tok != Token::LBRACE) { |
+ imported_default_binding = |
+ ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
+ } |
+ |
+ const AstRawString* module_instance_binding = NULL; |
ZoneList<const AstRawString*> names(1, zone()); |
+ if (imported_default_binding == NULL || Check(Token::COMMA)) { |
+ switch (peek()) { |
+ case Token::MUL: { |
+ Consume(Token::MUL); |
+ ExpectContextualKeyword(CStrVector("as"), CHECK_OK); |
+ module_instance_binding = |
+ ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK); |
+ break; |
+ } |
- const AstRawString* name = ParseIdentifierName(CHECK_OK); |
- names.Add(name, zone()); |
- while (peek() == Token::COMMA) { |
- Consume(Token::COMMA); |
- name = ParseIdentifierName(CHECK_OK); |
- names.Add(name, zone()); |
+ case Token::LBRACE: |
+ ParseNamedImports(&names, CHECK_OK); |
+ break; |
+ |
+ default: |
+ *ok = false; |
+ ReportUnexpectedToken(scanner()->current_token()); |
+ return NULL; |
+ } |
} |
ExpectContextualKeyword(CStrVector("from"), CHECK_OK); |
Module* module = ParseModuleSpecifier(CHECK_OK); |
+ USE(module); |
+ |
ExpectSemicolon(CHECK_OK); |
- // TODO(ES6): Do something with ParseModuleSpecifier's return value. |
- USE(module); |
+ if (module_instance_binding != NULL) { |
+ // TODO(ES6): Bind name to the Module Instance Object of module. |
+ } |
+ |
+ if (imported_default_binding != NULL) { |
+ // TODO(ES6): Add an appropriate declaration. |
+ } |
for (int i = 0; i < names.length(); ++i) { |
// TODO(ES6): Add an appropriate declaration for each name |
@@ -1435,18 +1534,36 @@ Statement* Parser::ParseExportDeclaration(bool* ok) { |
break; |
} |
- case Token::LBRACE: |
- ParseModuleDeclarationClause(&names, CHECK_OK); |
+ case Token::LBRACE: { |
+ // There are two cases here: |
+ // |
+ // 'export' ExportClause ';' |
+ // and |
+ // 'export' ExportClause FromClause ';' |
+ // |
+ // In the first case, the exported identifiers in ExportClause must |
+ // not be reserved words, while in the latter they may be. We |
+ // pass in a location that gets filled with the first reserved word |
+ // encountered, and then throw a SyntaxError if we are in the |
+ // non-FromClause case. |
+ Scanner::Location reserved_loc = Scanner::Location::invalid(); |
+ ParseExportClause(&names, &reserved_loc, 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; |
+ } else if (reserved_loc.IsValid()) { |
+ // No FromClause, so reserved words are invalid in ExportClause. |
+ *ok = false; |
+ ReportMessageAt(reserved_loc, "unexpected_reserved"); |
+ return NULL; |
} |
ExpectSemicolon(CHECK_OK); |
result = factory()->NewEmptyStatement(pos); |
break; |
+ } |
case Token::FUNCTION: |
result = ParseFunctionDeclaration(&names, CHECK_OK); |