| 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);
|
|
|