# HG changeset patch # User Jari-Matti M?kel? # Date 1192546439 -10800 # Node ID 13ecfb4278a4d0acd388cb5e3deb2abbed1e0346 # Parent 0934a82745396592b6fec293a6284ece1db7c08a Initial docgen test stuff. diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen-tests.d --- a/trunk/src/docgen-tests.d Tue Oct 16 17:49:53 2007 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/** - * Author: Jari-Matti Mäkelä - * License: GPL3 - */ -module trunk.src.tests; - -import docgen.graphutils.writers; -import tango.io.Stdout; -import tango.io.FileConduit; - -/** - * A temporary test program for the docgen package. - * I'll replace this with proper unittests in the future. - * - */ -void main() { - { - auto a = new Vertex("mod_a", "path.to.mod_a", 1); - auto b = new Vertex("mod_b", "path.to.mod_b", 2); - auto c = new Vertex("mod_c", "path.to.mod_c", 3); - - auto d = new Vertex("mod_d", "path.to.mod_d", 4); - auto e = new Vertex("mod_e", "path.to.mod_e", 5); - auto f = new Vertex("mod_f", "path.to.mod_f", 6); - auto g = new Vertex("mod_g", "path.to.mod_g", 7); - - Edge[] edges; - //edges ~= a.addChild(b); - //edges ~= b.addChild(c); - //edges ~= c.addChild(a); - edges ~= d.addChild(a); - //edges ~= e.addChild(a); - edges ~= b.addChild(d); - edges ~= b.addChild(e); - edges ~= g.addChild(a); - edges ~= b.addChild(f); - edges ~= g.addChild(f); - edges ~= a.addChild(g); - - - - GraphOptions test; - test.graphFormat = GraphFormat.Dot; - test.HighlightCyclicVertices = true; - //test.format = GraphOutputFormat.ModuleNames; - //test.format = GraphOutputFormat.ModulePaths; - test.depth = 5; - //test.depth++; - - auto gwf = new DefaultGraphWriterFactory(test); - auto writer = gwf.createGraphWriter([Stdout.stream, new FileConduit("test.dot", FileConduit.WriteCreate)]); - - writer([a,b,c,d,e,f,g], edges); - } -} \ No newline at end of file diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/archdoc.xmi --- a/trunk/src/docgen/archdoc.xmi Tue Oct 16 17:49:53 2007 +0300 +++ b/trunk/src/docgen/archdoc.xmi Tue Oct 16 17:53:59 2007 +0300 @@ -1,9 +1,9 @@ - + umbrello uml modeller http://uml.sf.net - 1.5.71 + 1.5.8 UnicodeUTF8 @@ -128,7 +128,7 @@ - + @@ -154,7 +154,7 @@ - + @@ -169,7 +169,7 @@ - + @@ -195,7 +195,7 @@ - + @@ -216,7 +216,7 @@ - + @@ -241,8 +241,8 @@ - - + + @@ -267,32 +267,32 @@ - - + + - - + + - - + + - - + + - - + + @@ -316,7 +316,7 @@ - + @@ -337,7 +337,7 @@ - + @@ -352,7 +352,7 @@ - + @@ -409,7 +409,7 @@ - + @@ -418,12 +418,12 @@ - + - + @@ -449,19 +449,19 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -527,7 +527,7 @@ - + @@ -576,8 +576,8 @@ - - + + @@ -597,30 +597,30 @@ - - + + - - - - - - + + + + + + - + - - - - - - - + + + + + + + @@ -641,21 +641,21 @@ - + - + - + @@ -682,7 +682,7 @@ - + @@ -747,21 +747,21 @@ - + - + - + @@ -775,16 +775,16 @@ - - + + - + - + @@ -820,8 +820,8 @@ - - + + @@ -872,7 +872,7 @@ - + @@ -883,10 +883,6 @@ - - - - @@ -896,6 +892,10 @@ + + + + @@ -905,16 +905,13 @@ - - + + + - - - - @@ -943,6 +940,9 @@ + + + @@ -972,14 +972,6 @@ - - - - - - - - @@ -988,6 +980,14 @@ + + + + + + + + diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/docgen.d --- a/trunk/src/docgen/docgen.d Tue Oct 16 17:49:53 2007 +0300 +++ b/trunk/src/docgen/docgen.d Tue Oct 16 17:53:59 2007 +0300 @@ -2,7 +2,7 @@ * Author: Jari-Matti Mäkelä * License: GPL3 */ -module trunk.src.docgen.docgen; +module docgen.docgen; import docgen.modulegraph.writer; diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/misc/parser.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/misc/parser.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,259 @@ +/** + * Author: Aziz Köksal & Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.misc.parser; + +import docgen.graphutils.writers; + +import dil.Parser; +import dil.Module; +import dil.Settings; +import tango.text.Regex : RegExp = Regex; +import tango.io.FilePath; +import tango.io.FileConst; +import tango.text.Util; +import common; +debug import tango.io.Stdout; + +class Parser { + private static string findModulePath(string moduleFQN, string[] importPaths) { + string modulePath; + + foreach (path; importPaths) { + modulePath = path ~ (path[$-1] == dirSep ? "" : [dirSep]) ~ moduleFQN ~ ".d"; + + // TODO: also check for *.di? + + if ((new FilePath(modulePath)).exists()) { + debug Stdout(" * File for ")(moduleFQN)(" found: ")(modulePath).newline; + return modulePath; + } + } + + debug Stdout(" * ")(moduleFQN)(" does not exist in imports")().newline()(); + return null; + } + + /** + * Imports the transitive closure of imports starting from "filePath", + * limited by recursionDepth. + * + * The search can be filtered by providing a list of regexps that match the + * FQNs of modules to be ignored. + * + * Params: + * filePath = Path of the file to parse + * importPaths = Directories to look for imports + * strRegexps = Filter regexps + * IncludeUnlocatableModules = Call the delegate also for unlocatable files + * recursionDepth = How many levels of imports to follow (-1 = no limit) + * mdg = Delegate that gets called for every module found + * idg = Delegate that gets called for every import found + * modules = List of parsed modules + */ + public static void loadModules(string filePath, string[] importPaths, string[] strRegexps, + bool IncludeUnlocatableModules, int recursionDepth, + void delegate (string fqn, string path, Module) mdg, + void delegate (Module imported, Module importer) idg, + out Module[] modules) { + + loadModules([filePath], importPaths, strRegexps, IncludeUnlocatableModules, + recursionDepth, mdg, idg, modules); + } + + /** + * Imports the transitive closure of imports starting from "filePath", + * limited by recursionDepth. + * + * The search can be filtered by providing a list of regexps that match the + * FQNs of modules to be ignored. + * + * Params: + * filePaths = Paths of the files to parse + * importPaths = Directories to look for imports + * strRegexps = Filter regexps + * IncludeUnlocatableModules = Call the delegate also for unlocatable files + * recursionDepth = How many levels of imports to follow (-1 = no limit) + * mdg = Delegate that gets called for every module found + * idg = Delegate that gets called for every import found + * modules = List of parsed modules + */ + public static void loadModules(string[] filePaths, string[] importPaths, string[] strRegexps, + bool IncludeUnlocatableModules, int recursionDepth, + void delegate (string fqn, string path, Module) mdg, + void delegate (Module imported, Module importer) idg, + out Module[] modules) { + // Initialize regular expressions. + RegExp[] regexps; + foreach (strRegexp; strRegexps) + regexps ~= new RegExp(strRegexp); + + // Add directory of file and global directories to import paths. + foreach(filePath; filePaths) { + auto fileDir = (new FilePath(filePath)).folder(); + if (fileDir.length) + importPaths ~= fileDir; + } + + importPaths ~= GlobalSettings.importPaths; + + debug foreach(path; importPaths) { + Stdout("Import path: ")(path).newline; + } + + Module[string] loadedModules; + + Module loadModule(string moduleFQNPath, int depth) { + if (depth == 0) return null; + + debug Stdout("Loading ")(moduleFQNPath).newline; + + // Return already loaded module. + auto mod_ = moduleFQNPath in loadedModules; + if (mod_ !is null) { + debug Stdout(" Already loaded.")(moduleFQNPath).newline; + return *mod_; + } + + auto FQN = replace(moduleFQNPath.dup, dirSep, '.'); + + // Ignore module names matching regular expressions. + foreach (rx; regexps) + if (rx.test(FQN)) return null; + + auto modulePath = findModulePath(moduleFQNPath, importPaths); + //foreach(filePath; filePaths) + //if (moduleFQNPath == filePath) modulePath = filePath; + + debug Stdout(" FQN ")(FQN).newline; + debug Stdout(" Module path ")(modulePath).newline; + + Module mod = null; + + if (modulePath is null) { + if (IncludeUnlocatableModules) + mdg(FQN, moduleFQNPath, null); + } else { + mod = new Module(modulePath); + loadedModules[moduleFQNPath] = mod; + mod.parse(); + + mdg(FQN, moduleFQNPath, mod); + + auto moduleFQNs = mod.getImports(); + + foreach (moduleFQN_; moduleFQNs) { + auto loaded_mod = loadModule(moduleFQN_, depth == -1 ? depth : depth-1); + + if (loaded_mod !is null) + idg(loaded_mod, mod); + } + } + + return mod; + } // loadModule + + foreach(filePath; filePaths) + loadModule(filePath, recursionDepth); + + // Finished loading modules. + + // Ordered list of loaded modules. + modules = loadedModules.values; + } + + + /+ Old version - deprecated + + /** + * Imports the transitive closure of imports starting from "filePath". + * + * The search can be filtered by providing a list of regexps that match the + * FQNs of modules to be ignored. + * + * TODO: integrate better with the docgen stuff - there's no need to + * scan&parse several times + */ + public static void loadModules2(string filePath, string[] importPaths, + string[] strRegexps, + bool IncludeUnlocatableModules, + out Vertex[] vertices, out Edge[] edges, + out Module[] modules) { + // Init regular expressions. + RegExp[] regexps; + foreach (strRegexp; strRegexps) + regexps ~= new RegExp(strRegexp); + + // Add directory of file and global directories to import paths. + auto fileDir = (new FilePath(filePath)).folder(); + if (fileDir.length) + importPaths ~= fileDir; + importPaths ~= GlobalSettings.importPaths; + + Vertex[string] loadedModules; + Edge[] _edges; + Module[] _modules; + + int modCounter = 0; + + void addModule(Vertex mod) { + assert(!(mod.location in loadedModules)); + + mod.id = modCounter++; + loadedModules[mod.location] = mod; + } + + Vertex loadModule(string moduleFQNPath) { + // Return already loaded module. + auto mod_ = moduleFQNPath in loadedModules; + if (mod_ !is null) return *mod_; + + // Ignore module names matching regular expressions. + foreach (rx; regexps) + if (rx.test(replace(moduleFQNPath, dirSep, '.'))) + return null; + + auto modulePath = findModulePath(moduleFQNPath, importPaths); + if (moduleFQNPath == filePath) modulePath = filePath; + auto FQN = replace(moduleFQNPath, dirSep, '.'); + + Vertex mod; + + if (modulePath is null) { + if (IncludeUnlocatableModules) { + mod = new Vertex(FQN, moduleFQNPath); + addModule(mod); + } + } else { + mod = new Vertex(FQN, moduleFQNPath); + addModule(mod); + + auto m = new Module(modulePath); + _modules ~= m; + m.parse(); + + auto moduleFQNs = m.getImports(); + + foreach (moduleFQN_; moduleFQNs) { + auto loaded_mod = loadModule(moduleFQN_); + + if (loaded_mod !is null) + loaded_mod.addChild(mod); + } + } + + return mod; + } // loadModule + + loadModule(filePath); + + // Finished loading modules. + + // Ordered list of loaded modules. + vertices = loadedModules.values; + edges = _edges; + modules = _modules; + } + +/ +} \ No newline at end of file diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/modulegraph/writer.d --- a/trunk/src/docgen/modulegraph/writer.d Tue Oct 16 17:49:53 2007 +0300 +++ b/trunk/src/docgen/modulegraph/writer.d Tue Oct 16 17:53:59 2007 +0300 @@ -18,115 +18,11 @@ alias FileConst.PathSeparatorChar dirSep; class ModuleGraphGenerator { - private static string findModulePath(string moduleFQN, string[] importPaths) { - string modulePath; - - foreach (path; importPaths) { - modulePath = path ~ (path[$-1] == dirSep ? "" : [dirSep]) - ~ moduleFQN ~ ".d"; - - // TODO: also check for *.di? - if ((new FilePath(modulePath)).exists()) - return modulePath; - } - - return null; - } - - /** - * Imports the transitive closure of imports starting from "filePath". - * - * The search can be filtered by providing a list of regexps that match the - * FQNs of modules to be ignored. - * - * TODO: integrate better with the docgen stuff - there's no need to - * scan&parse several times - */ - public static void loadModules(string filePath, string[] importPaths, - string[] strRegexps, - bool IncludeUnlocatableModules, - out Vertex[] vertices, out Edge[] edges, - out Module[] modules) { - // Init regular expressions. - RegExp[] regexps; - foreach (strRegexp; strRegexps) - regexps ~= new RegExp(strRegexp); - - // Add directory of file and global directories to import paths. - auto fileDir = (new FilePath(filePath)).folder(); - if (fileDir.length) - importPaths ~= fileDir; - importPaths ~= GlobalSettings.importPaths; - - Vertex[string] loadedModules; - Edge[] _edges; - Module[] _modules; - - int modCounter = 0; - - void addModule(Vertex mod) { - assert(!(mod.location in loadedModules)); - - mod.id = modCounter++; - loadedModules[mod.location] = mod; - } - - Vertex loadModule(string moduleFQNPath) { - // Return already loaded module. - auto mod_ = moduleFQNPath in loadedModules; - if (mod_ !is null) return *mod_; - - // Ignore module names matching regular expressions. - foreach (rx; regexps) - if (rx.test(replace(moduleFQNPath, dirSep, '.'))) - return null; - - auto modulePath = findModulePath(moduleFQNPath, importPaths); - if (moduleFQNPath == filePath) modulePath = filePath; - auto FQN = replace(moduleFQNPath, dirSep, '.'); - - Vertex mod; - - if (modulePath is null) { - if (IncludeUnlocatableModules) { - mod = new Vertex(FQN, moduleFQNPath); - addModule(mod); - } - } else { - mod = new Vertex(FQN, moduleFQNPath); - addModule(mod); - - auto m = new Module(modulePath); - _modules ~= m; - m.parse(); - - auto moduleFQNs = m.getImports(); - - foreach (moduleFQN_; moduleFQNs) { - auto loaded_mod = loadModule(moduleFQN_); - - if (loaded_mod !is null) - loaded_mod.addChild(mod); - } - } - - return mod; - } // loadModule - - loadModule(filePath); - - // Finished loading modules. - - // Ordered list of loaded modules. - vertices = loadedModules.values; - edges = _edges; - modules = _modules; - } /** * TODO */ - static void generateGraph(GraphWriterOptions *options) { + static void generateGraph(GraphOptions *options) { auto gwf = new DefaultGraphWriterFactory(*options); auto writer = gwf.createGraphWriter([Stdout.stream]); diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/tests/graphs.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/tests/graphs.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,98 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.tests.graphs; + +import docgen.graphutils.writers; +import tango.io.Stdout; +import tango.io.FileConduit; + +void saveDefaultGraph(Vertex[] vertices, Edge[] edges, char[] fname) { + GraphOptions test; + test.graphFormat = GraphFormat.Dot; + test.HighlightCyclicVertices = true; + //test.format = GraphOutputFormat.ModuleNames; + //test.format = GraphOutputFormat.ModulePaths; + test.depth = 5; + + auto gwf = new DefaultGraphWriterFactory(test); + auto file = new FileConduit("docgen/teststuff/" ~ fname, FileConduit.WriteCreate); + auto file2 = new FileConduit("docgen/teststuff/" ~ fname ~ "-2", FileConduit.WriteCreate); + auto writer = gwf.createGraphWriter( [ file2, file] ); + + writer(vertices, edges); + + file.close(); + file2.close(); +} + +// no edges +//@unittest +void graph1() { + auto a = new Vertex("mod_a", "path.to.mod_a", 1); + auto b = new Vertex("mod_b", "path.to.mod_b", 2); + auto c = new Vertex("mod_c", "path.to.mod_c", 3); + + saveDefaultGraph( [a,b,c], null, "graph1.dot" ); +} + + +// simple tree structure +//@unittest +void graph2() { + auto a = new Vertex("mod_a", "path.to.mod_a", 1); + auto b = new Vertex("mod_b", "path.to.mod_b", 2); + auto c = new Vertex("mod_c", "path.to.mod_c", 3); + auto d = new Vertex("mod_d", "path.to.mod_d", 4); + + Edge[] edges; + edges ~= a.addChild(b); + edges ~= a.addChild(c); + edges ~= c.addChild(d); + + saveDefaultGraph( [a,b,c,d], edges, "graph2.dot" ); +} + +// circular imports +//@unittest +void graph3() { + auto a = new Vertex("mod_a", "path.to.mod_a", 1); + auto b = new Vertex("mod_b", "path.to.mod_b", 2); + auto c = new Vertex("mod_c", "path.to.mod_c", 3); + auto d = new Vertex("mod_d", "path.to.mod_d", 4); + + Edge[] edges; + edges ~= a.addChild(b); + edges ~= b.addChild(c); + edges ~= c.addChild(a); + + saveDefaultGraph( [a,b,c,d], edges, "graph3.dot" ); +} + +// more complex graph +//@unittest +void graph4() { + auto a = new Vertex("mod_a", "path.to.mod_a", 1); + auto b = new Vertex("mod_b", "path.to.mod_b", 2); + auto c = new Vertex("mod_c", "path.to.mod_c", 3); + auto d = new Vertex("mod_d", "path.to.mod_d", 4); + auto e = new Vertex("mod_e", "path.to.mod_e", 5); + auto f = new Vertex("mod_f", "path.to.mod_f", 6); + auto g = new Vertex("mod_g", "path.to.mod_g", 7); + + Edge[] edges; + edges ~= a.addChild(b); + edges ~= b.addChild(c); + edges ~= c.addChild(a); + edges ~= d.addChild(a); + edges ~= e.addChild(a); + edges ~= b.addChild(d); + edges ~= b.addChild(e); + edges ~= g.addChild(a); + edges ~= b.addChild(f); + edges ~= g.addChild(f); + edges ~= a.addChild(g); + + saveDefaultGraph( [a,b,c,d,e,f,g], edges, "graph4.dot" ); +} \ No newline at end of file diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/tests/parse.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/tests/parse.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,70 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.tests.parse; + +import docgen.misc.parser; +import tango.io.Stdout; +import tango.io.FileConduit; +import tango.io.Print: Print; +import tango.text.convert.Layout : Layout; +import dil.Module; + +void saveToFile(char[] fname, void delegate(Print!(char) file) foo) { + auto file = new FileConduit("docgen/teststuff/" ~ fname, FileConduit.WriteCreate); + auto output = new Print!(char)(new Layout!(char), file); + + foo(output); + + file.close(); +} + +// load some test files +//@unittest +void parse1() { + saveToFile("parse1.txt", (Print!(char) file){ + + Module[] modules; + + Parser.loadModules( + [ "c" ], ["docgen/teststuff/"[].dup], + null, true, -1, + (char[] fqn, char[] path, Module m) { + file.format("{0} = {1}\n", fqn, path); + }, + (Module imported, Module importer) { + file.format("{0} <- {1}\n", + imported ? imported.moduleFQN : "null"[], + importer ? importer.moduleFQN : "null"[] + ); + }, + modules + ); + }); +} + +// load the imports of dil +//@unittest +void parse2() { +saveToFile("parse2.txt", (Print!(char) file){ + +Module[] modules; + +Parser.loadModules( + [ "docgen-tests" ], [".", "/home/jm/d/tango/"], +// [ "c" ], ["docgen/teststuff/"[].dup], + null, true, -1, + (char[] fqn, char[] path, Module m) { + file.format("{0} = {1}\n", fqn, path); + }, + (Module imported, Module importer) { + file.format("{0} <- {1}\n", + imported ? imported.moduleFQN : "null"[], + importer ? importer.moduleFQN : "null"[] + ); + }, + modules + ); +}); +} \ No newline at end of file diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/teststuff/a.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/teststuff/a.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,4 @@ +module a; + +void foo() {} +void bar() {} diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/teststuff/b.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/teststuff/b.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,4 @@ +module b; + +import a; + diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/teststuff/c.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/teststuff/c.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,4 @@ +module c; + +import a; +import b; diff -r 0934a8274539 -r 13ecfb4278a4 trunk/src/docgen/testsuite.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/docgen/testsuite.d Tue Oct 16 17:53:59 2007 +0300 @@ -0,0 +1,25 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.testsuite; + +import docgen.tests.graphs; +import docgen.tests.parse; +import tango.io.Stdout; + +/** + * A temporary test program for the docgen package. + * I'll replace this with proper unittests in the future. + * + */ +void main() { + Stdout("Running.."); + graph1(); + graph2(); + graph3(); + graph4(); + parse1(); + parse2(); + Stdout("done.\n"); +}