1 //Counts D features, doesn't really work yet :<( 2 module commands.featurecount; 3 4 import std; 5 import util.debug_; 6 import util.statman; 7 8 //The Kitchen sink 9 import dmd.astbase; 10 import dmd.errors; 11 import dmd.parse; 12 import dmd.transitivevisitor; 13 import dmd.dmodule; 14 import dmd.func; 15 import dmd.globals; 16 import dmd.id; 17 import dmd.identifier; 18 import dmd.visitor; 19 import dmd.frontend; 20 import dmd.dmangle; 21 import dmd.dsymbol; 22 import dmd.declaration; 23 import dmd.dtemplate; 24 ///Stolen from J.C.'s thing in github/dmd, gets the default dmd import paths on a system 25 string[] defaultImportPaths(string dlangDir) 26 { 27 import std.path : buildNormalizedPath, buildPath, dirName; 28 import std.process : environment; 29 30 const druntimeDir = dlangDir.buildPath("druntime", "import"); 31 const phobosDir = dlangDir.buildPath("phobos"); 32 33 return [environment.get("DRUNTIME_PATH", druntimeDir), 34 environment.get("PHOBOS_PATH", phobosDir)]; 35 } 36 37 ///Sorry god, utility function because dmd works in terms of c strings due to extern(C++) limitations 38 string cToD(inout char* x) 39 { 40 import core.stdc..string : strlen; 41 42 return cast(immutable char[]) x[0 .. x.strlen]; 43 } 44 ///Walks the semantic time AST, parse time is apparently not enough (e.g. needs sema to have everything) 45 extern (C++) //This is annoying but required unfortunately 46 class FeatureCountVisitor : SemanticTimePermissiveVisitor 47 { 48 alias visit = SemanticTimePermissiveVisitor.visit; 49 StatManager stats; 50 this() 51 { 52 stats = StatManager("FeatureCountVisitor"); 53 } 54 55 override void visit(Module mod) 56 { 57 foreach (x; *mod.members) 58 { 59 x.accept(this); 60 } 61 62 } 63 64 override void visit(Dsymbol sym) 65 { 66 67 debug writeln("stub dsymbol"); 68 } 69 70 override void visit(TemplateDeclaration decl) 71 { 72 73 if(auto c = decl.constraint) 74 { 75 import core.stdc.stdio; 76 77 } 78 } 79 override void visit(FuncDeclaration func) 80 { 81 import std.conv : to; 82 83 auto tmp = stats.category("functions").category(func.mangleExact.cToD); 84 with (tmp) 85 { 86 setAtom("fullSignature", func.toFullSignature.cToD); 87 setAtom("ProtectionClass", func.prot.to!string); 88 with (category("loc")) 89 { 90 setAtom("filename", func.loc.filename.cToD); 91 setAtom("line", func.loc.linnum); 92 } 93 } 94 95 } 96 } 97 98 auto command(string[] args) 99 { 100 import std.getopt : getopt, config; 101 import std.file : readText; 102 initDMD; 103 scope (exit) 104 deinitializeDMD; 105 106 string dimport; 107 string fileName; 108 string content; 109 110 111 auto parseResult = getopt(args, config.required, "I|import", &dimport, "f|file", &fileName); 112 113 if(fileName != "") { 114 content = readText(fileName); 115 } else { 116 //stdin 117 } 118 119 defaultImportPaths(dimport).each!writeln; 120 defaultImportPaths(dimport).each!addImport; 121 //Just dump any issues to stderr 122 scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); 123 scope mod = parseModule(fileName, content, diagnosticReporter); 124 125 scope tmp = new FeatureCountVisitor(); 126 127 //We wamt the whole shebang 128 mod.module_.fullSemantic; 129 130 mod.module_.accept(tmp); 131 132 return tmp.stats.gcDup; 133 }