changeset 370:ae4afb66768f

- Renamed findModule() to findModulePath(). - Added struct Edge. - Fix: don't append fileDir to importPaths when it's empty. - Added function findCyclicEdges(). - Added method getFQN() to class ModuleDeclaration. - Added member moduleFQN to class Module. - Renamed Module.fileName to filePath. - Added method setFQN() to class Module. - Fix in Lexer.scanspecialTokenSequence(): corrected MID.
author aziz
date Mon, 03 Sep 2007 16:29:02 +0000
parents 27767e203d64
children 01887f05d4b0
files trunk/src/cmd/ImportGraph.d trunk/src/dil/Declarations.d trunk/src/dil/Lexer.d trunk/src/dil/Module.d
diffstat 4 files changed, 138 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/cmd/ImportGraph.d	Sat Sep 01 19:58:01 2007 +0000
+++ b/trunk/src/cmd/ImportGraph.d	Mon Sep 03 16:29:02 2007 +0000
@@ -13,8 +13,9 @@
 import std.stdio : writefln;
 import std.path : getDirName, dirSep = sep;
 import std.file : exists;
+import std.string : replace;
 
-string findModule(string moduleFQN, string[] importPaths)
+string findModulePath(string moduleFQN, string[] importPaths)
 {
   string modulePath;
   foreach (path; importPaths)
@@ -26,36 +27,66 @@
   return null;
 }
 
+struct Edge
+{
+  Module outgoing;
+  Module incoming;
+  static Edge opCall(Module o, Module i)
+  {
+    Edge e;
+    e.outgoing = o;
+    e.incoming = i;
+    return e;
+  }
+}
+
 void execute(string fileName, string[] importPaths)
 {
   // Add directory of file and global directories to import paths.
-  importPaths ~= getDirName(fileName) ~ GlobalSettings.importPaths;
+  auto fileDir = getDirName(fileName);
+  if (fileDir.length)
+    importPaths ~= fileDir;
+  importPaths ~= GlobalSettings.importPaths;
 
   Module[string] loadedModules;
+  Module[] loadedModulesList; // Ordered list of loaded modules.
+  Edge edges[];
 
-  Module loadModule(string moduleFQN)
+  Module loadModule(string moduleFQNPath)
   {
-    auto mod_ = moduleFQN in loadedModules;
+    auto mod_ = moduleFQNPath in loadedModules;
     if (mod_ !is null)
       return *mod_;
 // writefln(moduleFQN);
-    auto modulePath = findModule(moduleFQN, importPaths);
+    auto modulePath = findModulePath(moduleFQNPath, importPaths);
+    Module mod;
     if (modulePath is null)
-      writefln("Warning: Module %s.d couldn't be found.", moduleFQN);
+    {
+// writefln("Warning: Module %s.d couldn't be found.", moduleFQNPath);
+      mod = new Module(null, true);
+      mod.setFQN(replace(moduleFQNPath, dirSep, "."));
+      loadedModules[moduleFQNPath] = mod;
+      loadedModulesList ~= mod;
+    }
     else
     {
-      auto mod = new Module(modulePath, true);
+      mod = new Module(modulePath, true);
       mod.parse();
 
-      loadedModules[moduleFQN] = mod;
+      loadedModules[moduleFQNPath] = mod;
+      loadedModulesList ~= mod;
 
       auto moduleFQNs = mod.getImports();
 
       foreach (moduleFQN_; moduleFQNs)
-        mod.modules ~= loadModule(moduleFQN_);
+      {
+        auto loaded_mod = loadModule(moduleFQN_);
+        edges ~= Edge(mod, loaded_mod);
+        mod.modules ~= loaded_mod;
+      }
       return mod;
     }
-    return null;
+    return mod;
   }
 
   auto mod = new Module(fileName, true);
@@ -63,6 +94,54 @@
 
   auto moduleFQNs = mod.getImports();
 
+  loadedModules[mod.getFQNPath()] = mod;
+  loadedModulesList ~= mod;
+
   foreach (moduleFQN_; moduleFQNs)
-    mod.modules ~= loadModule(moduleFQN_);
+  {
+    auto loaded_mod = loadModule(moduleFQN_);
+    edges ~= Edge(mod, loaded_mod);
+    mod.modules ~= loaded_mod;
+  }
+
+  writefln("digraph module_dependencies\n{");
+  foreach (edge; edges)
+  {
+    writefln(`  "%s" -> "%s"`, edge.outgoing.getFQN(), edge.incoming.getFQN());
+  }
+  writefln("}");
 }
