Parsing of basic module declarations (no imports/exports yet).
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 20 Feb 2012 14:02:59 +0000 (14:02 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 20 Feb 2012 14:02:59 +0000 (14:02 +0000)
Module definitions are not compiled or otherwise executed yet.
Toplevel module identifiers are bound but never initialized.

R=kmillikin@chromium.org,mstarzinger@google.com
BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9401008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10759 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/ast.h
src/contexts.h
src/flag-definitions.h
src/heap.cc
src/heap.h
src/parser.cc
src/parser.h
src/prettyprinter.cc
src/runtime.cc
src/scopes.cc
src/scopes.h
src/v8globals.h
test/mjsunit/harmony/module-parsing.js [new file with mode: 0644]

index a634e5ecc8187c241ba51660dfc1bc1ec9edc856..60f9d43d83852c591f60fbbc01867c8c0bb4bc07 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -548,17 +548,17 @@ class ModuleVariable: public Module {
  public:
   DECLARE_NODE_TYPE(ModuleVariable)
 
-  Variable* var() const { return var_; }
+  VariableProxy* proxy() const { return proxy_; }
 
  protected:
   template<class> friend class AstNodeFactory;
 
-  explicit ModuleVariable(Variable* var)
-      : var_(var) {
+  explicit ModuleVariable(VariableProxy* proxy)
+      : proxy_(proxy) {
   }
 
  private:
-  Variable* var_;
+  VariableProxy* proxy_;
 };
 
 
@@ -2536,19 +2536,19 @@ class AstNodeFactory BASE_EMBEDDED {
     VISIT_AND_RETURN(ModuleLiteral, module)
   }
 
-  ModuleVariable* NewModuleVariable(Variable* var) {
-    ModuleVariable* module = new(zone_) ModuleVariable(var);
-    VISIT_AND_RETURN(ModuleLiteral, module)
+  ModuleVariable* NewModuleVariable(VariableProxy* proxy) {
+    ModuleVariable* module = new(zone_) ModuleVariable(proxy);
+    VISIT_AND_RETURN(ModuleVariable, module)
   }
 
   ModulePath* NewModulePath(Module* origin, Handle<String> name) {
     ModulePath* module = new(zone_) ModulePath(origin, name);
-    VISIT_AND_RETURN(ModuleLiteral, module)
+    VISIT_AND_RETURN(ModulePath, module)
   }
 
   ModuleUrl* NewModuleUrl(Handle<String> url) {
     ModuleUrl* module = new(zone_) ModuleUrl(url);
-    VISIT_AND_RETURN(ModuleLiteral, module)
+    VISIT_AND_RETURN(ModuleUrl, module)
   }
 
   Block* NewBlock(ZoneStringList* labels,
index 1f88c946de964f4155863d51fed6d0b6c287fb61..af5cb036c615bb212a91aae4cd1a3bff808ec1ea 100644 (file)
@@ -356,6 +356,10 @@ class Context: public FixedArray {
     Map* map = this->map();
     return map == map->GetHeap()->block_context_map();
   }
+  bool IsModuleContext() {
+    Map* map = this->map();
+    return map == map->GetHeap()->module_context_map();
+  }
 
   // Tells whether the global context is marked with out of memory.
   inline bool has_out_of_memory();
index 179ee02bd2c50c236b597667bc108a8b256df260..8a9ae9d84e764673ab19d7b0a22028212206d75e 100644 (file)
@@ -111,7 +111,8 @@ DEFINE_bool(use_strict, false, "enforce strict mode")
 
 DEFINE_bool(harmony_typeof, false, "enable harmony semantics for typeof")
 DEFINE_bool(harmony_scoping, false, "enable harmony block scoping")
-DEFINE_bool(harmony_modules, false, "enable harmony modules")
+DEFINE_bool(harmony_modules, false,
+            "enable harmony modules (implies block scoping)")
 DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
 DEFINE_bool(harmony_collections, false,
             "enable harmony collections (sets, maps, and weak maps)")
@@ -120,6 +121,7 @@ DEFINE_implication(harmony, harmony_scoping)
 DEFINE_implication(harmony, harmony_modules)
 DEFINE_implication(harmony, harmony_proxies)
 DEFINE_implication(harmony, harmony_collections)
+DEFINE_implication(harmony_modules, harmony_scoping)
 
 // Flags for experimental implementation features.
 DEFINE_bool(smi_only_arrays, true, "tracks arrays with only smi values")
index 1d01b582bbc07a669dbededbbb4646bafe064994..fc53eb3529190a3bb2316e9f8c5c771c9baa298b 100644 (file)
@@ -2230,6 +2230,12 @@ bool Heap::CreateInitialMaps() {
   }
   set_block_context_map(Map::cast(obj));
 
+  { MaybeObject* maybe_obj =
+        AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
+    if (!maybe_obj->ToObject(&obj)) return false;
+  }
+  set_module_context_map(Map::cast(obj));
+
   { MaybeObject* maybe_obj =
         AllocateMap(FIXED_ARRAY_TYPE, kVariableSizeSentinel);
     if (!maybe_obj->ToObject(&obj)) return false;
index f41dac536f04d8083fe3441a5aec7e159ec53ceb..bb5c37562e1c6ff16ed010509b7b2afc04309114 100644 (file)
@@ -130,6 +130,7 @@ namespace internal {
   V(Map, catch_context_map, CatchContextMap)                                   \
   V(Map, with_context_map, WithContextMap)                                     \
   V(Map, block_context_map, BlockContextMap)                                   \
+  V(Map, module_context_map, ModuleContextMap)                                 \
   V(Map, oddball_map, OddballMap)                                              \
   V(Map, message_object_map, JSMessageObjectMap)                               \
   V(Map, foreign_map, ForeignMap)                                              \
index 3b9b69b4fac4d4a1ac5ae5614f0422fa12954953..3dfab294c8b4610c98c3db3edeac3469c8d767ba 100644 (file)
@@ -654,6 +654,7 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info,
   return result;
 }
 
+
 FunctionLiteral* Parser::ParseLazy(CompilationInfo* info) {
   ZoneScope zone_scope(isolate(), DONT_DELETE_ON_EXIT);
   HistogramTimerScope timer(isolate()->counters()->parse_lazy());
@@ -1087,32 +1088,11 @@ class ThisNamedPropertyAssignmentFinder : public ParserFinder {
 };
 
 
-Statement* Parser::ParseSourceElement(ZoneStringList* labels,
-                                      bool* ok) {
-  // (Ecma 262 5th Edition, clause 14):
-  // SourceElement:
-  //    Statement
-  //    FunctionDeclaration
-  //
-  // In harmony mode we allow additionally the following productions
-  // SourceElement:
-  //    LetDeclaration
-  //    ConstDeclaration
-
-  if (peek() == Token::FUNCTION) {
-    return ParseFunctionDeclaration(ok);
-  } else if (peek() == Token::LET || peek() == Token::CONST) {
-    return ParseVariableStatement(kSourceElement, ok);
-  }
-  return ParseStatement(labels, ok);
-}
-
-
 void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
                                   int end_token,
                                   bool* ok) {
   // SourceElements ::
-  //   (SourceElement)* <end_token>
+  //   (ModuleElement)* <end_token>
 
   // Allocate a target stack to use for this set of source
   // elements. This way, all scripts and functions get their own
@@ -1131,7 +1111,7 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
     }
 
     Scanner::Location token_loc = scanner().peek_location();
-    Statement* stat = ParseSourceElement(NULL, CHECK_OK);
+    Statement* stat = ParseModuleElement(NULL, CHECK_OK);
     if (stat == NULL || stat->IsEmpty()) {
       directive_prologue = false;   // End of directive prologue.
       continue;
@@ -1187,6 +1167,194 @@ void* Parser::ParseSourceElements(ZoneList<Statement*>* processor,
 }
 
 
+Statement* Parser::ParseModuleElement(ZoneStringList* labels,
+                                      bool* ok) {
+  // (Ecma 262 5th Edition, clause 14):
+  // SourceElement:
+  //    Statement
+  //    FunctionDeclaration
+  //
+  // In harmony mode we allow additionally the following productions
+  // ModuleElement:
+  //    LetDeclaration
+  //    ConstDeclaration
+  //    ModuleDeclaration
+  //    ImportDeclaration
+  //    ExportDeclaration
+
+  switch (peek()) {
+    case Token::FUNCTION:
+      return ParseFunctionDeclaration(ok);
+    case Token::LET:
+    case Token::CONST:
+      return ParseVariableStatement(kModuleElement, ok);
+    case Token::MODULE:
+      return ParseModuleDeclaration(ok);
+    case Token::IMPORT:
+      return ParseImportDeclaration(ok);
+    case Token::EXPORT:
+      return ParseExportDeclaration(ok);
+    default:
+      return ParseStatement(labels, ok);
+  }
+}
+
+
+Block* Parser::ParseModuleDeclaration(bool* ok) {
+  // ModuleDeclaration:
+  //    'module' Identifier Module
+
+  // Create new block with one expected declaration.
+  Block* block = factory()->NewBlock(NULL, 1, true);
+  Expect(Token::MODULE, CHECK_OK);
+  Handle<String> name = ParseIdentifier(CHECK_OK);
+  // top_scope_->AddDeclaration(
+  //     factory()->NewModuleDeclaration(proxy, module, top_scope_));
+  VariableProxy* proxy = Declare(name, LET, NULL, true, CHECK_OK);
+  Module* module = ParseModule(ok);
+  // TODO(rossberg): Add initialization statement to block.
+  USE(proxy);
+  USE(module);
+  return block;
+}
+
+
+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);
+      return ParseModulePath(ok);
+
+    default:
+      return ParseModuleUrl(ok);
+  }
+}
+
+
+Module* Parser::ParseModuleLiteral(bool* ok) {
+  // Module:
+  //    '{' ModuleElement '}'
+
+  // Construct block expecting 16 statements.
+  Block* body = factory()->NewBlock(NULL, 16, false);
+  Scope* scope = NewScope(top_scope_, MODULE_SCOPE);
+
+  Expect(Token::LBRACE, CHECK_OK);
+  scope->set_start_position(scanner().location().beg_pos);
+  scope->SetLanguageMode(EXTENDED_MODE);
+
+  {
+    BlockState block_state(this, scope);
+    TargetCollector collector;
+    Target target(&this->target_stack_, &collector);
+    Target target_body(&this->target_stack_, body);
+    InitializationBlockFinder block_finder(top_scope_, target_stack_);
+
+    while (peek() != Token::RBRACE) {
+      Statement* stat = ParseModuleElement(NULL, CHECK_OK);
+      if (stat && !stat->IsEmpty()) {
+        body->AddStatement(stat);
+        block_finder.Update(stat);
+      }
+    }
+  }
+
+  Expect(Token::RBRACE, CHECK_OK);
+  scope->set_end_position(scanner().location().end_pos);
+  body->set_block_scope(scope);
+  return factory()->NewModuleLiteral(body);
+}
+
+
+Module* Parser::ParseModulePath(bool* ok) {
+  // ModulePath:
+  //    Identifier
+  //    ModulePath '.' Identifier
+
+  Module* result = ParseModuleVariable(CHECK_OK);
+
+  while (Check(Token::PERIOD)) {
+    Handle<String> name = ParseIdentifierName(CHECK_OK);
+    result = factory()->NewModulePath(result, name);
+  }
+
+  return result;
+}
+
+
+Module* Parser::ParseModuleVariable(bool* ok) {
+  // ModulePath:
+  //    Identifier
+
+  Handle<String> name = ParseIdentifier(CHECK_OK);
+  VariableProxy* proxy = top_scope_->NewUnresolved(
+      factory(), name, scanner().location().beg_pos);
+  return factory()->NewModuleVariable(proxy);
+}
+
+
+Module* Parser::ParseModuleUrl(bool* ok) {
+  // Module:
+  //    'at' 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);
+
+  return factory()->NewModuleUrl(symbol);
+}
+
+
+Block* Parser::ParseImportDeclaration(bool* ok) {
+  // TODO(rossberg)
+  return NULL;
+}
+
+
+Block* Parser::ParseExportDeclaration(bool* ok) {
+  // TODO(rossberg)
+  return NULL;
+}
+
+
+Statement* Parser::ParseBlockElement(ZoneStringList* 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
+
+  switch (peek()) {
+    case Token::FUNCTION:
+      return ParseFunctionDeclaration(ok);
+    case Token::LET:
+    case Token::CONST:
+      return ParseVariableStatement(kModuleElement, ok);
+    default:
+      return ParseStatement(labels, ok);
+  }
+}
+
+
 Statement* Parser::ParseStatement(ZoneStringList* labels, bool* ok) {
   // Statement ::
   //   Block
@@ -1344,7 +1512,8 @@ VariableProxy* Parser::Declare(Handle<String> name,
   // statically declared.
   if (declaration_scope->is_function_scope() ||
       declaration_scope->is_strict_or_extended_eval_scope() ||
-      declaration_scope->is_block_scope()) {
+      declaration_scope->is_block_scope() ||
+      declaration_scope->is_module_scope()) {
     // Declare the variable in the function scope.
     var = declaration_scope->LocalLookup(name);
     if (var == NULL) {
@@ -1574,10 +1743,10 @@ Block* Parser::ParseBlock(ZoneStringList* labels, bool* ok) {
 
 
 Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
-  // The harmony mode uses source elements instead of statements.
+  // The harmony mode uses block elements instead of statements.
   //
   // Block ::
-  //   '{' SourceElement* '}'
+  //   '{' BlockElement* '}'
 
   // Construct block expecting 16 statements.
   Block* body = factory()->NewBlock(labels, 16, false);
@@ -1593,7 +1762,7 @@ Block* Parser::ParseScopedBlock(ZoneStringList* labels, bool* ok) {
     InitializationBlockFinder block_finder(top_scope_, target_stack_);
 
     while (peek() != Token::RBRACE) {
-      Statement* stat = ParseSourceElement(NULL, CHECK_OK);
+      Statement* stat = ParseBlockElement(NULL, CHECK_OK);
       if (stat && !stat->IsEmpty()) {
         body->AddStatement(stat);
         block_finder.Update(stat);
@@ -1614,10 +1783,8 @@ Block* Parser::ParseVariableStatement(VariableDeclarationContext var_context,
   //   VariableDeclarations ';'
 
   Handle<String> ignore;
-  Block* result = ParseVariableDeclarations(var_context,
-                                            NULL,
-                                            &ignore,
-                                            CHECK_OK);
+  Block* result =
+      ParseVariableDeclarations(var_context, NULL, &ignore, CHECK_OK);
   ExpectSemicolon(CHECK_OK);
   return result;
 }
@@ -1684,8 +1851,7 @@ Block* Parser::ParseVariableDeclarations(
         *ok = false;
         return NULL;
       case EXTENDED_MODE:
-        if (var_context != kSourceElement &&
-            var_context != kForStatement) {
+        if (var_context == kStatement) {
           // In extended mode 'const' declarations are only allowed in source
           // element positions.
           ReportMessage("unprotected_const", Vector<const char*>::empty());
@@ -1710,10 +1876,8 @@ Block* Parser::ParseVariableDeclarations(
       return NULL;
     }
     Consume(Token::LET);
-    if (var_context != kSourceElement &&
-        var_context != kForStatement) {
+    if (var_context == kStatement) {
       // Let declarations are only allowed in source element positions.
-      ASSERT(var_context == kStatement);
       ReportMessage("unprotected_let", Vector<const char*>::empty());
       *ok = false;
       return NULL;
@@ -2453,10 +2617,7 @@ 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, &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
index fbc4a1529d71efe2372d5ce1fd34f23b0c536f7e..66c801d9817e081d603d6bb083942e1ea4737b27 100644 (file)
@@ -464,7 +464,8 @@ class Parser {
   };
 
   enum VariableDeclarationContext {
-    kSourceElement,
+    kModuleElement,
+    kBlockElement,
     kStatement,
     kForStatement
   };
@@ -575,7 +576,16 @@ class Parser {
   // for failure at the call sites.
   void* ParseSourceElements(ZoneList<Statement*>* processor,
                             int end_token, bool* ok);
-  Statement* ParseSourceElement(ZoneStringList* labels, bool* ok);
+  Statement* ParseModuleElement(ZoneStringList* labels, bool* ok);
+  Block* ParseModuleDeclaration(bool* ok);
+  Module* ParseModule(bool* ok);
+  Module* ParseModuleLiteral(bool* ok);
+  Module* ParseModulePath(bool* ok);
+  Module* ParseModuleVariable(bool* ok);
+  Module* ParseModuleUrl(bool* ok);
+  Block* ParseImportDeclaration(bool* ok);
+  Block* ParseExportDeclaration(bool* ok);
+  Statement* ParseBlockElement(ZoneStringList* labels, bool* ok);
   Statement* ParseStatement(ZoneStringList* labels, bool* ok);
   Statement* ParseFunctionDeclaration(bool* ok);
   Statement* ParseNativeDeclaration(bool* ok);
index 685e443e243584bb032ee7682cf83ee6a68fd274..f3ec75adcffb5488bc2d91f7ae1549ebf6f8bb6e 100644 (file)
@@ -84,7 +84,7 @@ void PrettyPrinter::VisitModuleLiteral(ModuleLiteral* node) {
 
 
 void PrettyPrinter::VisitModuleVariable(ModuleVariable* node) {
-  PrintLiteral(node->var()->name(), false);
+  Visit(node->proxy());
 }
 
 
@@ -773,7 +773,7 @@ void AstPrinter::VisitModuleLiteral(ModuleLiteral* node) {
 
 
 void AstPrinter::VisitModuleVariable(ModuleVariable* node) {
-  PrintLiteralIndented("VARIABLE", node->var()->name(), false);
+  Visit(node->proxy());
 }
 
 
index 4fc724b707f38e8045a2d50e02ae8861ced7c419..8a0915c894dba7b98c9a0cd0c35918220468cb2d 100644 (file)
@@ -11283,6 +11283,29 @@ static Handle<JSObject> MaterializeBlockScope(
 }
 
 
+// Create a plain JSObject which materializes the module scope for the specified
+// module context.
+static Handle<JSObject> MaterializeModuleScope(
+    Isolate* isolate,
+    Handle<Context> context) {
+  ASSERT(context->IsModuleContext());
+  Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
+
+  // Allocate and initialize a JSObject with all the members of the debugged
+  // module.
+  Handle<JSObject> module_scope =
+      isolate->factory()->NewJSObject(isolate->object_function());
+
+  // Fill all context locals.
+  if (!CopyContextLocalsToScopeObject(
+          isolate, scope_info, context, module_scope)) {
+    return Handle<JSObject>();
+  }
+
+  return module_scope;
+}
+
+
 // Iterate over the actual scopes visible from a stack frame. The iteration
 // proceeds from the innermost visible nested scope outwards. All scopes are
 // backed by an actual context except the local scope, which is inserted
@@ -11295,7 +11318,8 @@ class ScopeIterator {
     ScopeTypeWith,
     ScopeTypeClosure,
     ScopeTypeCatch,
-    ScopeTypeBlock
+    ScopeTypeBlock,
+    ScopeTypeModule
   };
 
   ScopeIterator(Isolate* isolate,
@@ -11418,6 +11442,9 @@ class ScopeIterator {
           ASSERT(context_->IsFunctionContext() ||
                  !scope_info->HasContext());
           return ScopeTypeLocal;
+        case MODULE_SCOPE:
+          ASSERT(context_->IsModuleContext());
+          return ScopeTypeModule;
         case GLOBAL_SCOPE:
           ASSERT(context_->IsGlobalContext());
           return ScopeTypeGlobal;
@@ -11448,6 +11475,9 @@ class ScopeIterator {
     if (context_->IsBlockContext()) {
       return ScopeTypeBlock;
     }
+    if (context_->IsModuleContext()) {
+      return ScopeTypeModule;
+    }
     ASSERT(context_->IsWithContext());
     return ScopeTypeWith;
   }
@@ -11471,6 +11501,8 @@ class ScopeIterator {
         return MaterializeClosure(isolate_, CurrentContext());
       case ScopeIterator::ScopeTypeBlock:
         return MaterializeBlockScope(isolate_, CurrentContext());
+      case ScopeIterator::ScopeTypeModule:
+        return MaterializeModuleScope(isolate_, CurrentContext());
     }
     UNREACHABLE();
     return Handle<JSObject>();
index 35d804dff6adfc42fbf5818b86f727d9b571ace4..9835108751a14c564a12caba8eb9bac92a1ee75a 100644 (file)
@@ -704,6 +704,7 @@ static const char* Header(ScopeType type) {
   switch (type) {
     case EVAL_SCOPE: return "eval";
     case FUNCTION_SCOPE: return "function";
+    case MODULE_SCOPE: return "module";
     case GLOBAL_SCOPE: return "global";
     case CATCH_SCOPE: return "catch";
     case BLOCK_SCOPE: return "block";
index 06202c493baa9ba43e3642238d96472460e73b33..5b645f29c20bfa66709410da56a1ba5172b4fc99 100644 (file)
@@ -263,6 +263,7 @@ class Scope: public ZoneObject {
   // Specific scope types.
   bool is_eval_scope() const { return type_ == EVAL_SCOPE; }
   bool is_function_scope() const { return type_ == FUNCTION_SCOPE; }
+  bool is_module_scope() const { return type_ == MODULE_SCOPE; }
   bool is_global_scope() const { return type_ == GLOBAL_SCOPE; }
   bool is_catch_scope() const { return type_ == CATCH_SCOPE; }
   bool is_block_scope() const { return type_ == BLOCK_SCOPE; }
index ff3ad8d7486163333f513839dc0ec746ef5eb50c..bfc5e2339048ca6863adb0f6ea89b8bd7594eaa1 100644 (file)
@@ -461,6 +461,7 @@ enum CallKind {
 enum ScopeType {
   EVAL_SCOPE,      // The top-level scope for an eval source.
   FUNCTION_SCOPE,  // The top-level scope for a function.
+  MODULE_SCOPE,    // The scope introduced by a module literal
   GLOBAL_SCOPE,    // The top-level scope for a program or a top-level eval.
   CATCH_SCOPE,     // The scope introduced by catch.
   BLOCK_SCOPE,     // The scope introduced by a new block.
diff --git a/test/mjsunit/harmony/module-parsing.js b/test/mjsunit/harmony/module-parsing.js
new file mode 100644 (file)
index 0000000..ac39863
--- /dev/null
@@ -0,0 +1,80 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-modules
+
+// Test basic module syntax, with and without ASI.
+
+module A {}
+
+module A1 = A
+module A2 = A;
+module A3 = A2
+
+module B {
+  var x
+  var x, y;
+  var x = 0, y
+  let x, y
+  let z = 1
+  const c = 9
+  function f() {}
+  module C {
+    let x
+    module D {}
+    let y
+  }
+  let zz = ""
+}
+
+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.F
+
+
+// Check that ASI does not interfere.
+
+module
+X
+{
+let x
+}
+
+module
+Y
+=
+X
+
+module
+Z
+at
+"file://local"