| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 1bab4a61797acd54807a10cd7baa9d15c4783e18..aeb29abf274074df60ee7ae6702cfbef75d7c2e0 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -1184,10 +1184,10 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
|
|
|
| switch (peek()) {
|
| case Token::FUNCTION:
|
| - return ParseFunctionDeclaration(ok);
|
| + return ParseFunctionDeclaration(NULL, ok);
|
| case Token::LET:
|
| case Token::CONST:
|
| - return ParseVariableStatement(kModuleElement, ok);
|
| + return ParseVariableStatement(kModuleElement, NULL, ok);
|
| case Token::IMPORT:
|
| return ParseImportDeclaration(ok);
|
| case Token::EXPORT:
|
| @@ -1205,7 +1205,7 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
|
| estmt->expression()->AsVariableProxy()->name()->Equals(
|
| isolate()->heap()->module_symbol()) &&
|
| !scanner().literal_contains_escapes()) {
|
| - return ParseModuleDeclaration(ok);
|
| + return ParseModuleDeclaration(NULL, ok);
|
| }
|
| }
|
| return stmt;
|
| @@ -1214,7 +1214,7 @@ Statement* Parser::ParseModuleElement(ZoneStringList* labels,
|
| }
|
|
|
|
|
| -Block* Parser::ParseModuleDeclaration(bool* ok) {
|
| +Block* Parser::ParseModuleDeclaration(ZoneStringList* names, bool* ok) {
|
| // ModuleDeclaration:
|
| // 'module' Identifier Module
|
|
|
| @@ -1229,6 +1229,7 @@ Block* Parser::ParseModuleDeclaration(bool* ok) {
|
|
|
| // TODO(rossberg): Add initialization statement to block.
|
|
|
| + if (names) names->Add(name);
|
| return block;
|
| }
|
|
|
| @@ -1236,19 +1237,26 @@ Block* Parser::ParseModuleDeclaration(bool* ok) {
|
| Module* Parser::ParseModule(bool* ok) {
|
| // Module:
|
| // '{' ModuleElement '}'
|
| - // '=' ModulePath
|
| - // 'at' String
|
| + // '=' ModulePath ';'
|
| + // 'at' String ';'
|
|
|
| switch (peek()) {
|
| case Token::LBRACE:
|
| return ParseModuleLiteral(ok);
|
|
|
| - case Token::ASSIGN:
|
| + case Token::ASSIGN: {
|
| Expect(Token::ASSIGN, CHECK_OK);
|
| - return ParseModulePath(ok);
|
| + Module* result = ParseModulePath(CHECK_OK);
|
| + ExpectSemicolon(CHECK_OK);
|
| + return result;
|
| + }
|
|
|
| - default:
|
| - return ParseModuleUrl(ok);
|
| + default: {
|
| + ExpectContextualKeyword("at", CHECK_OK);
|
| + Module* result = ParseModuleUrl(CHECK_OK);
|
| + ExpectSemicolon(CHECK_OK);
|
| + return result;
|
| + }
|
| }
|
| }
|
|
|
| @@ -1317,31 +1325,122 @@ Module* Parser::ParseModuleVariable(bool* ok) {
|
|
|
| Module* Parser::ParseModuleUrl(bool* ok) {
|
| // Module:
|
| - // 'at' String
|
| + // String
|
|
|
| - Expect(Token::IDENTIFIER, CHECK_OK);
|
| - Handle<String> symbol = GetSymbol(CHECK_OK);
|
| - if (!symbol->IsEqualTo(CStrVector("at"))) {
|
| - *ok = false;
|
| - ReportUnexpectedToken(scanner().current_token());
|
| - return NULL;
|
| - }
|
| Expect(Token::STRING, CHECK_OK);
|
| - symbol = GetSymbol(CHECK_OK);
|
| + Handle<String> symbol = GetSymbol(CHECK_OK);
|
|
|
| return factory()->NewModuleUrl(symbol);
|
| }
|
|
|
|
|
| +Module* Parser::ParseModuleSpecifier(bool* ok) {
|
| + // ModuleSpecifier:
|
| + // String
|
| + // ModulePath
|
| +
|
| + if (peek() == Token::STRING) {
|
| + return ParseModuleUrl(ok);
|
| + } else {
|
| + return ParseModulePath(ok);
|
| + }
|
| +}
|
| +
|
| +
|
| Block* Parser::ParseImportDeclaration(bool* ok) {
|
| - // TODO(rossberg)
|
| - return NULL;
|
| + // ImportDeclaration:
|
| + // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
|
| + //
|
| + // TODO(ES6): implement destructuring ImportSpecifiers
|
| +
|
| + Expect(Token::IMPORT, CHECK_OK);
|
| + ZoneStringList names(1);
|
| +
|
| + Handle<String> name = ParseIdentifierName(CHECK_OK);
|
| + while (peek() == Token::COMMA) {
|
| + Consume(Token::COMMA);
|
| + name = ParseIdentifierName(CHECK_OK);
|
| + names.Add(name);
|
| + }
|
| +
|
| + ExpectContextualKeyword("from", CHECK_OK);
|
| + Module* module = ParseModuleSpecifier(CHECK_OK);
|
| + ExpectSemicolon(CHECK_OK);
|
| +
|
| + // Generate a separate declaration for each identifier.
|
| + // TODO(ES6): once we implement destructuring, make that one declaration.
|
| + Block* block = factory()->NewBlock(NULL, 1, true);
|
| + for (int i = 0; i < names.length(); ++i) {
|
| + VariableProxy* proxy = NewUnresolved(names[i], LET);
|
| + Declaration* declaration =
|
| + factory()->NewImportDeclaration(proxy, module, top_scope_);
|
| + Declare(declaration, true, CHECK_OK);
|
| + // TODO(rossberg): Add initialization statement to block.
|
| + }
|
| +
|
| +
|
| + return block;
|
| }
|
|
|
|
|
| -Block* Parser::ParseExportDeclaration(bool* ok) {
|
| - // TODO(rossberg)
|
| - return NULL;
|
| +Statement* Parser::ParseExportDeclaration(bool* ok) {
|
| + // ExportDeclaration:
|
| + // 'export' Identifier (',' Identifier)* ';'
|
| + // 'export' VariableDeclaration
|
| + // 'export' FunctionDeclaration
|
| + // 'export' ModuleDeclaration
|
| + //
|
| + // TODO(ES6): implement structuring ExportSpecifiers
|
| +
|
| + Expect(Token::EXPORT, CHECK_OK);
|
| +
|
| + Statement* result = NULL;
|
| + ZoneStringList names(1);
|
| + switch (peek()) {
|
| + case Token::IDENTIFIER: {
|
| + Handle<String> name = ParseIdentifier(CHECK_OK);
|
| + // Handle 'module' as a context-sensitive keyword.
|
| + if (!name->IsEqualTo(CStrVector("module"))) {
|
| + names.Add(name);
|
| + while (peek() == Token::COMMA) {
|
| + Consume(Token::COMMA);
|
| + name = ParseIdentifier(CHECK_OK);
|
| + names.Add(name);
|
| + }
|
| + ExpectSemicolon(CHECK_OK);
|
| + result = factory()->NewEmptyStatement();
|
| + } else {
|
| + result = ParseModuleDeclaration(&names, CHECK_OK);
|
| + }
|
| + break;
|
| + }
|
| +
|
| + case Token::FUNCTION:
|
| + result = ParseFunctionDeclaration(&names, CHECK_OK);
|
| + break;
|
| +
|
| + case Token::VAR:
|
| + case Token::LET:
|
| + case Token::CONST:
|
| + result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
|
| + break;
|
| +
|
| + default:
|
| + *ok = false;
|
| + ReportUnexpectedToken(scanner().current_token());
|
| + return NULL;
|
| + }
|
| +
|
| + // Extract declared names into export declarations.
|
| + for (int i = 0; i < names.length(); ++i) {
|
| + VariableProxy* proxy = NewUnresolved(names[i], LET);
|
| + Declaration* declaration =
|
| + factory()->NewExportDeclaration(proxy, top_scope_);
|
| + top_scope_->AddDeclaration(declaration);
|
| + }
|
| +
|
| + ASSERT(result != NULL);
|
| + return result;
|
| }
|
|
|
|
|
| @@ -1359,10 +1458,10 @@ Statement* Parser::ParseBlockElement(ZoneStringList* labels,
|
|
|
| switch (peek()) {
|
| case Token::FUNCTION:
|
| - return ParseFunctionDeclaration(ok);
|
| + return ParseFunctionDeclaration(NULL, ok);
|
| case Token::LET:
|
| case Token::CONST:
|
| - return ParseVariableStatement(kModuleElement, ok);
|
| + return ParseVariableStatement(kModuleElement, NULL, ok);
|
| default:
|
| return ParseStatement(labels, ok);
|
| }
|
| @@ -1404,7 +1503,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
|
| case Token::CONST: // fall through
|
| case Token::LET:
|
| case Token::VAR:
|
| - stmt = ParseVariableStatement(kStatement, ok);
|
| + stmt = ParseVariableStatement(kStatement, NULL, ok);
|
| break;
|
|
|
| case Token::SEMICOLON:
|
| @@ -1481,7 +1580,7 @@ Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
|
| *ok = false;
|
| return NULL;
|
| }
|
| - return ParseFunctionDeclaration(ok);
|
| + return ParseFunctionDeclaration(NULL, ok);
|
| }
|
|
|
| case Token::DEBUGGER:
|
| @@ -1708,7 +1807,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
|
| }
|
|
|
|
|
| -Statement* Parser::ParseFunctionDeclaration(bool* ok) {
|
| +Statement* Parser::ParseFunctionDeclaration(ZoneStringList* names, bool* ok) {
|
| // FunctionDeclaration ::
|
| // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
|
| Expect(Token::FUNCTION, CHECK_OK);
|
| @@ -1729,6 +1828,7 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
|
| Declaration* declaration =
|
| factory()->NewFunctionDeclaration(proxy, mode, fun, top_scope_);
|
| Declare(declaration, true, CHECK_OK);
|
| + if (names) names->Add(name);
|
| return factory()->NewEmptyStatement();
|
| }
|
|
|
| @@ -1795,13 +1895,14 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
|
|
|
|
|
| Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
|
| + ZoneStringList* names,
|
| bool* ok) {
|
| // VariableStatement ::
|
| // VariableDeclarations ';'
|
|
|
| Handle<String> ignore;
|
| Block* result =
|
| - ParseVariableDeclarations(var_context, NULL, &ignore, CHECK_OK);
|
| + ParseVariableDeclarations(var_context, NULL, names, &ignore, CHECK_OK);
|
| ExpectSemicolon(CHECK_OK);
|
| return result;
|
| }
|
| @@ -1821,6 +1922,7 @@ bool Parser::IsEvalOrArguments(Handle<String> string) {
|
| Block* Parser::ParseVariableDeclarations(
|
| VariableDeclarationContext var_context,
|
| VariableDeclarationProperties* decl_props,
|
| + ZoneStringList* names,
|
| Handle<String>* out,
|
| bool* ok) {
|
| // VariableDeclarations ::
|
| @@ -1965,6 +2067,7 @@ Block* Parser::ParseVariableDeclarations(
|
| *ok = false;
|
| return NULL;
|
| }
|
| + if (names) names->Add(name);
|
|
|
| // Parse initialization expression if present and/or needed. A
|
| // declaration of the form:
|
| @@ -2617,7 +2720,7 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| if (peek() == Token::VAR || peek() == Token::CONST) {
|
| Handle<String> name;
|
| Block* variable_statement =
|
| - ParseVariableDeclarations(kForStatement, NULL, &name, CHECK_OK);
|
| + ParseVariableDeclarations(kForStatement, NULL, NULL, &name, CHECK_OK);
|
|
|
| if (peek() == Token::IN && !name.is_null()) {
|
| VariableProxy* each = top_scope_->NewUnresolved(factory(), name);
|
| @@ -2646,7 +2749,8 @@ Statement* Parser::ParseForStatement(ZoneStringList* labels, bool* ok) {
|
| Handle<String> name;
|
| VariableDeclarationProperties decl_props = kHasNoInitializers;
|
| Block* variable_statement =
|
| - ParseVariableDeclarations(kForStatement, &decl_props, &name, CHECK_OK);
|
| + ParseVariableDeclarations(kForStatement, &decl_props, NULL, &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
|
| @@ -4576,6 +4680,18 @@ void Parser::ExpectSemicolon(bool* ok) {
|
| }
|
|
|
|
|
| +void Parser::ExpectContextualKeyword(const char* keyword, bool* ok) {
|
| + Expect(Token::IDENTIFIER, ok);
|
| + if (!*ok) return;
|
| + Handle<String> symbol = GetSymbol(ok);
|
| + if (!*ok) return;
|
| + if (!symbol->IsEqualTo(CStrVector(keyword))) {
|
| + *ok = false;
|
| + ReportUnexpectedToken(scanner().current_token());
|
| + }
|
| +}
|
| +
|
| +
|
| Literal* Parser::GetLiteralUndefined() {
|
| return factory()->NewLiteral(isolate()->factory()->undefined_value());
|
| }
|
|
|