Begin modernization of --harmony-modules
authoradamk <adamk@chromium.org>
Tue, 27 Jan 2015 21:06:36 +0000 (13:06 -0800)
committerCommit bot <commit-bot@chromium.org>
Tue, 27 Jan 2015 21:06:46 +0000 (21:06 +0000)
The approach taken in this CL is to incrementally move toward the
currently-specced version of modules in ES6. The biggest change in this
patch is separating the parsing of modules from the parsing of scripts,
getting rid of the 'module' keyword and thus disallowing modules-in-scripts
as well as modules-in-modules.

The syntax supported by import/export declarations has not yet been significantly
changed, with the major exception being that import declarations require a string
as the 'from' part.

Most of the existing tests have been disabled, with a first new test added
in cctest/test-parsing.

BUG=v8:1569
LOG=n

Review URL: https://codereview.chromium.org/881623002

Cr-Commit-Position: refs/heads/master@{#26299}

src/ast-value-factory.h
src/compiler.h
src/parser.cc
src/parser.h
src/scopes.cc
test/cctest/cctest.status
test/cctest/test-decls.cc
test/cctest/test-parsing.cc
test/mjsunit/harmony/module-parsing.js
test/mjsunit/mjsunit.status

index a189f17..dd079d3 100644 (file)
@@ -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__")                                 \
index bd9b98c..f56d40a 100644 (file)
@@ -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<JSFunction> 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;
index 51e79bb..dff7de9 100644 (file)
@@ -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(
index e8e9769..fe3a9a8 100644 (file)
@@ -696,7 +696,7 @@ class Parser : public ParserBase<ParserTraits> {
   static const int kMaxNumFunctionLocals = 4194303;  // 2^22-1
 
   enum VariableDeclarationContext {
-    kModuleElement,
+    kStatementListItem,
     kStatement,
     kForStatement
   };
@@ -746,22 +746,14 @@ class Parser : public ParserBase<ParserTraits> {
   // 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<Statement*>* processor, int end_token,
-                            bool is_eval, bool is_global,
-                            Scope** ad_hoc_eval_scope, bool* ok);
-  Statement* ParseModuleElement(ZoneList<const AstRawString*>* labels,
-                                bool* ok);
-  Statement* ParseModuleDeclaration(ZoneList<const AstRawString*>* names,
-                                    bool* ok);
+  void* ParseStatementList(ZoneList<Statement*>* 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<const AstRawString*>* labels, bool* ok);
   Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
   Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
                                       bool* ok);
index 7687a4c..01e311e 100644 (file)
@@ -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) {
index 7a04e9c..15a4bab 100644 (file)
@@ -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],
index 06afdd2..bce4d8b 100644 (file)
@@ -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
   };
 
index f2b82cc..1a9c36c 100644 (file)
@@ -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<v8::Context> 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<char> program(kProgramByteSize + 1);
+  i::SNPrintF(program, "%s", kSource);
+  i::Handle<i::String> source =
+      factory->NewStringFromUtf8(i::CStrVector(program.start()))
+          .ToHandleChecked();
+
+  // Show that parsing as a module works
+  {
+    i::Handle<i::Script> 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<i::Script> 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());
+  }
+}
index 8a9103d..2f45326 100644 (file)
 
 // 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);
index 4a7bc7f..b23d7e5 100644 (file)
   '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],