Mercurial > projects > dil
comparison src/main.d @ 806:bcb74c9b895c
Moved out files in the trunk folder to the root.
author | Aziz K?ksal <aziz.koeksal@gmail.com> |
---|---|
date | Sun, 09 Mar 2008 00:12:19 +0100 |
parents | trunk/src/main.d@dcd30b0ba711 |
children | a2880c95eda3 |
comparison
equal
deleted
inserted
replaced
805:a3fab8b74a7d | 806:bcb74c9b895c |
---|---|
1 /++ | |
2 Author: Aziz Köksal | |
3 License: GPL3 | |
4 +/ | |
5 module main; | |
6 | |
7 import dil.parser.Parser; | |
8 import dil.lexer.Lexer, | |
9 dil.lexer.Token; | |
10 import dil.ast.Declarations, | |
11 dil.ast.Expressions, | |
12 dil.ast.Node, | |
13 dil.ast.Visitor; | |
14 import dil.semantic.Module; | |
15 import dil.semantic.Symbols; | |
16 import dil.semantic.Pass1, | |
17 dil.semantic.Pass2, | |
18 dil.semantic.Interpreter; | |
19 import dil.translator.German; | |
20 import dil.doc.Doc; | |
21 import dil.Messages; | |
22 import dil.CompilerInfo; | |
23 import dil.Information; | |
24 import dil.SourceText; | |
25 import dil.Compilation; | |
26 | |
27 import cmd.Generate; | |
28 import cmd.Statistics; | |
29 import cmd.ImportGraph; | |
30 import cmd.DDoc; | |
31 | |
32 import Settings; | |
33 import SettingsLoader; | |
34 // import TypeRules; | |
35 import common; | |
36 | |
37 import Integer = tango.text.convert.Integer; | |
38 import tango.stdc.stdio; | |
39 import tango.io.File; | |
40 import tango.text.Util; | |
41 import tango.time.StopWatch; | |
42 import tango.text.Ascii : icompare; | |
43 | |
44 /// Entry function of dil. | |
45 void main(char[][] args) | |
46 { | |
47 auto infoMan = new InfoManager(); | |
48 SettingsLoader.SettingsLoader(infoMan).load(); | |
49 if (infoMan.hasInfo) | |
50 return printErrors(infoMan); | |
51 | |
52 if (args.length <= 1) | |
53 return Stdout(helpMain()).newline; | |
54 | |
55 string command = args[1]; | |
56 switch (command) | |
57 { | |
58 case "c", "compile": | |
59 if (args.length < 2) | |
60 return printHelp("compile"); | |
61 | |
62 string[] filePaths; | |
63 auto context = newCompilationContext(); | |
64 foreach (arg; args[2..$]) | |
65 { | |
66 if (parseDebugOrVersion(arg, context)) | |
67 {} | |
68 else | |
69 filePaths ~= arg; | |
70 } | |
71 infoMan = new InfoManager(); | |
72 foreach (filePath; filePaths) | |
73 { | |
74 auto mod = new Module(filePath, infoMan); | |
75 // Parse the file. | |
76 mod.parse(); | |
77 if (mod.hasErrors) | |
78 continue; | |
79 | |
80 // Start semantic analysis. | |
81 auto pass1 = new SemanticPass1(mod, context); | |
82 pass1.start(); | |
83 | |
84 void printSymbolTable(ScopeSymbol scopeSym, char[] indent) | |
85 { | |
86 foreach (member; scopeSym.members) | |
87 { | |
88 auto tokens = getDocTokens(member.node); | |
89 char[] docText; | |
90 foreach (token; tokens) | |
91 docText ~= token.srcText; | |
92 Stdout(indent).formatln("Id:{}, Symbol:{}, DocText:{}", member.name.str, member.classinfo.name, docText); | |
93 if (auto s = cast(ScopeSymbol)member) | |
94 printSymbolTable(s, indent ~ "→ "); | |
95 } | |
96 } | |
97 | |
98 printSymbolTable(mod, ""); | |
99 } | |
100 | |
101 infoMan.hasInfo && printErrors(infoMan); | |
102 break; | |
103 case "ddoc", "d": | |
104 if (args.length < 4) | |
105 return printHelp("ddoc"); | |
106 | |
107 auto destination = args[2]; | |
108 auto macroPaths = GlobalSettings.ddocFilePaths; | |
109 char[][] filePaths; | |
110 bool incUndoc; | |
111 bool writeXML; | |
112 bool verbose; | |
113 // Parse arguments. | |
114 auto context = newCompilationContext(); | |
115 foreach (arg; args[3..$]) | |
116 { | |
117 if (parseDebugOrVersion(arg, context)) | |
118 {} | |
119 else if (arg == "--xml") | |
120 writeXML = true; | |
121 else if (arg == "-i") | |
122 incUndoc = true; | |
123 else if (arg == "-v") | |
124 verbose = true; | |
125 else if (arg.length > 5 && icompare(arg[$-4..$], "ddoc") == 0) | |
126 macroPaths ~= arg; | |
127 else | |
128 filePaths ~= arg; | |
129 } | |
130 | |
131 infoMan = new InfoManager(); | |
132 // Execute command. | |
133 cmd.DDoc.execute(filePaths, destination, macroPaths, writeXML, | |
134 incUndoc, verbose, context, infoMan); | |
135 infoMan.hasInfo && printErrors(infoMan); | |
136 break; | |
137 case "gen", "generate": | |
138 char[] fileName; | |
139 GenOption options = GenOption.Tokens; | |
140 foreach (arg; args[2..$]) | |
141 { | |
142 switch (arg) | |
143 { | |
144 case "--syntax": | |
145 options |= GenOption.Syntax; break; | |
146 case "--xml": | |
147 options |= GenOption.XML; break; | |
148 case "--html": | |
149 options |= GenOption.HTML; break; | |
150 case "--lines": | |
151 options |= GenOption.PrintLines; break; | |
152 default: | |
153 fileName = arg; | |
154 } | |
155 } | |
156 if (!(options & (GenOption.XML | GenOption.HTML))) | |
157 options |= GenOption.XML; // Default to XML. | |
158 cmd.Generate.execute(fileName, options, infoMan); | |
159 infoMan.hasInfo && printErrors(infoMan); | |
160 break; | |
161 case "importgraph", "igraph": | |
162 string filePath; | |
163 string[] regexps; | |
164 string siStyle = "dashed"; // static import style | |
165 string piStyle = "bold"; // public import style | |
166 uint levels; | |
167 IGraphOption options; | |
168 auto context = newCompilationContext(); | |
169 foreach (arg; args[2..$]) | |
170 { | |
171 if (parseDebugOrVersion(arg, context)) | |
172 {} | |
173 else if (strbeg(arg, "-I")) | |
174 context.importPaths ~= arg[2..$]; | |
175 else if(strbeg(arg, "-r")) | |
176 regexps ~= arg[2..$]; | |
177 else if(strbeg(arg, "-l")) | |
178 levels = Integer.toInt(arg[2..$]); | |
179 else if(strbeg(arg, "-si")) | |
180 siStyle = arg[3..$]; | |
181 else if(strbeg(arg, "-pi")) | |
182 piStyle = arg[3..$]; | |
183 else | |
184 switch (arg) | |
185 { | |
186 case "--dot": | |
187 options |= IGraphOption.PrintDot; break; | |
188 case "--paths": | |
189 options |= IGraphOption.PrintPaths; break; | |
190 case "--list": | |
191 options |= IGraphOption.PrintList; break; | |
192 case "-i": | |
193 options |= IGraphOption.IncludeUnlocatableModules; break; | |
194 case "-hle": | |
195 options |= IGraphOption.HighlightCyclicEdges; break; | |
196 case "-hlv": | |
197 options |= IGraphOption.HighlightCyclicVertices; break; | |
198 case "-gbp": | |
199 options |= IGraphOption.GroupByPackageNames; break; | |
200 case "-gbf": | |
201 options |= IGraphOption.GroupByFullPackageName; break; | |
202 case "-m": | |
203 options |= IGraphOption.MarkCyclicModules; break; | |
204 default: | |
205 filePath = arg; | |
206 } | |
207 } | |
208 cmd.ImportGraph.execute(filePath, context, regexps, levels, siStyle, piStyle, options); | |
209 break; | |
210 case "stats", "statistics": | |
211 char[][] filePaths; | |
212 bool printTokensTable; | |
213 bool printNodesTable; | |
214 foreach (arg; args[2..$]) | |
215 if (arg == "--toktable") | |
216 printTokensTable = true; | |
217 else if (arg == "--asttable") | |
218 printNodesTable = true; | |
219 else | |
220 filePaths ~= arg; | |
221 cmd.Statistics.execute(filePaths, printTokensTable, printNodesTable); | |
222 break; | |
223 case "tok", "tokenize": | |
224 SourceText sourceText; | |
225 char[] filePath; | |
226 char[] separator; | |
227 bool ignoreWSToks; | |
228 bool printWS; | |
229 | |
230 foreach (arg; args[2..$]) | |
231 { | |
232 if (strbeg(arg, "-s")) | |
233 separator = arg[2..$]; | |
234 else if (arg == "-") | |
235 sourceText = new SourceText("stdin", readStdin()); | |
236 else if (arg == "-i") | |
237 ignoreWSToks = true; | |
238 else if (arg == "-ws") | |
239 printWS = true; | |
240 else | |
241 filePath = arg; | |
242 } | |
243 | |
244 separator || (separator = "\n"); | |
245 if (!sourceText) | |
246 sourceText = new SourceText(filePath, true); | |
247 | |
248 infoMan = new InfoManager(); | |
249 auto lx = new Lexer(sourceText, infoMan); | |
250 lx.scanAll(); | |
251 auto token = lx.firstToken(); | |
252 | |
253 for (; token.kind != TOK.EOF; token = token.next) | |
254 { | |
255 if (token.kind == TOK.Newline || ignoreWSToks && token.isWhitespace) | |
256 continue; | |
257 if (printWS && token.ws) | |
258 Stdout(token.wsChars); | |
259 Stdout(token.srcText)(separator); | |
260 } | |
261 | |
262 infoMan.hasInfo && printErrors(infoMan); | |
263 break; | |
264 case "trans", "translate": | |
265 if (args.length < 3) | |
266 return printHelp("trans"); | |
267 | |
268 if (args[2] != "German") | |
269 return Stdout.formatln("Error: unrecognized target language \"{}\"", args[2]); | |
270 | |
271 infoMan = new InfoManager(); | |
272 auto filePath = args[3]; | |
273 auto mod = new Module(filePath, infoMan); | |
274 // Parse the file. | |
275 mod.parse(); | |
276 if (!mod.hasErrors) | |
277 { // Translate | |
278 auto german = new GermanTranslator(Stdout, " "); | |
279 german.translate(mod.root); | |
280 } | |
281 printErrors(infoMan); | |
282 break; | |
283 case "profile": | |
284 if (args.length < 3) | |
285 break; | |
286 char[][] filePaths; | |
287 if (args[2] == "dstress") | |
288 { | |
289 auto text = cast(char[])(new File("dstress_files")).read(); | |
290 filePaths = split(text, "\0"); | |
291 } | |
292 else | |
293 filePaths = args[2..$]; | |
294 | |
295 StopWatch swatch; | |
296 swatch.start; | |
297 | |
298 foreach (filePath; filePaths) | |
299 (new Lexer(new SourceText(filePath, true))).scanAll(); | |
300 | |
301 Stdout.formatln("Scanned in {:f10}s.", swatch.stop); | |
302 break; | |
303 // case "parse": | |
304 // if (args.length == 3) | |
305 // parse(args[2]); | |
306 // break; | |
307 case "?", "help": | |
308 printHelp(args.length >= 3 ? args[2] : ""); | |
309 break; | |
310 // case "typerules": | |
311 // genHTMLTypeRulesTables(); | |
312 // break; | |
313 default: | |
314 } | |
315 } | |
316 | |
317 char[] readStdin() | |
318 { | |
319 char[] text; | |
320 while (1) | |
321 { | |
322 auto c = getc(stdin); | |
323 if (c == EOF) | |
324 break; | |
325 text ~= c; | |
326 } | |
327 return text; | |
328 } | |
329 | |
330 /// Available commands. | |
331 const char[] COMMANDS = | |
332 " compile (c)\n" | |
333 " ddoc (d)\n" | |
334 " generate (gen)\n" | |
335 " help (?)\n" | |
336 " importgraph (igraph)\n" | |
337 " statistics (stats)\n" | |
338 " tokenize (tok)\n" | |
339 " translate (trans)\n"; | |
340 | |
341 bool strbeg(char[] str, char[] begin) | |
342 { | |
343 if (str.length >= begin.length) | |
344 { | |
345 if (str[0 .. begin.length] == begin) | |
346 return true; | |
347 } | |
348 return false; | |
349 } | |
350 | |
351 /// Creates the global compilation context. | |
352 CompilationContext newCompilationContext() | |
353 { | |
354 auto cc = new CompilationContext; | |
355 cc.importPaths = GlobalSettings.importPaths; | |
356 cc.addVersionId("dil"); | |
357 cc.addVersionId("all"); | |
358 version(D2) | |
359 cc.addVersionId("D_Version2"); | |
360 foreach (versionId; GlobalSettings.versionIds) | |
361 if (!Lexer.isReservedIdentifier(versionId)) | |
362 cc.versionIds[versionId] = true; | |
363 return cc; | |
364 } | |
365 | |
366 bool parseDebugOrVersion(string arg, CompilationContext context) | |
367 { | |
368 if (strbeg(arg, "-debug")) | |
369 { | |
370 if (arg.length > 7) | |
371 { | |
372 auto val = arg[7..$]; | |
373 if (isdigit(val[0])) | |
374 context.debugLevel = Integer.toInt(val); | |
375 else if (!Lexer.isReservedIdentifier(val)) | |
376 context.addDebugId(val); | |
377 } | |
378 else | |
379 context.debugLevel = 1; | |
380 } | |
381 else if (arg.length > 9 && strbeg(arg, "-version=")) | |
382 { | |
383 auto val = arg[9..$]; | |
384 if (isdigit(val[0])) | |
385 context.versionLevel = Integer.toInt(val); | |
386 else if (!Lexer.isReservedIdentifier(val)) | |
387 context.addVersionId(val); | |
388 } | |
389 else | |
390 return false; | |
391 return true; | |
392 } | |
393 | |
394 /// Prints the errors collected in infoMan. | |
395 void printErrors(InfoManager infoMan) | |
396 { | |
397 foreach (info; infoMan.info) | |
398 { | |
399 char[] errorFormat; | |
400 if (info.classinfo is LexerError.classinfo) | |
401 errorFormat = GlobalSettings.lexerErrorFormat; | |
402 else if (info.classinfo is ParserError.classinfo) | |
403 errorFormat = GlobalSettings.parserErrorFormat; | |
404 else if (info.classinfo is SemanticError.classinfo) | |
405 errorFormat = GlobalSettings.semanticErrorFormat; | |
406 else if (info.classinfo is Warning.classinfo) | |
407 errorFormat = "{0}: Warning: {3}"; | |
408 else | |
409 continue; | |
410 auto err = cast(Problem)info; | |
411 Stderr.formatln(errorFormat, err.filePath, err.loc, err.col, err.getMsg); | |
412 } | |
413 } | |
414 | |
415 /// Prints the compiler's main help message. | |
416 char[] helpMain() | |
417 { | |
418 auto COMPILED_WITH = __VENDOR__; | |
419 auto COMPILED_VERSION = Format("{}.{,:d3}", __VERSION__/1000, __VERSION__%1000); | |
420 auto COMPILED_DATE = __TIMESTAMP__; | |
421 return FormatMsg(MID.HelpMain, VERSION, COMMANDS, COMPILED_WITH, | |
422 COMPILED_VERSION, COMPILED_DATE); | |
423 } | |
424 | |
425 /// Prints a help message for command. | |
426 void printHelp(char[] command) | |
427 { | |
428 char[] msg; | |
429 switch (command) | |
430 { | |
431 case "c", "compile": | |
432 msg = `Compile D source files. | |
433 Usage: | |
434 dil compile file.d [file2.d, ...] [Options] | |
435 | |
436 This command only parses the source files and does little semantic analysis. | |
437 Errors are printed to standard error output. | |
438 | |
439 Options: | |
440 -debug : include debug code | |
441 -debug=level : include debug(l) code where l <= level | |
442 -debug=ident : include debug(ident) code | |
443 -version=level : include version(l) code where l >= level | |
444 -version=ident : include version(ident) code | |
445 | |
446 Example: | |
447 dil c src/main.d`; | |
448 break; | |
449 case "ddoc", "d": | |
450 msg = `Generate documentation from DDoc comments in D source files. | |
451 Usage: | |
452 dil ddoc Destination file.d [file2.d, ...] [Options] | |
453 | |
454 Destination is the folder where the documentation files are written to. | |
455 Files with the extension .ddoc are recognized as macro definition files. | |
456 | |
457 Options: | |
458 --xml : write XML instead of HTML documents | |
459 -i : include undocumented symbols | |
460 -v : verbose output | |
461 | |
462 Example: | |
463 dil d doc/ src/main.d src/macros_dil.ddoc -i`; | |
464 break; | |
465 case "gen", "generate": | |
466 // msg = GetMsg(MID.HelpGenerate); | |
467 msg = `Generate an XML or HTML document from a D source file. | |
468 Usage: | |
469 dil gen file.d [Options] | |
470 | |
471 Options: | |
472 --syntax : generate tags for the syntax tree | |
473 --xml : use XML format (default) | |
474 --html : use HTML format | |
475 --lines : print line numbers | |
476 | |
477 Example: | |
478 dil gen Parser.d --html --syntax > Parser.html`; | |
479 break; | |
480 case "importgraph", "igraph": | |
481 // msg = GetMsg(MID.HelpImportGraph); | |
482 msg = `Parse a module and build a module dependency graph based on its imports. | |
483 Usage: | |
484 dil igraph file.d Format [Options] | |
485 | |
486 The directory of file.d is implicitly added to the list of import paths. | |
487 | |
488 Format: | |
489 --dot : generate a dot document (default) | |
490 Options related to --dot: | |
491 -gbp : Group modules by package names | |
492 -gbf : Group modules by full package name | |
493 -hle : highlight cyclic edges in the graph | |
494 -hlv : highlight modules in cyclic relationships | |
495 -siSTYLE : the edge style to use for static imports | |
496 -piSTYLE : the edge style to use for public imports | |
497 STYLE can be: "dashed", "dotted", "solid", "invis" or "bold" | |
498 | |
499 --paths : print the file paths of the modules in the graph | |
500 | |
501 --list : print the names of the module in the graph | |
502 Options common to --paths and --list: | |
503 -lN : print N levels. | |
504 -m : use '*' to mark modules in cyclic relationships | |
505 | |
506 Options: | |
507 -Ipath : add 'path' to the list of import paths where modules are | |
508 looked for | |
509 -rREGEXP : exclude modules whose names match the regular expression | |
510 REGEXP | |
511 -i : include unlocatable modules | |
512 | |
513 Example: | |
514 dil igraph src/main.d --list | |
515 dil igraph src/main.d | dot -Tpng > main.png`; | |
516 break; | |
517 case "tok", "tokenize": | |
518 msg = `Print the tokens of a D source file. | |
519 Usage: | |
520 dil tok file.d [Options] | |
521 | |
522 Options: | |
523 - : reads text from the standard input. | |
524 -sSEPARATOR : print SEPARATOR instead of newline between tokens. | |
525 -i : ignore whitespace tokens (e.g. comments, shebang etc.) | |
526 -ws : print a token's preceding whitespace characters. | |
527 | |
528 Example: | |
529 echo "module foo; void func(){}" | dil tok - | |
530 dil tok main.d | grep ^[0-9]`; | |
531 break; | |
532 case "stats", "statistics": | |
533 msg = "Gather statistics about D source files. | |
534 Usage: | |
535 dil stat file.d [file2.d, ...] [Options] | |
536 | |
537 Options: | |
538 --toktable : print the count of all kinds of tokens in a table. | |
539 --asttable : print the count of all kinds of nodes in a table. | |
540 | |
541 Example: | |
542 dil stat src/dil/Parser.d src/dil/Lexer.d"; | |
543 break; | |
544 case "trans", "translate": | |
545 msg = `Translate a D source file to another language. | |
546 Usage: | |
547 dil translate Language file.d | |
548 | |
549 Languages that are supported: | |
550 *) German | |
551 | |
552 Example: | |
553 dil trans German src/main.d`; | |
554 break; | |
555 default: | |
556 msg = helpMain(); | |
557 } | |
558 Stdout(msg).newline; | |
559 } | |
560 | |
561 /+void parse(string fileName) | |
562 { | |
563 auto mod = new Module(fileName); | |
564 mod.parse(); | |
565 | |
566 void print(Node[] decls, char[] indent) | |
567 { | |
568 foreach(decl; decls) | |
569 { | |
570 assert(decl !is null); | |
571 Stdout.formatln("{}{}: begin={} end={}", indent, decl.classinfo.name, decl.begin ? decl.begin.srcText : "\33[31mnull\33[0m", decl.end ? decl.end.srcText : "\33[31mnull\33[0m"); | |
572 print(decl.children, indent ~ " "); | |
573 } | |
574 } | |
575 print(mod.root.children, ""); | |
576 }+/ |