Mercurial > projects > dil
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.d Sun Mar 09 00:12:19 2008 +0100 @@ -0,0 +1,576 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module main; + +import dil.parser.Parser; +import dil.lexer.Lexer, + dil.lexer.Token; +import dil.ast.Declarations, + dil.ast.Expressions, + dil.ast.Node, + dil.ast.Visitor; +import dil.semantic.Module; +import dil.semantic.Symbols; +import dil.semantic.Pass1, + dil.semantic.Pass2, + dil.semantic.Interpreter; +import dil.translator.German; +import dil.doc.Doc; +import dil.Messages; +import dil.CompilerInfo; +import dil.Information; +import dil.SourceText; +import dil.Compilation; + +import cmd.Generate; +import cmd.Statistics; +import cmd.ImportGraph; +import cmd.DDoc; + +import Settings; +import SettingsLoader; +// import TypeRules; +import common; + +import Integer = tango.text.convert.Integer; +import tango.stdc.stdio; +import tango.io.File; +import tango.text.Util; +import tango.time.StopWatch; +import tango.text.Ascii : icompare; + +/// Entry function of dil. +void main(char[][] args) +{ + auto infoMan = new InfoManager(); + SettingsLoader.SettingsLoader(infoMan).load(); + if (infoMan.hasInfo) + return printErrors(infoMan); + + if (args.length <= 1) + return Stdout(helpMain()).newline; + + string command = args[1]; + switch (command) + { + case "c", "compile": + if (args.length < 2) + return printHelp("compile"); + + string[] filePaths; + auto context = newCompilationContext(); + foreach (arg; args[2..$]) + { + if (parseDebugOrVersion(arg, context)) + {} + else + filePaths ~= arg; + } + infoMan = new InfoManager(); + foreach (filePath; filePaths) + { + auto mod = new Module(filePath, infoMan); + // Parse the file. + mod.parse(); + if (mod.hasErrors) + continue; + + // Start semantic analysis. + auto pass1 = new SemanticPass1(mod, context); + pass1.start(); + + void printSymbolTable(ScopeSymbol scopeSym, char[] indent) + { + foreach (member; scopeSym.members) + { + auto tokens = getDocTokens(member.node); + char[] docText; + foreach (token; tokens) + docText ~= token.srcText; + Stdout(indent).formatln("Id:{}, Symbol:{}, DocText:{}", member.name.str, member.classinfo.name, docText); + if (auto s = cast(ScopeSymbol)member) + printSymbolTable(s, indent ~ "→ "); + } + } + + printSymbolTable(mod, ""); + } + + infoMan.hasInfo && printErrors(infoMan); + break; + case "ddoc", "d": + if (args.length < 4) + return printHelp("ddoc"); + + auto destination = args[2]; + auto macroPaths = GlobalSettings.ddocFilePaths; + char[][] filePaths; + bool incUndoc; + bool writeXML; + bool verbose; + // Parse arguments. + auto context = newCompilationContext(); + foreach (arg; args[3..$]) + { + if (parseDebugOrVersion(arg, context)) + {} + else if (arg == "--xml") + writeXML = true; + else if (arg == "-i") + incUndoc = true; + else if (arg == "-v") + verbose = true; + else if (arg.length > 5 && icompare(arg[$-4..$], "ddoc") == 0) + macroPaths ~= arg; + else + filePaths ~= arg; + } + + infoMan = new InfoManager(); + // Execute command. + cmd.DDoc.execute(filePaths, destination, macroPaths, writeXML, + incUndoc, verbose, context, infoMan); + infoMan.hasInfo && printErrors(infoMan); + break; + case "gen", "generate": + char[] fileName; + GenOption options = GenOption.Tokens; + foreach (arg; args[2..$]) + { + switch (arg) + { + case "--syntax": + options |= GenOption.Syntax; break; + case "--xml": + options |= GenOption.XML; break; + case "--html": + options |= GenOption.HTML; break; + case "--lines": + options |= GenOption.PrintLines; break; + default: + fileName = arg; + } + } + if (!(options & (GenOption.XML | GenOption.HTML))) + options |= GenOption.XML; // Default to XML. + cmd.Generate.execute(fileName, options, infoMan); + infoMan.hasInfo && printErrors(infoMan); + break; + case "importgraph", "igraph": + string filePath; + string[] regexps; + string siStyle = "dashed"; // static import style + string piStyle = "bold"; // public import style + uint levels; + IGraphOption options; + auto context = newCompilationContext(); + foreach (arg; args[2..$]) + { + if (parseDebugOrVersion(arg, context)) + {} + else if (strbeg(arg, "-I")) + context.importPaths ~= arg[2..$]; + else if(strbeg(arg, "-r")) + regexps ~= arg[2..$]; + else if(strbeg(arg, "-l")) + levels = Integer.toInt(arg[2..$]); + else if(strbeg(arg, "-si")) + siStyle = arg[3..$]; + else if(strbeg(arg, "-pi")) + piStyle = arg[3..$]; + else + switch (arg) + { + case "--dot": + options |= IGraphOption.PrintDot; break; + case "--paths": + options |= IGraphOption.PrintPaths; break; + case "--list": + options |= IGraphOption.PrintList; break; + case "-i": + options |= IGraphOption.IncludeUnlocatableModules; break; + case "-hle": + options |= IGraphOption.HighlightCyclicEdges; break; + case "-hlv": + options |= IGraphOption.HighlightCyclicVertices; break; + case "-gbp": + options |= IGraphOption.GroupByPackageNames; break; + case "-gbf": + options |= IGraphOption.GroupByFullPackageName; break; + case "-m": + options |= IGraphOption.MarkCyclicModules; break; + default: + filePath = arg; + } + } + cmd.ImportGraph.execute(filePath, context, regexps, levels, siStyle, piStyle, options); + break; + case "stats", "statistics": + char[][] filePaths; + bool printTokensTable; + bool printNodesTable; + foreach (arg; args[2..$]) + if (arg == "--toktable") + printTokensTable = true; + else if (arg == "--asttable") + printNodesTable = true; + else + filePaths ~= arg; + cmd.Statistics.execute(filePaths, printTokensTable, printNodesTable); + break; + case "tok", "tokenize": + SourceText sourceText; + char[] filePath; + char[] separator; + bool ignoreWSToks; + bool printWS; + + foreach (arg; args[2..$]) + { + if (strbeg(arg, "-s")) + separator = arg[2..$]; + else if (arg == "-") + sourceText = new SourceText("stdin", readStdin()); + else if (arg == "-i") + ignoreWSToks = true; + else if (arg == "-ws") + printWS = true; + else + filePath = arg; + } + + separator || (separator = "\n"); + if (!sourceText) + sourceText = new SourceText(filePath, true); + + infoMan = new InfoManager(); + auto lx = new Lexer(sourceText, infoMan); + lx.scanAll(); + auto token = lx.firstToken(); + + for (; token.kind != TOK.EOF; token = token.next) + { + if (token.kind == TOK.Newline || ignoreWSToks && token.isWhitespace) + continue; + if (printWS && token.ws) + Stdout(token.wsChars); + Stdout(token.srcText)(separator); + } + + infoMan.hasInfo && printErrors(infoMan); + break; + case "trans", "translate": + if (args.length < 3) + return printHelp("trans"); + + if (args[2] != "German") + return Stdout.formatln("Error: unrecognized target language \"{}\"", args[2]); + + infoMan = new InfoManager(); + auto filePath = args[3]; + auto mod = new Module(filePath, infoMan); + // Parse the file. + mod.parse(); + if (!mod.hasErrors) + { // Translate + auto german = new GermanTranslator(Stdout, " "); + german.translate(mod.root); + } + printErrors(infoMan); + break; + case "profile": + if (args.length < 3) + break; + char[][] filePaths; + if (args[2] == "dstress") + { + auto text = cast(char[])(new File("dstress_files")).read(); + filePaths = split(text, "\0"); + } + else + filePaths = args[2..$]; + + StopWatch swatch; + swatch.start; + + foreach (filePath; filePaths) + (new Lexer(new SourceText(filePath, true))).scanAll(); + + Stdout.formatln("Scanned in {:f10}s.", swatch.stop); + break; + // case "parse": + // if (args.length == 3) + // parse(args[2]); + // break; + case "?", "help": + printHelp(args.length >= 3 ? args[2] : ""); + break; + // case "typerules": + // genHTMLTypeRulesTables(); + // break; + default: + } +} + +char[] readStdin() +{ + char[] text; + while (1) + { + auto c = getc(stdin); + if (c == EOF) + break; + text ~= c; + } + return text; +} + +/// Available commands. +const char[] COMMANDS = + " compile (c)\n" + " ddoc (d)\n" + " generate (gen)\n" + " help (?)\n" + " importgraph (igraph)\n" + " statistics (stats)\n" + " tokenize (tok)\n" + " translate (trans)\n"; + +bool strbeg(char[] str, char[] begin) +{ + if (str.length >= begin.length) + { + if (str[0 .. begin.length] == begin) + return true; + } + return false; +} + +/// Creates the global compilation context. +CompilationContext newCompilationContext() +{ + auto cc = new CompilationContext; + cc.importPaths = GlobalSettings.importPaths; + cc.addVersionId("dil"); + cc.addVersionId("all"); +version(D2) + cc.addVersionId("D_Version2"); + foreach (versionId; GlobalSettings.versionIds) + if (!Lexer.isReservedIdentifier(versionId)) + cc.versionIds[versionId] = true; + return cc; +} + +bool parseDebugOrVersion(string arg, CompilationContext context) +{ + if (strbeg(arg, "-debug")) + { + if (arg.length > 7) + { + auto val = arg[7..$]; + if (isdigit(val[0])) + context.debugLevel = Integer.toInt(val); + else if (!Lexer.isReservedIdentifier(val)) + context.addDebugId(val); + } + else + context.debugLevel = 1; + } + else if (arg.length > 9 && strbeg(arg, "-version=")) + { + auto val = arg[9..$]; + if (isdigit(val[0])) + context.versionLevel = Integer.toInt(val); + else if (!Lexer.isReservedIdentifier(val)) + context.addVersionId(val); + } + else + return false; + return true; +} + +/// Prints the errors collected in infoMan. +void printErrors(InfoManager infoMan) +{ + foreach (info; infoMan.info) + { + char[] errorFormat; + if (info.classinfo is LexerError.classinfo) + errorFormat = GlobalSettings.lexerErrorFormat; + else if (info.classinfo is ParserError.classinfo) + errorFormat = GlobalSettings.parserErrorFormat; + else if (info.classinfo is SemanticError.classinfo) + errorFormat = GlobalSettings.semanticErrorFormat; + else if (info.classinfo is Warning.classinfo) + errorFormat = "{0}: Warning: {3}"; + else + continue; + auto err = cast(Problem)info; + Stderr.formatln(errorFormat, err.filePath, err.loc, err.col, err.getMsg); + } +} + +/// Prints the compiler's main help message. +char[] helpMain() +{ + auto COMPILED_WITH = __VENDOR__; + auto COMPILED_VERSION = Format("{}.{,:d3}", __VERSION__/1000, __VERSION__%1000); + auto COMPILED_DATE = __TIMESTAMP__; + return FormatMsg(MID.HelpMain, VERSION, COMMANDS, COMPILED_WITH, + COMPILED_VERSION, COMPILED_DATE); +} + +/// Prints a help message for command. +void printHelp(char[] command) +{ + char[] msg; + switch (command) + { + case "c", "compile": + msg = `Compile D source files. +Usage: + dil compile file.d [file2.d, ...] [Options] + + This command only parses the source files and does little semantic analysis. + Errors are printed to standard error output. + +Options: + -debug : include debug code + -debug=level : include debug(l) code where l <= level + -debug=ident : include debug(ident) code + -version=level : include version(l) code where l >= level + -version=ident : include version(ident) code + +Example: + dil c src/main.d`; + break; + case "ddoc", "d": + msg = `Generate documentation from DDoc comments in D source files. +Usage: + dil ddoc Destination file.d [file2.d, ...] [Options] + + Destination is the folder where the documentation files are written to. + Files with the extension .ddoc are recognized as macro definition files. + +Options: + --xml : write XML instead of HTML documents + -i : include undocumented symbols + -v : verbose output + +Example: + dil d doc/ src/main.d src/macros_dil.ddoc -i`; + break; + case "gen", "generate": +// msg = GetMsg(MID.HelpGenerate); + msg = `Generate an XML or HTML document from a D source file. +Usage: + dil gen file.d [Options] + +Options: + --syntax : generate tags for the syntax tree + --xml : use XML format (default) + --html : use HTML format + --lines : print line numbers + +Example: + dil gen Parser.d --html --syntax > Parser.html`; + break; + case "importgraph", "igraph": +// msg = GetMsg(MID.HelpImportGraph); + msg = `Parse a module and build a module dependency graph based on its imports. +Usage: + dil igraph file.d Format [Options] + + The directory of file.d is implicitly added to the list of import paths. + +Format: + --dot : generate a dot document (default) + Options related to --dot: + -gbp : Group modules by package names + -gbf : Group modules by full package name + -hle : highlight cyclic edges in the graph + -hlv : highlight modules in cyclic relationships + -siSTYLE : the edge style to use for static imports + -piSTYLE : the edge style to use for public imports + STYLE can be: "dashed", "dotted", "solid", "invis" or "bold" + + --paths : print the file paths of the modules in the graph + + --list : print the names of the module in the graph + Options common to --paths and --list: + -lN : print N levels. + -m : use '*' to mark modules in cyclic relationships + +Options: + -Ipath : add 'path' to the list of import paths where modules are + looked for + -rREGEXP : exclude modules whose names match the regular expression + REGEXP + -i : include unlocatable modules + +Example: + dil igraph src/main.d --list + dil igraph src/main.d | dot -Tpng > main.png`; + break; + case "tok", "tokenize": + msg = `Print the tokens of a D source file. +Usage: + dil tok file.d [Options] + +Options: + - : reads text from the standard input. + -sSEPARATOR : print SEPARATOR instead of newline between tokens. + -i : ignore whitespace tokens (e.g. comments, shebang etc.) + -ws : print a token's preceding whitespace characters. + +Example: + echo "module foo; void func(){}" | dil tok - + dil tok main.d | grep ^[0-9]`; + break; + case "stats", "statistics": + msg = "Gather statistics about D source files. +Usage: + dil stat file.d [file2.d, ...] [Options] + +Options: + --toktable : print the count of all kinds of tokens in a table. + --asttable : print the count of all kinds of nodes in a table. + +Example: + dil stat src/dil/Parser.d src/dil/Lexer.d"; + break; + case "trans", "translate": + msg = `Translate a D source file to another language. +Usage: + dil translate Language file.d + + Languages that are supported: + *) German + +Example: + dil trans German src/main.d`; + break; + default: + msg = helpMain(); + } + Stdout(msg).newline; +} + +/+void parse(string fileName) +{ + auto mod = new Module(fileName); + mod.parse(); + + void print(Node[] decls, char[] indent) + { + foreach(decl; decls) + { + assert(decl !is null); + 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"); + print(decl.children, indent ~ " "); + } + } + print(mod.root.children, ""); +}+/