1 /// Author: Aziz Köksal 2 /// License: GPL3 3 /// $(Maturity low) 4 module cmd.Compile; 5 6 import cmd.Command; 7 import dil.ast.Declarations; 8 import dil.lexer.Token; 9 import dil.semantic.Module, 10 dil.semantic.Package, 11 dil.semantic.Pass1, 12 dil.semantic.Pass2, 13 dil.semantic.Passes, 14 dil.semantic.Symbol, 15 dil.semantic.Symbols; 16 import dil.doc.Doc; 17 import dil.i18n.Messages; 18 import dil.Compilation, 19 dil.Diagnostics, 20 dil.ModuleManager, 21 dil.String; 22 import util.Path; 23 import common; 24 25 /// The compile command. 26 class CompileCommand : Command 27 { 28 cstring[] filePaths; /// Explicitly specified modules (on the command line.) 29 bool printSymbolTree; /// Whether to print the symbol tree. 30 bool printModuleTree; /// Whether to print the module tree. 31 bool m32; /// Emit 32bit code. 32 bool m64; /// Emit 64bit code. 33 34 cstring binOutput; /// Output destination. 35 36 ModuleManager moduleMan; 37 SemanticPass1[] passes1; 38 39 CompilationContext context; 40 Diagnostics diag; 41 42 /// Executes the compile command. 43 override void run() 44 { 45 // TODO: import object.d 46 moduleMan = new ModuleManager(context); 47 foreach (filePath; filePaths) 48 moduleMan.loadModuleFile(filePath); 49 50 foreach (modul; moduleMan.loadedModules) 51 { 52 runPass1(modul); 53 if (printSymbolTree) 54 printSymbolTable(modul, ""); 55 } 56 57 // foreach (modul; moduleMan.loadedModules) 58 // { 59 // auto pass2 = new SemanticPass2(modul); 60 // pass2.run(); 61 // } 62 63 if (printModuleTree) 64 { 65 moduleMan.sortPackageTree(); 66 printMTree2(moduleMan.rootPackage, ""); 67 } 68 // foreach (mod; moduleMan.orderedModules) 69 // Stdout(mod.moduleFQN, mod.imports.length).newline; 70 } 71 72 /// Prints the package/module tree including the root. 73 void printMTree(Package pckg, cstring indent) 74 { 75 Stdout(indent)(pckg.pckgName)("/").newline; // PackageName/ 76 foreach (p; pckg.packages) 77 printMTree(p, indent ~ " "); // Print the sub-packages. 78 foreach (m; pckg.modules) // Print the modules. 79 Stdout(indent ~ " ")(m.moduleName)(".")(m.fileExtension()).newline; 80 } 81 82 /// Prints the package/module tree excluding the root. 83 void printMTree2(Package pckg, cstring indent) 84 { 85 foreach (p; pckg.packages) 86 { 87 Stdout(indent)(p.pckgName)("/").newline; // PackageName/ 88 printMTree2(p, indent ~ " "); // Print the sub-packages. 89 } 90 foreach (m; pckg.modules) // Print the modules. 91 Stdout(indent)(m.moduleName)(".")(m.fileExtension()).newline; 92 } 93 94 /// Runs the first pass on modul. 95 void runPass1(Module modul) 96 { 97 if (modul.hasErrors || modul.semanticPass != 0) 98 return; 99 auto pass1 = new SemanticPass1(modul, context); 100 pass1.importModule = &importModule; 101 pass1.run(); 102 passes1 ~= pass1; 103 } 104 105 /// Imports a module and runs the first pass on it. 106 Module importModule(cstring moduleFQNPath) 107 { 108 auto modul = moduleMan.loadModule(moduleFQNPath); 109 modul && runPass1(modul); 110 return modul; 111 } 112 113 /// Prints all symbols recursively (for debugging.) 114 static void printSymbolTable(ScopeSymbol scopeSym, cstring indent) 115 { 116 foreach (member; scopeSym.members) 117 { 118 auto tokens = DDocUtils.getDocTokens(member.loc.n); 119 char[] docText; 120 foreach (token; tokens) 121 docText ~= token.text; 122 Stdout(indent).formatln("Id:{}, Symbol:{}, DocText:{}", 123 member.name.str, typeid(member).name, 124 docText); 125 if (auto s = cast(ScopeSymbol)member) 126 printSymbolTable(s, indent ~ "→ "); 127 } 128 } 129 } 130 131 132 /// The compile command. 133 /// NOTE: The plan is to replace CompileCommand. 134 class CompileCommand2 : Command 135 { 136 /// For finding and loading modules. 137 ModuleManager mm; 138 /// Context information. 139 CompilationContext cc; 140 /// Explicitly specified modules (on the command line.) 141 cstring[] filePaths; 142 /// Whether to print the symbol tree. 143 bool printSymbolTree; 144 /// Whether to print the module tree. 145 bool printModuleTree; 146 147 // Format strings for logging. 148 auto LogPass1 = "pass1: {}"; 149 auto LogPass2 = "pass2: {}"; 150 auto LogDeps = "deps: {}"; 151 auto LogLoad = "load: {}"; 152 auto LogImport = "import: {} ({})"; 153 auto LogDiags = "diagnostics:"; 154 155 /// Runs semantic pass 1 on a module. Also imports its dependencies. 156 void runPass1(Module modul) 157 { 158 if (modul.hasErrors || modul.semanticPass != 0) 159 return; 160 161 lzy(log(LogPass1, modul.getFQN())); 162 163 auto pass1 = new FirstSemanticPass(modul); 164 pass1.run(); 165 166 lzy({if (pass1.imports.length) log(LogDeps, modul.getFQN());}()); 167 168 // Load the module's imported modules. 169 foreach (d; pass1.imports) 170 importModuleByDecl(d, modul); 171 // TODO: modul.modules ~= importedModule; 172 } 173 174 /// Runs semantic pass 2 on a module. 175 void runPass2(Module modul) 176 { 177 if (modul.hasErrors || modul.semanticPass != 1) 178 return; 179 180 lzy(log(LogPass2, modul.getFQN())); 181 182 auto pass2 = new SecondSemanticPass(modul); 183 pass2.run(); 184 } 185 186 /// Loads a module by its file path and runs pass 1 on it. 187 /// Params: 188 /// filePath = E.g.: src/main.d 189 void importModuleByFile(cstring filePath) 190 { 191 if (mm.moduleByPath(filePath)) 192 return; // The module has already been loaded. 193 194 lzy(log(LogLoad, filePath)); 195 196 if (auto modul = mm.loadModuleFile(filePath)) 197 runPass1(modul); // Load and run pass 1 on it. 198 else 199 mm.errorModuleNotFound(filePath); 200 } 201 202 /// Loads a module by its FQN path and runs pass 1 on it. 203 /// Params: 204 /// modFQNPath = E.g.: dil/cmd/Compile 205 /// fqnTok = Identifier token in the import statement. 206 /// modul = Where the import statement is located. 207 void importModuleByFQN(cstring modFQNPath, 208 Token* fqnTok = null, Module modul = null) 209 { 210 if (mm.moduleByFQN(modFQNPath)) 211 return; // The module has already been loaded. 212 if (auto modFilePath = mm.findModuleFile(modFQNPath)) 213 { 214 lzy(log(LogImport, modFQNPath.replace('/', '.'), modFilePath)); 215 runPass1(mm.loadModule(modFQNPath)); // Load and run pass 1 on it. 216 } 217 else 218 mm.errorModuleNotFound(modFQNPath ~ ".d", 219 fqnTok ? fqnTok.getErrorLocation(modul.filePath()) : null); 220 } 221 222 void importModuleByDecl(ImportDecl d, Module modul) 223 { 224 foreach (i, fqnPath; d.getModuleFQNs(dirSep)) 225 importModuleByFQN(fqnPath, d.moduleFQNs[i][0], modul); 226 } 227 228 /// Runs the command. 229 override void run() 230 { 231 mm = new ModuleManager(cc); 232 233 // Always implicitly import "object.d". 234 importModuleByFQN("object"); 235 auto objectModule = mm.moduleByFQN("object"); 236 if (!objectModule) 237 {} // error 238 239 // Load modules specified on the command line. 240 foreach (filePath; filePaths) 241 importModuleByFile(filePath); 242 243 // Run pass2 on all the loaded modules. 244 foreach (m; mm.orderedModules) 245 { 246 runPass2(m); 247 } 248 249 lzy({if (cc.diag.hasInfo()) log(LogDiags);}()); 250 //lzy(cc.diag.hasInfo() && log(LogDiags)); // DMD bug: void has no value 251 } 252 }