Re-introduce ImportDeclaration to the parser
authoradamk <adamk@chromium.org>
Thu, 26 Feb 2015 18:40:50 +0000 (10:40 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 26 Feb 2015 18:41:04 +0000 (18:41 +0000)
This also adds a new VariableMode, IMPORT, which will be
used to do appropriate binding for Import-declared Variables.

Only named imports are handled for now. "import *" and default
import syntaxes have had their TODOs adjusted to match the new
code structure.

BUG=v8:1569
LOG=n

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

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

15 files changed:
src/ast-numbering.cc
src/ast.h
src/contexts.cc
src/globals.h
src/parser.cc
src/parser.h
src/prettyprinter.cc
src/runtime/runtime-scopes.cc
src/typing.cc
src/variables.cc
test/cctest/test-parsing.cc
test/message/import-as-redeclaration.js [new file with mode: 0644]
test/message/import-as-redeclaration.out [new file with mode: 0644]
test/message/import-redeclaration.js [new file with mode: 0644]
test/message/import-redeclaration.out [new file with mode: 0644]

index ea25ad8bbca4722f0deeb89be9f40a1d77004757..ff41bc19bd8a2ab1df318391ab3846e1f865f38c 100644 (file)
@@ -186,7 +186,6 @@ void AstNumberingVisitor::VisitImportDeclaration(ImportDeclaration* node) {
   IncrementNodeCount();
   DisableOptimization(kImportDeclaration);
   VisitVariableProxy(node->proxy());
-  Visit(node->module());
 }
 
 
index 735f2f92f9e680ab1c3eac43da348468fb688c6e..341c3470726cd2643baf0c670068d272330d8d28 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -609,23 +609,27 @@ class ImportDeclaration FINAL : public Declaration {
  public:
   DECLARE_NODE_TYPE(ImportDeclaration)
 
-  Module* module() const { return module_; }
+  const AstRawString* import_name() const { return import_name_; }
+  const AstRawString* module_specifier() const { return module_specifier_; }
+  void set_module_specifier(const AstRawString* module_specifier) {
+    DCHECK(module_specifier_ == NULL);
+    module_specifier_ = module_specifier;
+  }
   InitializationFlag initialization() const OVERRIDE {
-    return kCreatedInitialized;
+    return kNeedsInitialization;
   }
 
  protected:
-  ImportDeclaration(Zone* zone,
-                    VariableProxy* proxy,
-                    Module* module,
-                    Scope* scope,
-                    int pos)
-      : Declaration(zone, proxy, LET, scope, pos),
-        module_(module) {
-  }
+  ImportDeclaration(Zone* zone, VariableProxy* proxy,
+                    const AstRawString* import_name,
+                    const AstRawString* module_specifier, Scope* scope, int pos)
+      : Declaration(zone, proxy, IMPORT, scope, pos),
+        import_name_(import_name),
+        module_specifier_(module_specifier) {}
 
  private:
-  Module* module_;
+  const AstRawString* import_name_;
+  const AstRawString* module_specifier_;
 };
 
 
@@ -3168,10 +3172,11 @@ class AstNodeFactory FINAL BASE_EMBEDDED {
   }
 
   ImportDeclaration* NewImportDeclaration(VariableProxy* proxy,
-                                          Module* module,
-                                          Scope* scope,
-                                          int pos) {
-    return new (zone_) ImportDeclaration(zone_, proxy, module, scope, pos);
+                                          const AstRawString* import_name,
+                                          const AstRawString* module_specifier,
+                                          Scope* scope, int pos) {
+    return new (zone_) ImportDeclaration(zone_, proxy, import_name,
+                                         module_specifier, scope, pos);
   }
 
   ExportDeclaration* NewExportDeclaration(VariableProxy* proxy,
index 6537e2c3e260d5f8b1da53e04b0153e9c724d73e..667a57c4544c90877dc1c9aa3876d92ad26c5ff5 100644 (file)
@@ -173,6 +173,10 @@ static void GetAttributesAndBindingFlags(VariableMode mode,
                            ? IMMUTABLE_CHECK_INITIALIZED_HARMONY
                            : IMMUTABLE_IS_INITIALIZED_HARMONY;
       break;
+    case IMPORT:
+      // TODO(ES6)
+      UNREACHABLE();
+      break;
     case DYNAMIC:
     case DYNAMIC_GLOBAL:
     case DYNAMIC_LOCAL:
index 6bc0c52e0a8e1dfe2ca7e9bdb5e39f88492385a1..b0239b367cfd63ec6dd9c04bc03a9c5b6e462aff 100644 (file)
@@ -717,10 +717,12 @@ enum VariableMode {
 
   CONST_LEGACY,    // declared via legacy 'const' declarations
 
-  LET,             // declared via 'let' declarations
+  LET,             // declared via 'let' declarations (first lexical)
 
   CONST,           // declared via 'const' declarations
 
+  IMPORT,          // declared via 'import' declarations (last lexical)
+
   // Variables introduced by the compiler:
   INTERNAL,        // like VAR, but not user-visible (may or may not
                    // be in a context)
@@ -748,17 +750,17 @@ inline bool IsDynamicVariableMode(VariableMode mode) {
 
 
 inline bool IsDeclaredVariableMode(VariableMode mode) {
-  return mode >= VAR && mode <= CONST;
+  return mode >= VAR && mode <= IMPORT;
 }
 
 
 inline bool IsLexicalVariableMode(VariableMode mode) {
-  return mode == LET || mode == CONST;
+  return mode >= LET && mode <= IMPORT;
 }
 
 
 inline bool IsImmutableVariableMode(VariableMode mode) {
-  return mode == CONST || mode == CONST_LEGACY;
+  return mode == CONST || mode == CONST_LEGACY || mode == IMPORT;
 }
 
 
index 3a81127b482b4fc3ba3f33c9e87396fa71d1e425..f4828a0d5ca5f9a1e13c1ee934f8f4b043a62e1a 100644 (file)
@@ -1284,13 +1284,12 @@ void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
 }
 
 
-Literal* Parser::ParseModuleSpecifier(bool* ok) {
+const AstRawString* Parser::ParseModuleSpecifier(bool* ok) {
   // ModuleSpecifier :
   //    StringLiteral
 
-  int pos = peek_position();
   Expect(Token::STRING, CHECK_OK);
-  return factory()->NewStringLiteral(GetSymbol(scanner()), pos);
+  return GetSymbol(scanner());
 }
 
 
@@ -1342,9 +1341,7 @@ void* Parser::ParseExportClause(ZoneList<const AstRawString*>* export_names,
 }
 
 
-void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* import_names,
-                                ZoneList<const AstRawString*>* local_names,
-                                bool* ok) {
+ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
   // NamedImports :
   //   '{' '}'
   //   '{' ImportsList '}'
@@ -1360,6 +1357,8 @@ void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* import_names,
 
   Expect(Token::LBRACE, CHECK_OK);
 
+  ZoneList<ImportDeclaration*>* result =
+      new (zone()) ZoneList<ImportDeclaration*>(1, zone());
   while (peek() != Token::RBRACE) {
     const AstRawString* import_name = ParseIdentifierName(CHECK_OK);
     const AstRawString* local_name = import_name;
@@ -1378,15 +1377,18 @@ void* Parser::ParseNamedImports(ZoneList<const AstRawString*>* import_names,
       ReportMessage("strict_eval_arguments");
       return NULL;
     }
-    import_names->Add(import_name, zone());
-    local_names->Add(local_name, zone());
+    VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
+    ImportDeclaration* declaration =
+        factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
+    Declare(declaration, true, CHECK_OK);
+    result->Add(declaration, zone());
     if (peek() == Token::RBRACE) break;
     Expect(Token::COMMA, CHECK_OK);
   }
 
   Expect(Token::RBRACE, CHECK_OK);
 
-  return NULL;
+  return result;
 }
 
 
@@ -1412,7 +1414,7 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
 
   // 'import' ModuleSpecifier ';'
   if (tok == Token::STRING) {
-    Literal* module_specifier = ParseModuleSpecifier(CHECK_OK);
+    const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
     ExpectSemicolon(CHECK_OK);
     // TODO(ES6): Add module to the requested modules of scope_->module().
     USE(module_specifier);
@@ -1424,11 +1426,11 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
   if (tok != Token::MUL && tok != Token::LBRACE) {
     imported_default_binding =
         ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+    // TODO(ES6): Add an appropriate declaration.
   }
 
   const AstRawString* module_instance_binding = NULL;
-  ZoneList<const AstRawString*> local_names(1, zone());
-  ZoneList<const AstRawString*> import_names(1, zone());
+  ZoneList<ImportDeclaration*>* named_declarations = NULL;
   if (imported_default_binding == NULL || Check(Token::COMMA)) {
     switch (peek()) {
       case Token::MUL: {
@@ -1436,11 +1438,12 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
         ExpectContextualKeyword(CStrVector("as"), CHECK_OK);
         module_instance_binding =
             ParseIdentifier(kDontAllowEvalOrArguments, CHECK_OK);
+        // TODO(ES6): Add an appropriate declaration.
         break;
       }
 
       case Token::LBRACE:
-        ParseNamedImports(&import_names, &local_names, CHECK_OK);
+        named_declarations = ParseNamedImports(pos, CHECK_OK);
         break;
 
       default:
@@ -1451,23 +1454,21 @@ Statement* Parser::ParseImportDeclaration(bool* ok) {
   }
 
   ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
-  Literal* module = ParseModuleSpecifier(CHECK_OK);
-  USE(module);
-
+  const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
   ExpectSemicolon(CHECK_OK);
 
   if (module_instance_binding != NULL) {
-    // TODO(ES6): Bind name to the Module Instance Object of module.
+    // TODO(ES6): Set the module specifier for the module namespace binding.
   }
 
   if (imported_default_binding != NULL) {
-    // TODO(ES6): Add an appropriate declaration.
+    // TODO(ES6): Set the module specifier for the default binding.
   }
 
-  const int length = import_names.length();
-  DCHECK_EQ(length, local_names.length());
-  for (int i = 0; i < length; ++i) {
-    // TODO(ES6): Add an appropriate declaration for each name
+  if (named_declarations != NULL) {
+    for (int i = 0; i < named_declarations->length(); ++i) {
+      named_declarations->at(i)->set_module_specifier(module_specifier);
+    }
   }
 
   return factory()->NewEmptyStatement(pos);
@@ -1544,10 +1545,10 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
     case Token::MUL: {
       Consume(Token::MUL);
       ExpectContextualKeyword(CStrVector("from"), CHECK_OK);
-      Literal* module = ParseModuleSpecifier(CHECK_OK);
+      const AstRawString* module_specifier = ParseModuleSpecifier(CHECK_OK);
       ExpectSemicolon(CHECK_OK);
       // TODO(ES6): scope_->module()->AddStarExport(...)
-      USE(module);
+      USE(module_specifier);
       return factory()->NewEmptyStatement(pos);
     }
 
@@ -1569,7 +1570,7 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
       ZoneList<const AstRawString*> local_names(1, zone());
       ParseExportClause(&export_names, &export_locations, &local_names,
                         &reserved_loc, CHECK_OK);
-      Literal* indirect_export_module_specifier = NULL;
+      const AstRawString* indirect_export_module_specifier = NULL;
       if (CheckContextualKeyword(CStrVector("from"))) {
         indirect_export_module_specifier = ParseModuleSpecifier(CHECK_OK);
       } else if (reserved_loc.IsValid()) {
index 33b4f7107d77944ea9fb8c852a0ef2388868887a..882e2ac5f81a74a83bb902d2cc48e115c8e37731 100644 (file)
@@ -707,7 +707,7 @@ class Parser : public ParserBase<ParserTraits> {
   Statement* ParseStatementListItem(bool* ok);
   void* ParseModuleItemList(ZoneList<Statement*>* body, bool* ok);
   Statement* ParseModuleItem(bool* ok);
-  Literal* ParseModuleSpecifier(bool* ok);
+  const AstRawString* ParseModuleSpecifier(bool* ok);
   Statement* ParseImportDeclaration(bool* ok);
   Statement* ParseExportDeclaration(bool* ok);
   Statement* ParseExportDefault(bool* ok);
@@ -715,8 +715,7 @@ class Parser : public ParserBase<ParserTraits> {
                           ZoneList<Scanner::Location>* export_locations,
                           ZoneList<const AstRawString*>* local_names,
                           Scanner::Location* reserved_loc, bool* ok);
-  void* ParseNamedImports(ZoneList<const AstRawString*>* import_names,
-                          ZoneList<const AstRawString*>* local_names, bool* ok);
+  ZoneList<ImportDeclaration*>* ParseNamedImports(int pos, bool* ok);
   Statement* ParseStatement(ZoneList<const AstRawString*>* labels, bool* ok);
   Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels, bool* ok);
   Statement* ParseFunctionDeclaration(ZoneList<const AstRawString*>* names,
index da43d0eb0f870ad7097f80277d09f46fad47c41d..165e71721228ce6abae4820d27c50c52d53072d2 100644 (file)
@@ -106,7 +106,6 @@ void CallPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
 
 
 void CallPrinter::VisitImportDeclaration(ImportDeclaration* node) {
-  Find(node->module());
 }
 
 
@@ -481,7 +480,7 @@ void PrettyPrinter::VisitImportDeclaration(ImportDeclaration* node) {
   Print("import ");
   PrintLiteral(node->proxy()->name(), false);
   Print(" from ");
-  Visit(node->module());
+  PrintLiteral(node->module_specifier()->string(), true);
   Print(";");
 }
 
@@ -1213,7 +1212,7 @@ void AstPrinter::VisitModuleDeclaration(ModuleDeclaration* node) {
 void AstPrinter::VisitImportDeclaration(ImportDeclaration* node) {
   IndentedScope indent(this, "IMPORT");
   PrintLiteralIndented("NAME", node->proxy()->name(), true);
-  Visit(node->module());
+  PrintLiteralIndented("FROM", node->module_specifier()->string(), true);
 }
 
 
index a38f30fa419e5166cf94b649beb36c7db9b5a69b..8b957ffc198b039c8465e58cf58c556192acb06a 100644 (file)
@@ -790,7 +790,8 @@ RUNTIME_FUNCTION(Runtime_DeclareModules) {
         case VAR:
         case LET:
         case CONST:
-        case CONST_LEGACY: {
+        case CONST_LEGACY:
+        case IMPORT: {
           PropertyAttributes attr =
               IsImmutableVariableMode(mode) ? FROZEN : SEALED;
           Handle<AccessorInfo> info =
index 794accc48399d7095bea85aac88e0bb5954594cc..eddf4c3501e577c9dac14100c46477b853ae6379 100644 (file)
@@ -799,7 +799,6 @@ void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
 
 
 void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
-  RECURSE(Visit(declaration->module()));
 }
 
 
index 2351e529a24c8c1bd19c6cc47351df3e3f6ab06c..dd67052663e2699667bfa92f5aadc73fc2d2487b 100644 (file)
@@ -20,6 +20,7 @@ const char* Variable::Mode2String(VariableMode mode) {
     case CONST_LEGACY: return "CONST_LEGACY";
     case LET: return "LET";
     case CONST: return "CONST";
+    case IMPORT: return "IMPORT";
     case DYNAMIC: return "DYNAMIC";
     case DYNAMIC_GLOBAL: return "DYNAMIC_GLOBAL";
     case DYNAMIC_LOCAL: return "DYNAMIC_LOCAL";
index 8b2813cf8e0cdc02abda8803f1604b4676327ed2..02f8869c419fc4c70504c2ac87fa1cf8fe3e7ee3 100644 (file)
@@ -5218,11 +5218,11 @@ TEST(ModuleParsingInternals) {
   isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
                                         128 * 1024);
 
-  static const char kSource[] = "let x = 5; export { x as y };";
+  static const char kSource[] =
+      "let x = 5; export { x as y }; import { q as z } from 'm.js';";
   i::Handle<i::String> source = factory->NewStringFromAsciiChecked(kSource);
   i::Handle<i::Script> script = factory->NewScript(source);
   i::CompilationInfoWithZone info(script);
-  i::AstValueFactory avf(info.zone(), isolate->heap()->HashSeed());
   i::Parser parser(&info, isolate->stack_guard()->real_climit(),
                    isolate->heap()->HashSeed(), isolate->unicode_cache());
   parser.set_allow_harmony_modules(true);
@@ -5233,15 +5233,21 @@ TEST(ModuleParsingInternals) {
   CHECK_EQ(i::MODULE_SCOPE, func->scope()->scope_type());
   i::ModuleDescriptor* descriptor = func->scope()->module();
   CHECK_NOT_NULL(descriptor);
-  const i::AstRawString* name_x = avf.GetOneByteString("x");
-  const i::AstRawString* name_y = avf.GetOneByteString("y");
   int num_exports = 0;
   for (auto it = descriptor->iterator(); !it.done(); it.Advance()) {
     ++num_exports;
-    CHECK(*name_x == *it.local_name());
-    CHECK(*name_y == *it.export_name());
+    CHECK(it.local_name()->IsOneByteEqualTo("x"));
+    CHECK(it.export_name()->IsOneByteEqualTo("y"));
   }
   CHECK_EQ(1, num_exports);
+  i::ZoneList<i::Declaration*>* declarations = func->scope()->declarations();
+  CHECK_EQ(2, declarations->length());
+  CHECK(declarations->at(0)->proxy()->raw_name()->IsOneByteEqualTo("x"));
+  i::ImportDeclaration* import_decl =
+      declarations->at(1)->AsImportDeclaration();
+  CHECK(import_decl->import_name()->IsOneByteEqualTo("q"));
+  CHECK(import_decl->proxy()->raw_name()->IsOneByteEqualTo("z"));
+  CHECK(import_decl->module_specifier()->IsOneByteEqualTo("m.js"));
 }
 
 
diff --git a/test/message/import-as-redeclaration.js b/test/message/import-as-redeclaration.js
new file mode 100644 (file)
index 0000000..43bf278
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// MODULE
+
+let foo = 42;
+import { bar as foo } from "mod";
diff --git a/test/message/import-as-redeclaration.out b/test/message/import-as-redeclaration.out
new file mode 100644 (file)
index 0000000..51c4c03
--- /dev/null
@@ -0,0 +1,7 @@
+# Copyright 2015 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared
+import { bar as foo } from "mod";
+                ^^^
+SyntaxError: Identifier 'foo' has already been declared
diff --git a/test/message/import-redeclaration.js b/test/message/import-redeclaration.js
new file mode 100644 (file)
index 0000000..27b0cdc
--- /dev/null
@@ -0,0 +1,8 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// MODULE
+
+let foo = 42;
+import { foo } from "mod";
diff --git a/test/message/import-redeclaration.out b/test/message/import-redeclaration.out
new file mode 100644 (file)
index 0000000..6419488
--- /dev/null
@@ -0,0 +1,7 @@
+# Copyright 2015 the V8 project authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+*%(basename)s:8: SyntaxError: Identifier 'foo' has already been declared
+import { foo } from "mod";
+         ^^^
+SyntaxError: Identifier 'foo' has already been declared