+
+Edge[] findCyclicEdges(Module[] modules, Edge[] edges)
+{
+  foreach (module_; modules)
+  {
+    uint outgoing, incoming;
+    foreach (edge; edges)
+    {
+      if (edge.outgoing == module_)
+        outgoing++;
+      if (edge.incoming == module_)
+        incoming++;
+    }
+
+    if (outgoing == 0)
+    {
+      if (incoming != 0)
+      {
+        // sink
+      }
+      else
+        assert(0); // orphaned vertex (module) in graph
+    }
+    else if (incoming == 0)
+    {
+      // source
+    }
+    else
+    {
+      // source && sink
+    }
+  }
+  return null;
+}
--- a/trunk/src/dil/Declarations.d	Sat Sep 01 19:58:01 2007 +0000
+++ b/trunk/src/dil/Declarations.d	Mon Sep 03 16:29:02 2007 +0000
@@ -74,6 +74,15 @@
     this.packages = moduleFQN[0..$-1];
   }
 
+  string getFQN()
+  {
+    auto pname = getPackageName('.');
+    if (pname.length)
+      return pname ~ "." ~ getName();
+    else
+      return getName();
+  }
+
   string getName()
   {
     if (moduleName)
--- a/trunk/src/dil/Lexer.d	Sat Sep 01 19:58:01 2007 +0000
+++ b/trunk/src/dil/Lexer.d	Mon Sep 03 16:29:02 2007 +0000
@@ -1441,7 +1441,7 @@
     ++p;
     if (p[0] != 'l' || p[1] != 'i' || p[2] != 'n' || p[3] != 'e')
     {
-      mid = MID.ExpectedNumberAfterSTLine;
+      mid = MID.ExpectedIdentifierSTLine;
       goto Lerr;
     }
     p += 3;
--- a/trunk/src/dil/Module.d	Sat Sep 01 19:58:01 2007 +0000
+++ b/trunk/src/dil/Module.d	Mon Sep 03 16:29:02 2007 +0000
@@ -13,7 +13,8 @@
 class Module
 {
   bool isLightweight; /// If true an ImportParser is used instead of a full Parser.
-  string fileName; /// Path to the source file.
+  string filePath; /// Path to the source file.
+  string moduleFQN; /// Fully qualified name of the module.
   string packageName;
   string moduleName;
   Declarations root; /// The root of the AST.
@@ -23,36 +24,40 @@
 
   Module[] modules;
 
-  this(string fileName, bool isLight = false)
+  this(string filePath, bool isLight = false)
   {
-    this.fileName = fileName;
+    this.filePath = filePath;
     this.isLightweight = isLightweight;
   }
 
   void parse()
   {
-    auto sourceText = loadFile(fileName);
+    auto sourceText = loadFile(filePath);
     if (this.isLightweight)
-      this.parser = new ImportParser(sourceText, fileName);
+      this.parser = new ImportParser(sourceText, filePath);
     else
-      this.parser = new Parser(sourceText, fileName);
+      this.parser = new Parser(sourceText, filePath);
 
     this.root = parser.start();
 
     if (root.children.length)
     {
-      // moduleDecl will be null if first node can't be casted to ModuleDeclaration.
+      // moduleDecl will be null if first node can't be cast to ModuleDeclaration.
       this.moduleDecl = Cast!(ModuleDeclaration)(root.children[0]);
       if (moduleDecl)
       {
-        this.moduleName = moduleDecl.getName();
-        this.packageName = moduleDecl.getPackageName(std.path.sep[0]);
+        this.setFQN(moduleDecl.getFQN());
       }
       else
       {
-        auto str = getBaseName(getName(fileName));
+        // Take base name of file path as module name.
+        auto str = getBaseName(getName(filePath));
         if (Lexer.isNonReservedIdentifier(str))
-          this.moduleName = str;
+        {
+          this.moduleFQN = moduleName = str;
+        }
+        // else
+        // TODO: error: file name has invalid identifier characters.
       }
 
       this.imports = parser.imports;
@@ -69,6 +74,27 @@
 
   string getFQN()
   {
-    return packageName ~ std.path.sep ~ moduleName;
+    return moduleFQN;
+  }
+
+  void setFQN(string moduleFQN)
+  {
+    uint i = moduleFQN.length;
+    if (i != 0) // Don't decrement if string has zero length.
+      i--;
+    // Find last dot.
+    for (; i != 0 && moduleFQN[i] != '.'; i--)
+    {}
+    this.moduleFQN = moduleFQN;
+    this.packageName = moduleFQN[0..i];
+    this.moduleName = moduleFQN[(i == 0 ? 0 : i+1) .. $];
+  }
+
+  string getFQNPath()
+  {
+    if (packageName.length)
+      return packageName ~ std.path.sep ~ moduleName;
+    else
+      return moduleName;
   }
 }