1 /// Author: Aziz Köksal
3 /// $(Maturity average)
6 import dil
.parser
.Parser
;
7 import dil
.lexer
.Lexer
,
9 import dil
.ast
.Declarations
,
13 import dil
.semantic
.Module
,
18 import dil
.code
.Interpreter
;
19 import dil
.translator
.German
;
21 import dil
.CompilerInfo
;
22 import dil
.Diagnostics
;
23 import dil
.SourceText
;
24 import dil
.Compilation
;
28 import cmd
.Statistics
;
29 import cmd
.ImportGraph
;
33 import SettingsLoader
;
36 import Integer
= tango
.text
.convert
.Integer
;
37 import tango
.stdc
.stdio
;
39 import tango
.text
.Util
;
40 import tango
.time
.StopWatch
;
41 import tango
.text
.Ascii
: icompare
;
43 /// Entry function of dil.
44 void main(char[][] args
)
46 auto diag
= new Diagnostics();
47 ConfigLoader(diag
).load();
49 return printErrors(diag
);
52 return printHelp("main");
54 string command
= args
[1];
59 return printHelp(command
);
62 cmd
.context
= newCompilationContext();
65 foreach (arg
; args
[2..$])
67 if (parseDebugOrVersion(arg
, cmd
.context
))
69 else if (strbeg(arg
, "-I"))
70 cmd
.context
.importPaths
~= arg
[2..$];
71 else if (arg
== "-release")
72 cmd
.context
.releaseBuild
= true;
73 else if (arg
== "-unittest")
76 cmd
.context
.addVersionId("unittest");
77 cmd
.context
.unittestBuild
= true;
80 cmd
.context
.acceptDeprecated
= true;
81 else if (arg
== "-ps")
82 cmd
.printSymbolTree
= true;
83 else if (arg
== "-pm")
84 cmd
.printModuleTree
= true;
89 diag
.hasInfo
&& printErrors(diag
);
93 return printHelp(command
);
96 cmd
.destDirPath
= args
[2];
97 cmd
.macroPaths
= GlobalSettings
.ddocFilePaths
;
98 cmd
.context
= newCompilationContext();
102 foreach (arg
; args
[3..$])
104 if (parseDebugOrVersion(arg
, cmd
.context
))
106 else if (arg
== "--xml")
108 else if (arg
== "-i")
109 cmd
.includeUndocumented
= true;
110 else if (arg
== "-v")
112 else if (arg
.length
> 3 && strbeg(arg
, "-m="))
113 cmd
.modsTxtPath
= arg
[3..$];
114 else if (arg
.length
> 5 && icompare(arg
[$-4..$], "ddoc") == 0)
115 cmd
.macroPaths
~= arg
;
117 cmd
.filePaths
~= arg
;
120 diag
.hasInfo
&& printErrors(diag
);
122 case "hl", "highlight":
124 return printHelp(command
);
126 HighlightCommand cmd
;
129 foreach (arg
; args
[2..$])
134 cmd
.add(HighlightCommand
.Option
.Syntax
); break;
136 cmd
.add(HighlightCommand
.Option
.XML
); break;
138 cmd
.add(HighlightCommand
.Option
.HTML
); break;
140 cmd
.add(HighlightCommand
.Option
.PrintLines
); break;
146 diag
.hasInfo
&& printErrors(diag
);
148 case "importgraph", "igraph":
150 return printHelp(command
);
153 cmd
.context
= newCompilationContext();
155 foreach (arg
; args
[2..$])
157 if (parseDebugOrVersion(arg
, cmd
.context
))
159 else if (strbeg(arg
, "-I"))
160 cmd
.context
.importPaths
~= arg
[2..$];
161 else if(strbeg(arg
, "-x"))
162 cmd
.regexps
~= arg
[2..$];
163 else if(strbeg(arg
, "-l"))
164 cmd
.levels
= Integer
.toInt(arg
[2..$]);
165 else if(strbeg(arg
, "-si"))
166 cmd
.siStyle
= arg
[3..$];
167 else if(strbeg(arg
, "-pi"))
168 cmd
.piStyle
= arg
[3..$];
173 cmd
.add(IGraphCommand
.Option
.PrintDot
); break;
175 cmd
.add(IGraphCommand
.Option
.PrintPaths
); break;
177 cmd
.add(IGraphCommand
.Option
.PrintList
); break;
179 cmd
.add(IGraphCommand
.Option
.IncludeUnlocatableModules
); break;
181 cmd
.add(IGraphCommand
.Option
.HighlightCyclicEdges
); break;
183 cmd
.add(IGraphCommand
.Option
.HighlightCyclicVertices
); break;
185 cmd
.add(IGraphCommand
.Option
.GroupByPackageNames
); break;
187 cmd
.add(IGraphCommand
.Option
.GroupByFullPackageName
); break;
189 cmd
.add(IGraphCommand
.Option
.MarkCyclicModules
); break;
196 case "stats", "statistics":
198 return printHelp(command
);
201 foreach (arg
; args
[2..$])
202 if (arg
== "--toktable")
203 cmd
.printTokensTable
= true;
204 else if (arg
== "--asttable")
205 cmd
.printNodesTable
= true;
207 cmd
.filePaths
~= arg
;
210 case "tok", "tokenize":
212 return printHelp(command
);
213 SourceText sourceText
;
219 foreach (arg
; args
[2..$])
221 if (strbeg(arg
, "-s"))
222 separator
= arg
[2..$];
224 sourceText
= new SourceText("stdin", readStdin());
225 else if (arg
== "-i")
227 else if (arg
== "-ws")
233 separator ||
(separator
= "\n");
235 sourceText
= new SourceText(filePath
, true);
237 diag
= new Diagnostics();
238 auto lx
= new Lexer(sourceText
, diag
);
240 auto token
= lx
.firstToken();
242 for (; token
.kind
!= TOK
.EOF
; token
= token
.next
)
244 if (token
.kind
== TOK
.Newline || ignoreWSToks
&& token
.isWhitespace
)
246 if (printWS
&& token
.ws
)
247 Stdout(token
.wsChars
);
248 Stdout(token
.srcText
)(separator
);
251 diag
.hasInfo
&& printErrors(diag
);
253 case "trans", "translate":
255 return printHelp(command
);
257 if (args
[2] != "German")
258 return Stdout
.formatln("Error: unrecognized target language \"{}\"", args
[2]);
260 diag
= new Diagnostics();
261 auto filePath
= args
[3];
262 auto mod
= new Module(filePath
, diag
);
267 auto german
= new GermanTranslator(Stdout
, " ");
268 german
.translate(mod
.root
);
276 if (args
[2] == "dstress")
278 auto text
= cast(char[])(new File("dstress_files")).read();
279 filePaths
= split(text
, "\0");
282 filePaths
= args
[2..$];
287 foreach (filePath
; filePaths
)
288 (new Lexer(new SourceText(filePath
, true))).scanAll();
290 Stdout
.formatln("Scanned in {:f10}s.", swatch
.stop
);
293 printHelp(args
.length
>= 3 ? args
[2] : "");
300 /// Reads the standard input and returns its contents.
306 auto c
= getc(stdin
);
314 /// Available commands.
315 const char[] COMMANDS
=
320 " importgraph (igraph)\n"
321 " statistics (stats)\n"
323 " translate (trans)\n";
325 bool strbeg(char[] str, char[] begin
)
327 if (str.length
>= begin
.length
)
329 if (str[0 .. begin
.length
] == begin
)
335 /// Creates the global compilation context.
336 CompilationContext
newCompilationContext()
338 auto cc
= new CompilationContext
;
339 cc
.importPaths
= GlobalSettings
.importPaths
;
340 cc
.addVersionId("dil");
341 cc
.addVersionId("all");
343 cc
.addVersionId("D_Version2");
344 foreach (versionId
; GlobalSettings
.versionIds
)
345 if (Lexer
.isValidUnreservedIdentifier(versionId
))
346 cc
.addVersionId(versionId
);
350 /// Parses a debug or version command line option.
351 bool parseDebugOrVersion(string arg
, CompilationContext context
)
353 if (strbeg(arg
, "-debug"))
357 auto val
= arg
[7..$];
359 context
.debugLevel
= Integer
.toInt(val
);
360 else if (Lexer
.isValidUnreservedIdentifier(val
))
361 context
.addDebugId(val
);
364 context
.debugLevel
= 1;
366 else if (arg
.length
> 9 && strbeg(arg
, "-version="))
368 auto val
= arg
[9..$];
370 context
.versionLevel
= Integer
.toInt(val
);
371 else if (Lexer
.isValidUnreservedIdentifier(val
))
372 context
.addVersionId(val
);
379 /// Prints the errors collected in diag.
380 void printErrors(Diagnostics diag
)
382 foreach (info
; diag
.info
)
385 if (info
.classinfo
is LexerError
.classinfo
)
386 errorFormat
= GlobalSettings
.lexerErrorFormat
;
387 else if (info
.classinfo
is ParserError
.classinfo
)
388 errorFormat
= GlobalSettings
.parserErrorFormat
;
389 else if (info
.classinfo
is SemanticError
.classinfo
)
390 errorFormat
= GlobalSettings
.semanticErrorFormat
;
391 else if (info
.classinfo
is Warning
.classinfo
)
392 errorFormat
= "{0}: Warning: {3}";
393 else if (info
.classinfo
is dil
.Information
.Error
.classinfo
)
394 errorFormat
= "Error: {3}";
397 auto err
= cast(Problem
)info
;
398 Stderr
.formatln(errorFormat
, err
.filePath
, err
.loc
, err
.col
, err
.getMsg
);
402 /// Prints the help message of a command.
403 /// If the command wasn't found, the main help message is printed.
404 void printHelp(char[] command
)
410 msg
= `Compile D source files.
412 dil compile file.d [file2.d, ...] [Options]
414 This command only parses the source files and does little semantic analysis.
415 Errors are printed to standard error output.
418 -d : accept deprecated code
419 -debug : include debug code
420 -debug=level : include debug(l) code where l <= level
421 -debug=ident : include debug(ident) code
422 -version=level : include version(l) code where l >= level
423 -version=ident : include version(ident) code
424 -Ipath : add 'path' to the list of import paths
425 -release : compile a release build
426 -unittest : compile a unittest build
427 -32 : produce 32 bit code (default)
428 -64 : produce 64 bit code
429 -ofPROG : output program to PROG
431 -ps : print the symbol tree of the modules
432 -pm : print the package/module tree
435 dil c src/main.d -Isrc/`;
438 msg
= `Generate documentation from DDoc comments in D source files.
440 dil ddoc Destination file.d [file2.d, ...] [Options]
442 Destination is the folder where the documentation files are written to.
443 Files with the extension .ddoc are recognized as macro definition files.
446 --xml : write XML instead of HTML documents
447 -i : include undocumented symbols
449 -m=PATH : write list of processed modules to PATH
452 dil d doc/ src/main.d src/macros_dil.ddoc -i -m=doc/modules.txt`;
454 case "hl", "highlight":
455 // msg = GetMsg(MID.HelpGenerate);
456 msg
= `Highlight a D source file with XML or HTML tags.
458 dil hl file.d [Options]
461 --syntax : generate tags for the syntax tree
462 --xml : use XML format (default)
463 --html : use HTML format
464 --lines : print line numbers
467 dil hl src/main.d --html --syntax > main.html`;
469 case "importgraph", "igraph":
470 // msg = GetMsg(MID.HelpImportGraph);
471 msg
= `Parse a module and build a module dependency graph based on its imports.
473 dil igraph file.d Format [Options]
475 The directory of file.d is implicitly added to the list of import paths.
478 --dot : generate a dot document (default)
479 Options related to --dot:
480 -gbp : Group modules by package names
481 -gbf : Group modules by full package name
482 -hle : highlight cyclic edges in the graph
483 -hlv : highlight modules in cyclic relationships
484 -siSTYLE : the edge style to use for static imports
485 -piSTYLE : the edge style to use for public imports
486 STYLE can be: "dashed", "dotted", "solid", "invis" or "bold"
488 --paths : print the file paths of the modules in the graph
490 --list : print the names of the module in the graph
491 Options common to --paths and --list:
492 -lN : print N levels.
493 -m : use '*' to mark modules in cyclic relationships
496 -Ipath : add 'path' to the list of import paths where modules are
498 -xREGEXP : exclude modules whose names match the regular expression
500 -i : include unlocatable modules
503 dil igraph src/main.d --list
504 dil igraph src/main.d | dot -Tpng > main.png`;
506 case "tok", "tokenize":
507 msg
= `Print the tokens of a D source file.
509 dil tok file.d [Options]
512 - : reads text from the standard input.
513 -sSEPARATOR : print SEPARATOR instead of newline between tokens.
514 -i : ignore whitespace tokens (e.g. comments, shebang etc.)
515 -ws : print a token's preceding whitespace characters.
518 echo "module foo; void func(){}" | dil tok -
519 dil tok src/main.d | grep ^[0-9]`;
521 case "stats", "statistics":
522 msg
= "Gather statistics about D source files.
524 dil stats file.d [file2.d, ...] [Options]
527 --toktable : print the count of all kinds of tokens in a table.
528 --asttable : print the count of all kinds of nodes in a table.
531 dil stats src/main.d src/dil/Unicode.d";
533 case "trans", "translate":
534 msg
= `Translate a D source file to another language.
536 dil translate Language file.d
538 Languages that are supported:
542 dil trans German src/main.d`;
546 auto COMPILED_WITH
= __VENDOR__
;
547 auto COMPILED_VERSION
= Format("{}.{,:d3}", __VERSION__
/1000, __VERSION__
%1000);
548 auto COMPILED_DATE
= __TIMESTAMP__
;
549 msg
= FormatMsg(MID
.HelpMain
, VERSION
, COMMANDS
, COMPILED_WITH
,
550 COMPILED_VERSION
, COMPILED_DATE
);