changeset 813:1abffc396594

Revised the ModuleManager class. Fixed Parser.parseModuleDeclaration().
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Wed, 12 Mar 2008 00:49:17 +0100
parents 3b567bce56f3
children 49e32b5bc161
files src/dil/Messages.d src/dil/ModuleManager.d src/dil/parser/Parser.d
diffstat 3 files changed, 56 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/dil/Messages.d	Tue Mar 11 17:23:30 2008 +0100
+++ b/src/dil/Messages.d	Wed Mar 12 00:49:17 2008 +0100
@@ -155,6 +155,8 @@
   auto MissingCatchOrFinally = "try statement is missing a catch or finally body.";
   // Semantic analysis:
   auto CouldntLoadModule = "couldn't load module '{}'";
+  auto ConflictingModuleFiles = "module is in conflict with '{}'";
+  auto ModuleNotInPackage = "expected module to be in package '{}'";
   auto UndefinedIdentifier = "undefined identifier '{}'";
   auto DeclConflictsWithDecl = "declaration '{}' conflicts with declaration @{}";
   auto VariableConflictsWithDecl = "variable '{}' conflicts with declaration @{}";
--- a/src/dil/ModuleManager.d	Tue Mar 11 17:23:30 2008 +0100
+++ b/src/dil/ModuleManager.d	Wed Mar 12 00:49:17 2008 +0100
@@ -5,16 +5,24 @@
 module dil.ModuleManager;
 
 import dil.semantic.Module;
+import dil.Location;
 import dil.Information;
+import dil.Messages;
 import common;
 
 import tango.io.FilePath;
+import tango.io.FileSystem;
+import tango.io.FileConst;
+
+alias FileConst.PathSeparatorChar dirSep;
 
 /// Manages loaded modules in a table.
 class ModuleManager
 {
   /// Maps FQN paths to modules. E.g.: dil/ast/Node
-  Module[string] modulesTable;
+  Module[string] moduleFQNPathTable;
+  /// Maps absolute file paths to modules. E.g.: /home/user/dil/src/main.d
+  Module[string] absFilePathTable;
   Module[] loadedModules; /// Loaded modules in sequential order.
   string[] importPaths; /// Where to look for module files.
   InfoManager infoMan;
@@ -29,41 +37,63 @@
   /// Loads a module given a file path.
   Module loadModuleFile(string moduleFilePath)
   {
-    auto modul = new Module(moduleFilePath, infoMan);
-    modul.parse();
-    auto moduleFQNPath = modul.getFQNPath();
-    // Return the module if it's in the table already.
-    // This can happen if the module file path has been defined
-    // more than once on the command line.
-    if (auto existingModule = moduleFQNPath in modulesTable)
-    {
-      // TODO: avoid parsing the module in the first place, by
-      //       using another table mapping absolute file paths
-      //       to modules.
-      delete modul;
+    auto absFilePath = FileSystem.toAbsolute(moduleFilePath);
+    if (auto existingModule = absFilePath in absFilePathTable)
+      return *existingModule;
+
+    // Create a new module.
+    auto newModule = new Module(moduleFilePath, infoMan);
+    newModule.parse();
+
+    auto moduleFQNPath = newModule.getFQNPath();
+    if (auto existingModule = moduleFQNPath in moduleFQNPathTable)
+    { // Error: two module files have the same f.q. module name.
+      auto location = newModule.moduleDecl.begin.getErrorLocation();
+      auto msg = Format(MSG.ConflictingModuleFiles, newModule.filePath());
+      infoMan ~= new SemanticError(location, msg);
       return *existingModule;
     }
     // Insert new module.
-    modulesTable[moduleFQNPath] = modul;
-    loadedModules ~= modul;
-    return modul;
+    moduleFQNPathTable[moduleFQNPath] = newModule;
+    absFilePathTable[absFilePath] = newModule;
+    loadedModules ~= newModule;
+    return newModule;
   }
 
   /// Loads a module given an FQN path.
   Module loadModule(string moduleFQNPath)
   {
     // Look up in table if the module is already loaded.
-    Module* pmodul = moduleFQNPath in modulesTable;
+    Module* pmodul = moduleFQNPath in moduleFQNPathTable;
     if (pmodul)
       return *pmodul;
     // Locate the module in the file system.
-    auto moduleFilePath = findModuleFilePath(moduleFQNPath,
-                                             importPaths);
+    auto moduleFilePath = findModuleFilePath(moduleFQNPath, importPaths);
     if (moduleFilePath.length)
-      return loadModuleFile(moduleFilePath);
+    { // Load the found module file.
+      auto modul = loadModuleFile(moduleFilePath);
+      if (modul.getFQNPath() != moduleFQNPath)
+      { // Error: the requested module is not in the correct package.
+        auto location = modul.moduleDecl.begin.getErrorLocation();
+        auto msg = Format(MSG.ModuleNotInPackage, getPackage(moduleFQNPath));
+        infoMan ~= new SemanticError(location, msg);
+      }
+      return modul;
+    }
     return null;
   }
 
+  /// Returns e.g. 'dil.ast' for 'dil/ast/Node'.
+  string getPackage(string moduleFQNPath)
+  {
+    string pckg = moduleFQNPath.dup;
+    uint lastDirSep;
+    foreach (i, c; pckg)
+      if (c == dirSep)
+        (pckg[i] = '.'), (lastDirSep = i);
+    return pckg[0..lastDirSep];
+  }
+
   /// Searches for a module in the file system looking in importPaths.
   /// Returns: the file path to the module, or null if it wasn't found.
   static string findModuleFilePath(string moduleFQNPath, string[] importPaths)
@@ -71,12 +101,12 @@
     auto filePath = new FilePath();
     foreach (importPath; importPaths)
     {
-      filePath.set(importPath);
-      filePath.append(moduleFQNPath);
+      filePath.set(importPath); // E.g.: src/
+      filePath.append(moduleFQNPath); // E.g.: dil/ast/Node
       foreach (moduleSuffix; [".d", ".di"/*interface file*/])
       {
         filePath.suffix(moduleSuffix);
-        if (filePath.exists())
+        if (filePath.exists()) // E.g.: src/dil/ast/Node.d
           return filePath.toString();
       }
     }
--- a/src/dil/parser/Parser.d	Tue Mar 11 17:23:30 2008 +0100
+++ b/src/dil/parser/Parser.d	Wed Mar 12 00:49:17 2008 +0100
@@ -182,8 +182,8 @@
 
   Declaration parseModuleDeclaration()
   {
+    auto begin = token;
     skip(T.Module);
-    auto begin = token;
     ModuleFQN moduleFQN;
     do
       moduleFQN ~= requireIdentifier(MSG.ExpectedModuleIdentifier);