| Index: src/parser.cc
|
| diff --git a/src/parser.cc b/src/parser.cc
|
| index 51e79bb14cf1c6519de925d6bb1434e06ccc225f..dff7de9e6b25c9c9370c866ab5bd4f52646852a6 100644
|
| --- a/src/parser.cc
|
| +++ b/src/parser.cc
|
| @@ -265,6 +265,7 @@ void Parser::SetCachedData() {
|
|
|
| Scope* Parser::NewScope(Scope* parent, ScopeType scope_type) {
|
| DCHECK(ast_value_factory());
|
| + DCHECK(scope_type != MODULE_SCOPE || allow_harmony_modules());
|
| Scope* result = new (zone())
|
| Scope(isolate(), zone(), parent, scope_type, ast_value_factory());
|
| result->Initialize();
|
| @@ -934,8 +935,17 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
|
| ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone());
|
| bool ok = true;
|
| int beg_pos = scanner()->location().beg_pos;
|
| - ParseSourceElements(body, Token::EOS, info->is_eval(), true, eval_scope,
|
| - &ok);
|
| + if (info->is_module()) {
|
| + DCHECK(allow_harmony_modules());
|
| + Module* module = ParseModule(&ok);
|
| + if (ok) {
|
| + // TODO(adamk): Do something with returned Module
|
| + CHECK(module);
|
| + body->Add(factory()->NewEmptyStatement(RelocInfo::kNoPosition), zone());
|
| + }
|
| + } else {
|
| + ParseStatementList(body, Token::EOS, info->is_eval(), eval_scope, &ok);
|
| + }
|
|
|
| if (ok && strict_mode() == STRICT) {
|
| CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
|
| @@ -1080,11 +1090,10 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source) {
|
| }
|
|
|
|
|
| -void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| - int end_token, bool is_eval, bool is_global,
|
| - Scope** eval_scope, bool* ok) {
|
| - // SourceElements ::
|
| - // (ModuleElement)* <end_token>
|
| +void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
|
| + bool is_eval, Scope** eval_scope, bool* ok) {
|
| + // StatementList ::
|
| + // (StatementListItem)* <end_token>
|
|
|
| // Allocate a target stack to use for this set of source
|
| // elements. This way, all scripts and functions get their own
|
| @@ -1092,7 +1101,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| // functions.
|
| TargetScope scope(&this->target_stack_);
|
|
|
| - DCHECK(processor != NULL);
|
| + DCHECK(body != NULL);
|
| bool directive_prologue = true; // Parsing directive prologue.
|
|
|
| while (peek() != end_token) {
|
| @@ -1101,12 +1110,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| }
|
|
|
| Scanner::Location token_loc = scanner()->peek_location();
|
| - Statement* stat;
|
| - if (is_global && !is_eval) {
|
| - stat = ParseModuleElement(NULL, CHECK_OK);
|
| - } else {
|
| - stat = ParseBlockElement(NULL, CHECK_OK);
|
| - }
|
| + Statement* stat = ParseStatementListItem(CHECK_OK);
|
| if (stat == NULL || stat->IsEmpty()) {
|
| directive_prologue = false; // End of directive prologue.
|
| continue;
|
| @@ -1162,134 +1166,64 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
|
| }
|
| }
|
|
|
| - processor->Add(stat, zone());
|
| + body->Add(stat, zone());
|
| }
|
|
|
| return 0;
|
| }
|
|
|
|
|
| -Statement* Parser::ParseModuleElement(ZoneList<const AstRawString*>* labels,
|
| - bool* ok) {
|
| - // (Ecma 262 5th Edition, clause 14):
|
| - // SourceElement:
|
| +Statement* Parser::ParseStatementListItem(bool* ok) {
|
| + // (Ecma 262 6th Edition, 13.1):
|
| + // StatementListItem:
|
| // Statement
|
| - // FunctionDeclaration
|
| - //
|
| - // In harmony mode we allow additionally the following productions
|
| - // ModuleElement:
|
| - // LetDeclaration
|
| - // ConstDeclaration
|
| - // ModuleDeclaration
|
| - // ImportDeclaration
|
| - // ExportDeclaration
|
| - // GeneratorDeclaration
|
| + // Declaration
|
|
|
| switch (peek()) {
|
| case Token::FUNCTION:
|
| return ParseFunctionDeclaration(NULL, ok);
|
| case Token::CLASS:
|
| return ParseClassDeclaration(NULL, ok);
|
| - case Token::IMPORT:
|
| - return ParseImportDeclaration(ok);
|
| - case Token::EXPORT:
|
| - return ParseExportDeclaration(ok);
|
| case Token::CONST:
|
| - return ParseVariableStatement(kModuleElement, NULL, ok);
|
| + case Token::VAR:
|
| + return ParseVariableStatement(kStatementListItem, NULL, ok);
|
| case Token::LET:
|
| DCHECK(allow_harmony_scoping());
|
| if (strict_mode() == STRICT) {
|
| - return ParseVariableStatement(kModuleElement, NULL, ok);
|
| + return ParseVariableStatement(kStatementListItem, NULL, ok);
|
| }
|
| // Fall through.
|
| - default: {
|
| - Statement* stmt = ParseStatement(labels, CHECK_OK);
|
| - // Handle 'module' as a context-sensitive keyword.
|
| - if (FLAG_harmony_modules &&
|
| - peek() == Token::IDENTIFIER &&
|
| - !scanner()->HasAnyLineTerminatorBeforeNext() &&
|
| - stmt != NULL) {
|
| - ExpressionStatement* estmt = stmt->AsExpressionStatement();
|
| - if (estmt != NULL && estmt->expression()->AsVariableProxy() != NULL &&
|
| - estmt->expression()->AsVariableProxy()->raw_name() ==
|
| - ast_value_factory()->module_string() &&
|
| - !scanner()->literal_contains_escapes()) {
|
| - return ParseModuleDeclaration(NULL, ok);
|
| - }
|
| - }
|
| - return stmt;
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -Statement* Parser::ParseModuleDeclaration(ZoneList<const AstRawString*>* names,
|
| - bool* ok) {
|
| - // ModuleDeclaration:
|
| - // 'module' Identifier Module
|
| -
|
| - int pos = peek_position();
|
| - const AstRawString* name =
|
| - ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
| -
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interface_details)
|
| - PrintF("# Module %.*s ", name->length(), name->raw_data());
|
| -#endif
|
| -
|
| - Module* module = ParseModule(CHECK_OK);
|
| - VariableProxy* proxy = NewUnresolved(name, MODULE, module->interface());
|
| - Declaration* declaration =
|
| - factory()->NewModuleDeclaration(proxy, module, scope_, pos);
|
| - Declare(declaration, true, CHECK_OK);
|
| -
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interface_details)
|
| - PrintF("# Module %.*s ", name->length(), name->raw_data());
|
| - if (FLAG_print_interfaces) {
|
| - PrintF("module %.*s: ", name->length(), name->raw_data());
|
| - module->interface()->Print();
|
| + default:
|
| + return ParseStatement(NULL, ok);
|
| }
|
| -#endif
|
| -
|
| - if (names) names->Add(name, zone());
|
| - if (module->body() == NULL)
|
| - return factory()->NewEmptyStatement(pos);
|
| - else
|
| - return factory()->NewModuleStatement(proxy, module->body(), pos);
|
| }
|
|
|
|
|
| -Module* Parser::ParseModule(bool* ok) {
|
| - // Module:
|
| - // '{' ModuleElement '}'
|
| - // '=' ModulePath ';'
|
| - // 'at' String ';'
|
| +Statement* Parser::ParseModuleItem(bool* ok) {
|
| + // (Ecma 262 6th Edition, 15.2):
|
| + // ModuleItem :
|
| + // ImportDeclaration
|
| + // ExportDeclaration
|
| + // StatementListItem
|
|
|
| switch (peek()) {
|
| - case Token::LBRACE:
|
| - return ParseModuleLiteral(ok);
|
| -
|
| - case Token::ASSIGN: {
|
| - Expect(Token::ASSIGN, CHECK_OK);
|
| - Module* result = ParseModulePath(CHECK_OK);
|
| - ExpectSemicolon(CHECK_OK);
|
| - return result;
|
| - }
|
| -
|
| - default: {
|
| - ExpectContextualKeyword(CStrVector("at"), CHECK_OK);
|
| - Module* result = ParseModuleUrl(CHECK_OK);
|
| - ExpectSemicolon(CHECK_OK);
|
| - return result;
|
| - }
|
| + case Token::IMPORT:
|
| + return ParseImportDeclaration(ok);
|
| + case Token::EXPORT:
|
| + return ParseExportDeclaration(ok);
|
| + default:
|
| + return ParseStatementListItem(ok);
|
| }
|
| }
|
|
|
|
|
| -Module* Parser::ParseModuleLiteral(bool* ok) {
|
| - // Module:
|
| - // '{' ModuleElement '}'
|
| +Module* Parser::ParseModule(bool* ok) {
|
| + // (Ecma 262 6th Edition, 15.2):
|
| + // Module :
|
| + // ModuleBody?
|
| + //
|
| + // ModuleBody :
|
| + // ModuleItem*
|
|
|
| int pos = peek_position();
|
| // Construct block expecting 16 statements.
|
| @@ -1299,7 +1233,6 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
|
| #endif
|
| Scope* scope = NewScope(scope_, MODULE_SCOPE);
|
|
|
| - Expect(Token::LBRACE, CHECK_OK);
|
| scope->set_start_position(scanner()->location().beg_pos);
|
| scope->SetStrictMode(STRICT);
|
|
|
| @@ -1307,15 +1240,14 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
|
| BlockState block_state(&scope_, scope);
|
| Target target(&this->target_stack_, body);
|
|
|
| - while (peek() != Token::RBRACE) {
|
| - Statement* stat = ParseModuleElement(NULL, CHECK_OK);
|
| + while (peek() != Token::EOS) {
|
| + Statement* stat = ParseModuleItem(CHECK_OK);
|
| if (stat && !stat->IsEmpty()) {
|
| body->AddStatement(stat, zone());
|
| }
|
| }
|
| }
|
|
|
| - Expect(Token::RBRACE, CHECK_OK);
|
| scope->set_end_position(scanner()->location().end_pos);
|
| body->set_scope(scope);
|
|
|
| @@ -1338,60 +1270,6 @@ Module* Parser::ParseModuleLiteral(bool* ok) {
|
| }
|
|
|
|
|
| -Module* Parser::ParseModulePath(bool* ok) {
|
| - // ModulePath:
|
| - // Identifier
|
| - // ModulePath '.' Identifier
|
| -
|
| - int pos = peek_position();
|
| - Module* result = ParseModuleVariable(CHECK_OK);
|
| - while (Check(Token::PERIOD)) {
|
| - const AstRawString* name = ParseIdentifierName(CHECK_OK);
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interface_details)
|
| - PrintF("# Path .%.*s ", name->length(), name->raw_data());
|
| -#endif
|
| - Module* member = factory()->NewModulePath(result, name, pos);
|
| - result->interface()->Add(name, member->interface(), zone(), ok);
|
| - if (!*ok) {
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interfaces) {
|
| - PrintF("PATH TYPE ERROR at '%.*s'\n", name->length(), name->raw_data());
|
| - PrintF("result: ");
|
| - result->interface()->Print();
|
| - PrintF("member: ");
|
| - member->interface()->Print();
|
| - }
|
| -#endif
|
| - ParserTraits::ReportMessage("invalid_module_path", name);
|
| - return NULL;
|
| - }
|
| - result = member;
|
| - }
|
| -
|
| - return result;
|
| -}
|
| -
|
| -
|
| -Module* Parser::ParseModuleVariable(bool* ok) {
|
| - // ModulePath:
|
| - // Identifier
|
| -
|
| - int pos = peek_position();
|
| - const AstRawString* name =
|
| - ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interface_details)
|
| - PrintF("# Module variable %.*s ", name->length(), name->raw_data());
|
| -#endif
|
| - VariableProxy* proxy = scope_->NewUnresolved(
|
| - factory(), name, Interface::NewModule(zone()),
|
| - scanner()->location().beg_pos);
|
| -
|
| - return factory()->NewModuleVariable(proxy, pos);
|
| -}
|
| -
|
| -
|
| Module* Parser::ParseModuleUrl(bool* ok) {
|
| // Module:
|
| // String
|
| @@ -1421,24 +1299,11 @@ Module* Parser::ParseModuleUrl(bool* ok) {
|
| }
|
|
|
|
|
| -Module* Parser::ParseModuleSpecifier(bool* ok) {
|
| - // ModuleSpecifier:
|
| - // String
|
| - // ModulePath
|
| -
|
| - if (peek() == Token::STRING) {
|
| - return ParseModuleUrl(ok);
|
| - } else {
|
| - return ParseModulePath(ok);
|
| - }
|
| -}
|
| -
|
| -
|
| -Block* Parser::ParseImportDeclaration(bool* ok) {
|
| +Statement* Parser::ParseImportDeclaration(bool* ok) {
|
| // ImportDeclaration:
|
| - // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleSpecifier ';'
|
| + // 'import' IdentifierName (',' IdentifierName)* 'from' ModuleUrl ';'
|
| //
|
| - // TODO(ES6): implement destructuring ImportSpecifiers
|
| + // TODO(ES6): implement current syntax
|
|
|
| int pos = peek_position();
|
| Expect(Token::IMPORT, CHECK_OK);
|
| @@ -1453,38 +1318,17 @@ Block* Parser::ParseImportDeclaration(bool* ok) {
|
| }
|
|
|
| ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
|
| - Module* module = ParseModuleSpecifier(CHECK_OK);
|
| + Module* module = ParseModuleUrl(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, RelocInfo::kNoPosition);
|
| + // TODO(ES6): Do something with ParseModuleUrl's return value.
|
| + USE(module);
|
| +
|
| for (int i = 0; i < names.length(); ++i) {
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interface_details)
|
| - PrintF("# Import %.*s ", name->length(), name->raw_data());
|
| -#endif
|
| - Interface* interface = Interface::NewUnknown(zone());
|
| - module->interface()->Add(names[i], interface, zone(), ok);
|
| - if (!*ok) {
|
| -#ifdef DEBUG
|
| - if (FLAG_print_interfaces) {
|
| - PrintF("IMPORT TYPE ERROR at '%.*s'\n", name->length(),
|
| - name->raw_data());
|
| - PrintF("module: ");
|
| - module->interface()->Print();
|
| - }
|
| -#endif
|
| - ParserTraits::ReportMessage("invalid_module_path", name);
|
| - return NULL;
|
| - }
|
| - VariableProxy* proxy = NewUnresolved(names[i], LET, interface);
|
| - Declaration* declaration =
|
| - factory()->NewImportDeclaration(proxy, module, scope_, pos);
|
| - Declare(declaration, true, CHECK_OK);
|
| + // TODO(ES6): Add an appropriate declaration for each name
|
| }
|
|
|
| - return block;
|
| + return factory()->NewEmptyStatement(pos);
|
| }
|
|
|
|
|
| @@ -1496,7 +1340,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
| // 'export' GeneratorDeclaration
|
| // 'export' ModuleDeclaration
|
| //
|
| - // TODO(ES6): implement structuring ExportSpecifiers
|
| + // TODO(ES6): implement current syntax
|
|
|
| Expect(Token::EXPORT, CHECK_OK);
|
|
|
| @@ -1507,19 +1351,14 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
| int pos = position();
|
| const AstRawString* name =
|
| ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
|
| - // Handle 'module' as a context-sensitive keyword.
|
| - if (name != ast_value_factory()->module_string()) {
|
| + names.Add(name, zone());
|
| + while (peek() == Token::COMMA) {
|
| + Consume(Token::COMMA);
|
| + 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());
|
| - }
|
| - ExpectSemicolon(CHECK_OK);
|
| - result = factory()->NewEmptyStatement(pos);
|
| - } else {
|
| - result = ParseModuleDeclaration(&names, CHECK_OK);
|
| }
|
| + ExpectSemicolon(CHECK_OK);
|
| + result = factory()->NewEmptyStatement(pos);
|
| break;
|
| }
|
|
|
| @@ -1534,7 +1373,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
| case Token::VAR:
|
| case Token::LET:
|
| case Token::CONST:
|
| - result = ParseVariableStatement(kModuleElement, &names, CHECK_OK);
|
| + result = ParseVariableStatement(kStatementListItem, &names, CHECK_OK);
|
| break;
|
|
|
| default:
|
| @@ -1581,39 +1420,6 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
|
| }
|
|
|
|
|
| -Statement* Parser::ParseBlockElement(ZoneList<const AstRawString*>* labels,
|
| - bool* ok) {
|
| - // (Ecma 262 5th Edition, clause 14):
|
| - // SourceElement:
|
| - // Statement
|
| - // FunctionDeclaration
|
| - //
|
| - // In harmony mode we allow additionally the following productions
|
| - // BlockElement (aka SourceElement):
|
| - // LetDeclaration
|
| - // ConstDeclaration
|
| - // GeneratorDeclaration
|
| - // ClassDeclaration
|
| -
|
| - switch (peek()) {
|
| - case Token::FUNCTION:
|
| - return ParseFunctionDeclaration(NULL, ok);
|
| - case Token::CLASS:
|
| - return ParseClassDeclaration(NULL, ok);
|
| - case Token::CONST:
|
| - return ParseVariableStatement(kModuleElement, NULL, ok);
|
| - case Token::LET:
|
| - DCHECK(allow_harmony_scoping());
|
| - if (strict_mode() == STRICT) {
|
| - return ParseVariableStatement(kModuleElement, NULL, ok);
|
| - }
|
| - // Fall through.
|
| - default:
|
| - return ParseStatement(labels, ok);
|
| - }
|
| -}
|
| -
|
| -
|
| Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
|
| bool* ok) {
|
| // Statement ::
|
| @@ -2067,7 +1873,7 @@ Block* Parser::ParseScopedBlock(ZoneList<const AstRawString*>* labels,
|
| Target target(&this->target_stack_, body);
|
|
|
| while (peek() != Token::RBRACE) {
|
| - Statement* stat = ParseBlockElement(NULL, CHECK_OK);
|
| + Statement* stat = ParseStatementListItem(CHECK_OK);
|
| if (stat && !stat->IsEmpty()) {
|
| body->AddStatement(stat, zone());
|
| }
|
| @@ -2482,24 +2288,16 @@ Statement* Parser::ParseExpressionOrLabelledStatement(
|
| return ParseNativeDeclaration(ok);
|
| }
|
|
|
| - // Parsed expression statement, or the context-sensitive 'module' keyword.
|
| - // Only expect semicolon in the former case.
|
| - // Also detect attempts at 'let' declarations in sloppy mode.
|
| - if (!FLAG_harmony_modules || peek() != Token::IDENTIFIER ||
|
| - scanner()->HasAnyLineTerminatorBeforeNext() ||
|
| - expr->AsVariableProxy() == NULL ||
|
| - expr->AsVariableProxy()->raw_name() !=
|
| - ast_value_factory()->module_string() ||
|
| - scanner()->literal_contains_escapes()) {
|
| - if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
|
| - expr->AsVariableProxy()->raw_name() ==
|
| - ast_value_factory()->let_string()) {
|
| - ReportMessage("sloppy_lexical", NULL);
|
| - *ok = false;
|
| - return NULL;
|
| - }
|
| - ExpectSemicolon(CHECK_OK);
|
| + // Parsed expression statement, followed by semicolon.
|
| + // Detect attempts at 'let' declarations in sloppy mode.
|
| + if (peek() == Token::IDENTIFIER && expr->AsVariableProxy() != NULL &&
|
| + expr->AsVariableProxy()->raw_name() ==
|
| + ast_value_factory()->let_string()) {
|
| + ReportMessage("sloppy_lexical", NULL);
|
| + *ok = false;
|
| + return NULL;
|
| }
|
| + ExpectSemicolon(CHECK_OK);
|
| return factory()->NewExpressionStatement(expr, pos);
|
| }
|
|
|
| @@ -3913,7 +3711,7 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
| yield, RelocInfo::kNoPosition), zone());
|
| }
|
|
|
| - ParseSourceElements(body, Token::RBRACE, false, false, NULL, CHECK_OK);
|
| + ParseStatementList(body, Token::RBRACE, false, NULL, CHECK_OK);
|
|
|
| if (is_generator) {
|
| VariableProxy* get_proxy = factory()->NewVariableProxy(
|
|
|