diff --git a/src/ast-value-factory.h b/src/ast-value-factory.h index a189f173b5..dd079d3ebd 100644 --- a/src/ast-value-factory.h +++ b/src/ast-value-factory.h @@ -253,7 +253,6 @@ class AstValue : public ZoneObject { F(make_reference_error, "MakeReferenceErrorEmbedded") \ F(make_syntax_error, "MakeSyntaxErrorEmbedded") \ F(make_type_error, "MakeTypeErrorEmbedded") \ - F(module, "module") \ F(native, "native") \ F(next, "next") \ F(proto, "__proto__") \ diff --git a/src/compiler.h b/src/compiler.h index bd9b98c745..f56d40a8f9 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -89,7 +89,8 @@ class CompilationInfo { kInliningEnabled = 1 << 17, kTypingEnabled = 1 << 18, kDisableFutureOptimization = 1 << 19, - kToplevel = 1 << 20 + kModule = 1 << 20, + kToplevel = 1 << 21 }; CompilationInfo(Handle closure, Zone* zone); @@ -105,6 +106,7 @@ class CompilationInfo { bool is_lazy() const { return GetFlag(kLazy); } bool is_eval() const { return GetFlag(kEval); } bool is_global() const { return GetFlag(kGlobal); } + bool is_module() const { return GetFlag(kModule); } StrictMode strict_mode() const { return GetFlag(kStrictMode) ? STRICT : SLOPPY; } @@ -146,6 +148,11 @@ class CompilationInfo { SetFlag(kGlobal); } + void MarkAsModule() { + DCHECK(!is_lazy()); + SetFlag(kModule); + } + void set_parameter_count(int parameter_count) { DCHECK(IsStub()); parameter_count_ = parameter_count; diff --git a/src/parser.cc b/src/parser.cc index 51e79bb14c..dff7de9e6b 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* body = new(zone()) ZoneList(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* processor, - int end_token, bool is_eval, bool is_global, - Scope** eval_scope, bool* ok) { - // SourceElements :: - // (ModuleElement)* +void* Parser::ParseStatementList(ZoneList* body, int end_token, + bool is_eval, Scope** eval_scope, bool* ok) { + // StatementList :: + // (StatementListItem)* // 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* 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* 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* processor, } } - processor->Add(stat, zone()); + body->Add(stat, zone()); } return 0; } -Statement* Parser::ParseModuleElement(ZoneList* 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::CONST: + case Token::VAR: + return ParseVariableStatement(kStatementListItem, NULL, ok); + case Token::LET: + DCHECK(allow_harmony_scoping()); + if (strict_mode() == STRICT) { + return ParseVariableStatement(kStatementListItem, NULL, ok); + } + // Fall through. + default: + return ParseStatement(NULL, ok); + } +} + + +Statement* Parser::ParseModuleItem(bool* ok) { + // (Ecma 262 6th Edition, 15.2): + // ModuleItem : + // ImportDeclaration + // ExportDeclaration + // StatementListItem + + switch (peek()) { case Token::IMPORT: return ParseImportDeclaration(ok); case Token::EXPORT: return ParseExportDeclaration(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: { - 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; - } + default: + return ParseStatementListItem(ok); } } -Statement* Parser::ParseModuleDeclaration(ZoneList* 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(); - } -#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 ';' - - 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; - } - } -} - - -Module* Parser::ParseModuleLiteral(bool* ok) { - // Module: - // '{' ModuleElement '}' + // (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* 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* labels, bool* ok) { // Statement :: @@ -2067,7 +1873,7 @@ Block* Parser::ParseScopedBlock(ZoneList* 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* 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( diff --git a/src/parser.h b/src/parser.h index e8e97695e0..fe3a9a8522 100644 --- a/src/parser.h +++ b/src/parser.h @@ -696,7 +696,7 @@ class Parser : public ParserBase { static const int kMaxNumFunctionLocals = 4194303; // 2^22-1 enum VariableDeclarationContext { - kModuleElement, + kStatementListItem, kStatement, kForStatement }; @@ -746,22 +746,14 @@ class Parser : public ParserBase { // which is set to false if parsing failed; it is unchanged otherwise. // By making the 'exception handling' explicit, we are forced to check // for failure at the call sites. - void* ParseSourceElements(ZoneList* processor, int end_token, - bool is_eval, bool is_global, - Scope** ad_hoc_eval_scope, bool* ok); - Statement* ParseModuleElement(ZoneList* labels, - bool* ok); - Statement* ParseModuleDeclaration(ZoneList* names, - bool* ok); + void* ParseStatementList(ZoneList* processor, int end_token, + bool is_eval, Scope** ad_hoc_eval_scope, bool* ok); + Statement* ParseStatementListItem(bool* ok); Module* ParseModule(bool* ok); - Module* ParseModuleLiteral(bool* ok); - Module* ParseModulePath(bool* ok); - Module* ParseModuleVariable(bool* ok); + Statement* ParseModuleItem(bool* ok); Module* ParseModuleUrl(bool* ok); - Module* ParseModuleSpecifier(bool* ok); - Block* ParseImportDeclaration(bool* ok); + Statement* ParseImportDeclaration(bool* ok); Statement* ParseExportDeclaration(bool* ok); - Statement* ParseBlockElement(ZoneList* labels, bool* ok); Statement* ParseStatement(ZoneList* labels, bool* ok); Statement* ParseFunctionDeclaration(ZoneList* names, bool* ok); diff --git a/src/scopes.cc b/src/scopes.cc index 7687a4cbb6..01e311e292 100644 --- a/src/scopes.cc +++ b/src/scopes.cc @@ -77,10 +77,8 @@ Scope::Scope(Isolate* isolate, Zone* zone, Scope* outer_scope, params_(4, zone), unresolved_(16, zone), decls_(4, zone), - interface_(FLAG_harmony_modules && (scope_type == MODULE_SCOPE || - scope_type == SCRIPT_SCOPE) - ? Interface::NewModule(zone) - : NULL), + interface_(scope_type == MODULE_SCOPE ? Interface::NewModule(zone) + : NULL), already_resolved_(false), ast_value_factory_(ast_value_factory), zone_(zone) { diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status index 7a04e9cd76..15a4bab28c 100644 --- a/test/cctest/cctest.status +++ b/test/cctest/cctest.status @@ -63,6 +63,9 @@ # are actually 13 * 38 * 5 * 128 = 316160 individual tests hidden here. 'test-parsing/ParserSync': [PASS, NO_VARIANTS], + # Modules are busted + 'test-parsing/ExportsMaybeAssigned': [SKIP], + # This tests only the type system, so there is no point in running several # variants. 'test-hydrogen-types/*': [PASS, NO_VARIANTS], diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc index 06afdd2be7..bce4d8b904 100644 --- a/test/cctest/test-decls.cc +++ b/test/cctest/test-decls.cc @@ -676,7 +676,6 @@ TEST(CrossScriptReferences_Simple2) { TEST(CrossScriptReferencesHarmony) { i::FLAG_harmony_scoping = true; - i::FLAG_harmony_modules = true; v8::Isolate* isolate = CcTest::isolate(); HandleScope scope(isolate); @@ -687,7 +686,6 @@ TEST(CrossScriptReferencesHarmony) { "'use strict'; function x() { return 1 }; x()", "x()", "'use strict'; let x = 1; x", "x", "'use strict'; const x = 1; x", "x", - "'use strict'; module x { export let a = 1 }; x.a", "x.a", NULL }; @@ -823,7 +821,6 @@ TEST(CrossScriptReferencesHarmony) { TEST(GlobalLexicalOSR) { i::FLAG_use_strict = true; i::FLAG_harmony_scoping = true; - i::FLAG_harmony_modules = true; v8::Isolate* isolate = CcTest::isolate(); HandleScope scope(isolate); @@ -848,7 +845,6 @@ TEST(GlobalLexicalOSR) { TEST(CrossScriptConflicts) { i::FLAG_use_strict = true; i::FLAG_harmony_scoping = true; - i::FLAG_harmony_modules = true; HandleScope scope(CcTest::isolate()); @@ -857,7 +853,6 @@ TEST(CrossScriptConflicts) { "function x() { return 1 }; x()", "let x = 1; x", "const x = 1; x", - "module x { export let a = 1 }; x.a", NULL }; const char* seconds[] = { @@ -865,7 +860,6 @@ TEST(CrossScriptConflicts) { "function x() { return 2 }; x()", "let x = 2; x", "const x = 2; x", - "module x { export let a = 2 }; x.a", NULL }; diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc index f2b82ccf98..1a9c36ce90 100644 --- a/test/cctest/test-parsing.cc +++ b/test/cctest/test-parsing.cc @@ -4668,3 +4668,57 @@ TEST(ComputedPropertyNameShorthandError) { RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags, arraysize(always_flags)); } + + +TEST(BasicImportExportParsing) { + const char kSource[] = + "export let x = 0;" + "import y from 'http://module.com/foo.js';" + "function f() {};" + "f();"; + + i::Isolate* isolate = CcTest::i_isolate(); + i::Factory* factory = isolate->factory(); + + v8::HandleScope handles(CcTest::isolate()); + v8::Handle context = v8::Context::New(CcTest::isolate()); + v8::Context::Scope context_scope(context); + + isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() - + 128 * 1024); + + int kProgramByteSize = i::StrLength(kSource); + i::ScopedVector program(kProgramByteSize + 1); + i::SNPrintF(program, "%s", kSource); + i::Handle source = + factory->NewStringFromUtf8(i::CStrVector(program.start())) + .ToHandleChecked(); + + // Show that parsing as a module works + { + i::Handle script = factory->NewScript(source); + i::CompilationInfoWithZone info(script); + i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(), + isolate->heap()->HashSeed(), + isolate->unicode_cache()}; + i::Parser parser(&info, &parse_info); + parser.set_allow_harmony_modules(true); + parser.set_allow_harmony_scoping(true); + info.MarkAsModule(); + CHECK(parser.Parse()); + } + + // And that parsing a script does not. + { + i::Handle script = factory->NewScript(source); + i::CompilationInfoWithZone info(script); + i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(), + isolate->heap()->HashSeed(), + isolate->unicode_cache()}; + i::Parser parser(&info, &parse_info); + parser.set_allow_harmony_modules(true); + parser.set_allow_harmony_scoping(true); + info.MarkAsGlobal(); + CHECK(!parser.Parse()); + } +} diff --git a/test/mjsunit/harmony/module-parsing.js b/test/mjsunit/harmony/module-parsing.js index 8a9103d132..2f45326512 100644 --- a/test/mjsunit/harmony/module-parsing.js +++ b/test/mjsunit/harmony/module-parsing.js @@ -27,164 +27,19 @@ // Flags: --harmony-modules -// Test basic module syntax, with and without automatic semicolon insertion. - -module A {} - -module A1 = A -module A2 = A; -module A3 = A2 - -module B { - export vx - export vy, lz, c, f - - var vx - var vx, vy; - var vx = 0, vy - let lx, ly - let lz = 1 - const c = 9 - function f() {} - - module C0 {} - - export module C { - let x - export module D { export let x } - let y - } - - let zz = "" - - export var x0 - export var x1, x2 = 6, x3 - export let y0 - export let y1 = 0, y2 - export const z0 = 0 - export const z1 = 2, z2 = 3 - export function f0() {} - export module M1 {} - export module M2 = C.D - export module M3 at "http://where" - - import i0 from I - import i1, i2, i3, M from I - //import i4, i5 from "http://where" -} - -module I { - export let i0, i1, i2, i3; - export module M {} -} - -module C1 = B.C; -module D1 = B.C.D -module D2 = C1.D -module D3 = D2 - -module E1 at "http://where" -module E2 at "http://where"; -module E3 = E1 - -// Check that ASI does not interfere. - -module X -{ -let x -} - -module Y -= -X - -module Z -at -"file://local" - -import -vx -, -vy -from -B - - -module Wrap { -export -x -, -y - -var -x -, -y - -export -var -v1 = 1 - -export -let -v2 = 2 - -export -const -v3 = 3 - -export -function -f -( -) -{ -} - -export -module V -{ -} -} - -export A, A1, A2, A3, B, I, C1, D1, D2, D3, E1, E2, E3, X, Y, Z, Wrap, x, y, UU - - - -// Check that 'module' still works as an identifier. - -var module -module = {} -module["a"] = 6 -function module() {} -function f(module) { return module } -try {} catch (module) {} - -module -v = 20 - - - -// Check that module declarations are rejected in eval or local scope. - -module M { export let x; } - -assertThrows("export x;", SyntaxError); // It's using eval, so should throw. +// Check that import/export declarations are rejected in eval or local scope. +assertThrows("export x;", SyntaxError); assertThrows("export let x;", SyntaxError); -assertThrows("import x from M;", SyntaxError); -assertThrows("module M {};", SyntaxError); +assertThrows("import x from 'http://url';", SyntaxError); assertThrows("{ export x; }", SyntaxError); assertThrows("{ export let x; }", SyntaxError); -assertThrows("{ import x from M; }", SyntaxError); -assertThrows("{ module M {}; }", SyntaxError); +assertThrows("{ import x from 'http://url'; }", SyntaxError); assertThrows("function f() { export x; }", SyntaxError); assertThrows("function f() { export let x; }", SyntaxError); -assertThrows("function f() { import x from M; }", SyntaxError); -assertThrows("function f() { module M {}; }", SyntaxError); +assertThrows("function f() { import x from 'http://url'; }", SyntaxError); assertThrows("function f() { { export x; } }", SyntaxError); assertThrows("function f() { { export let x; } }", SyntaxError); -assertThrows("function f() { { import x from M; } }", SyntaxError); -assertThrows("function f() { { module M {}; } }", SyntaxError); +assertThrows("function f() { { import x from 'http://url'; } }", SyntaxError); diff --git a/test/mjsunit/mjsunit.status b/test/mjsunit/mjsunit.status index 4a7bc7fd65..b23d7e530d 100644 --- a/test/mjsunit/mjsunit.status +++ b/test/mjsunit/mjsunit.status @@ -80,6 +80,12 @@ 'regress/regress-2185-2': [PASS, NO_VARIANTS], 'regress/regress-2612': [PASS, NO_VARIANTS], + # Modules are busted + 'harmony/module-linking': [SKIP], + 'harmony/module-recompile': [SKIP], + 'harmony/module-resolution': [SKIP], + 'harmony/regress/regress-343928': [SKIP], + # Issue 3660: Replacing activated TurboFan frames by unoptimized code does # not work, but we expect it to not crash. 'debug-step-turbofan': [PASS, FAIL],