Mercurial > projects > dil
changeset 363:2b387a3c6b58
- Added package cmd.
- Moved code from main.d to cmd.Generate.
- Added command stats/statistics (implemented in cmd.Statistics.)
author | aziz |
---|---|
date | Thu, 30 Aug 2007 12:02:04 +0000 |
parents | 1b6e61915858 |
children | 1059295c2727 |
files | trunk/src/cmd/Generate.d trunk/src/cmd/Generate.d trunk/src/cmd/Statistics.d trunk/src/cmd/Statistics.d trunk/src/main.d |
diffstat | 3 files changed, 582 insertions(+), 488 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/cmd/Generate.d Thu Aug 30 12:02:04 2007 +0000 @@ -0,0 +1,497 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module cmd.Generate; +import dil.SyntaxTree; +import dil.Token; +import dil.Parser, dil.Lexer; +import dil.File; +import std.stdio; + +enum DocOption +{ + Tokens, + Syntax = 1<<1, + HTML = 1<<2, + XML = 1<<3 +} + +char[] xml_escape(char[] text) +{ + char[] result; + foreach(c; text) + switch(c) + { + case '<': result ~= "<"; break; + case '>': result ~= ">"; break; + case '&': result ~= "&"; break; + default: result ~= c; + } + return result; +} + +char[] getShortClassName(Node n) +{ + static char[][] name_table; + if (name_table is null) + name_table = new char[][NodeKind.max+1]; + char[] name = name_table[n.kind]; + if (name !is null) + return name; + + alias std.string.find find; + name = n.classinfo.name; + name = name[find(name, ".")+1 .. $]; // Remove package name + name = name[find(name, ".")+1 .. $]; // Remove module name + char[] remove; + switch (n.category) + { + alias NodeCategory NC; + case NC.Declaration: remove = "Declaration"; break; + case NC.Statement: + if (n.kind == NodeKind.Statements) + return name; + remove = "Statement"; + break; + case NC.Expression: remove = "Expression"; break; + case NC.Type: remove = "Type"; break; + case NC.Other: return name; + default: + } + // Remove common suffix. + auto idx = find(name, remove); + if (idx != -1) + name = name[0 .. idx]; + // Store the name. + name_table[n.kind] = name; + return name; +} + +enum DocPart +{ + Head, + CompBegin, + CompEnd, + Error, + SyntaxBegin, + SyntaxEnd, + SrcBegin, + SrcEnd, + Tail, + // Tokens: + Identifier, + Comment, + StringLiteral, + CharLiteral, + Operator, + LorG, + LessEqual, + GreaterEqual, + AndLogical, + OrLogical, + NotEqual, + Not, + Number, + Bracket, + SpecialToken, + Shebang, + Keyword, + HLineBegin, + HLineEnd, + Filespec, +} + +auto html_tags = [ + // Head + `<html>`\n + `<head>`\n + `<meta http-equiv="Content-Type" content="text/html; charset=utf-8">`\n + `<link href="dil_html.css" rel="stylesheet" type="text/css">`\n + `</head>`\n + `<body>`[], + // CompBegin + `<div class="compilerinfo">`, + // CompEnd + `</div>`, + // Error + `<p class="error %s">%s(%d)%s: %s</p>`, + // SyntaxBegin + `<span class="%s %s">`, + // SyntaxEnd + `</span>`, + // SrcBegin + `<pre class="sourcecode">`, + // SrcEnd + `</pre>`, + // Tail + `</html>`, + // Identifier + `<span class="i">%s</span>`, + // Comment + `<span class="c%s">%s</span>`, + // StringLiteral + `<span class="sl">%s</span>`, + // CharLiteral + `<span class="cl">%s</span>`, + // Operator + `<span class="op">%s</span>`, + // LorG + `<span class="oplg"><></span>`, + // LessEqual + `<span class="ople"><=</span>`, + // GreaterEqual + `<span class="opge">>=</span>`, + // AndLogical + `<span class="opaa">&&</span>`, + // OrLogical + `<span class="opoo">||</span>`, + // NotEqual + `<span class="opne">!=</span>`, + // Not + `<span class="opn">!</span>`, + // Number + `<span class="n">%s</span>`, + // Bracket + `<span class="br">%s</span>`, + // SpecialToken + `<span class="st">%s</span>`, + // Shebang + `<span class="shebang">%s</span>`, + // Keyword + `<span class="k">%s</span>`, + // HLineBegin + `<span class="hl">#line`, + // HLineEnd + "</span>", + // Filespec + `<span class="fs">%s</span>`, +]; + +auto xml_tags = [ + // Head + `<?xml version="1.0"?>`\n + `<?xml-stylesheet href="dil_xml.css" type="text/css"?>`\n + `<root>`[], + // CompBegin + `<compilerinfo>`, + // CompEnd + `</compilerinfo>`, + // Error + `<error t="%s">%s(%d)%s: %s</error>`, + // SyntaxBegin + `<%s t="%s">`, + // SyntaxEnd + `</%s>`, + // SrcBegin + `<sourcecode>`, + // SrcEnd + `</sourcecode>`, + // Tail + `</root>`, + // Identifier + "<i>%s</i>", + // Comment + `<c t="%s">%s</c>`, + // StringLiteral + "<sl>%s</sl>", + // CharLiteral + "<cl>%s</cl>", + // Operator + "<op>%s</op>", + // LorG + `<op t="lg"><></op>`, + // LessEqual + `<op t="le"><=</op>`, + // GreaterEqual + `<op t="ge">>=</op>`, + // AndLogical + `<op t="aa">&&</op>`, + // OrLogical + `<op t="oo">||</op>`, + // NotEqual + `<op t="ne">!=</op>`, + // Not + `<op t="n">!</op>`, + // Number + "<n>%s</n>", + // Bracket + "<br>%s</br>", + // SpecialToken + "<st>%s</st>", + // Shebang + "<shebang>%s</shebang>", + // Keyword + "<k>%s</k>", + // HLineBegin + "<hl>#line", + // HLineEnd + "</hl>", + // Filespec + "<fs>%s</fs>", +]; + +static assert(html_tags.length == DocPart.max+1); +static assert(xml_tags.length == DocPart.max+1); + +void syntaxToDoc(string fileName, DocOption options) +{ + auto tags = options & DocOption.HTML ? html_tags : xml_tags; + auto sourceText = loadFile(fileName); + auto parser = new Parser(sourceText, fileName); + parser.start(); + auto root = parser.parseModule(); + auto lx = parser.lx; + + auto token = lx.head; + char* end = lx.text.ptr; + + writefln(tags[DocPart.Head]); + // Output error messages. + if (lx.errors.length || parser.errors.length) + { + writefln(tags[DocPart.CompBegin]); + foreach (error; lx.errors) + { + writefln(tags[DocPart.Error], "L", lx.fileName, error.loc, "L", xml_escape(error.getMsg)); + } + foreach (error; parser.errors) + { + writefln(tags[DocPart.Error], "P", lx.fileName, error.loc, "P", xml_escape(error.getMsg)); + } + writefln(tags[DocPart.CompEnd]); + } + writef(tags[DocPart.SrcBegin]); + + Node[][Token*] beginNodes, endNodes; + + void populateAAs(Node[] nodes) + { + foreach (node; nodes) + { + auto begin = node.begin; + if (begin) + { + auto end = node.end; + assert(end); + beginNodes[begin] ~= node; + endNodes[end] ~= node; + } + if (node.children.length) + populateAAs(node.children); + } + } + populateAAs(root.children); + + char[] getTag(NodeCategory nc) + { + char[] tag; + switch (nc) + { + alias NodeCategory NC; + case NC.Declaration: tag = "d"; break; + case NC.Statement: tag = "s"; break; + case NC.Expression: tag = "e"; break; + case NC.Type: tag = "t"; break; + case NC.Other: tag = "o"; break; + default: + } + return tag; + } + + // Traverse linked list and print tokens. + while (token.type != TOK.EOF) + { + token = token.next; + + // Print whitespace between previous and current token. + if (end != token.start) + writef("%s", end[0 .. token.start - end]); + + Node[]* nodes = token in beginNodes; + + if (nodes) + { + foreach (node; *nodes) + writef(tags[DocPart.SyntaxBegin], getTag(node.category), getShortClassName(node)); + } + + printToken(token, tags); + + nodes = token in endNodes; + + if (nodes) + { + foreach_reverse (node; *nodes) + if (options & DocOption.HTML) + writef(tags[DocPart.SyntaxEnd]); + else + writef(tags[DocPart.SyntaxEnd], getTag(node.category)); + } + + end = token.end; + } + writef(tags[DocPart.SrcEnd], tags[DocPart.Tail]); +} + +void tokensToDoc(string fileName, DocOption options) +{ + auto tags = options & DocOption.HTML ? html_tags : xml_tags; + auto sourceText = loadFile(fileName); + auto lx = new Lexer(sourceText, fileName); + + auto token = lx.getTokens(); + char* end = lx.text.ptr; + + writefln(tags[DocPart.Head]); + + if (lx.errors.length) + { + writefln(tags[DocPart.CompBegin]); + foreach (error; lx.errors) + { + writefln(tags[DocPart.Error], "L", lx.fileName, error.loc, "L", xml_escape(error.getMsg)); + } + writefln(tags[DocPart.CompEnd]); + } + writef(tags[DocPart.SrcBegin]); + + // Traverse linked list and print tokens. + while (token.type != TOK.EOF) + { + token = token.next; + + // Print whitespace between previous and current token. + if (end != token.start) + writef("%s", end[0 .. token.start - end]); + printToken(token, tags); + end = token.end; + } + writef(\n, tags[DocPart.SrcEnd], \n, tags[DocPart.Tail]); +} + +void printToken(Token* token, string[] tags) +{ + alias DocPart DP; + string srcText = xml_escape(token.srcText); + + switch(token.type) + { + case TOK.Identifier: + writef(tags[DP.Identifier], srcText); + break; + case TOK.Comment: + string t; + switch (token.start[1]) + { + case '/': t = "l"; break; + case '*': t = "b"; break; + case '+': t = "n"; break; + default: + assert(0); + } + writef(tags[DP.Comment], t, srcText); + break; + case TOK.String: + writef(tags[DP.StringLiteral], srcText); + break; + case TOK.CharLiteral, TOK.WCharLiteral, TOK.DCharLiteral: + writef(tags[DP.CharLiteral], srcText); + break; + case TOK.Assign, TOK.Equal, + TOK.Less, TOK.Greater, + TOK.LShiftAssign, TOK.LShift, + TOK.RShiftAssign, TOK.RShift, + TOK.URShiftAssign, TOK.URShift, + TOK.OrAssign, TOK.OrBinary, + TOK.AndAssign, TOK.AndBinary, + TOK.PlusAssign, TOK.PlusPlus, TOK.Plus, + TOK.MinusAssign, TOK.MinusMinus, TOK.Minus, + TOK.DivAssign, TOK.Div, + TOK.MulAssign, TOK.Mul, + TOK.ModAssign, TOK.Mod, + TOK.XorAssign, TOK.Xor, + TOK.CatAssign, + TOK.Tilde, + TOK.Unordered, + TOK.UorE, + TOK.UorG, + TOK.UorGorE, + TOK.UorL, + TOK.UorLorE, + TOK.LorEorG: + writef(tags[DP.Operator], srcText); + break; + case TOK.LorG: + writef(tags[DP.LorG]); + break; + case TOK.LessEqual: + writef(tags[DP.LessEqual]); + break; + case TOK.GreaterEqual: + writef(tags[DP.GreaterEqual]); + break; + case TOK.AndLogical: + writef(tags[DP.AndLogical]); + break; + case TOK.OrLogical: + writef(tags[DP.OrLogical]); + break; + case TOK.NotEqual: + writef(tags[DP.NotEqual]); + break; + case TOK.Not: + // Check if this is part of a template instantiation. + // TODO: comments aren't skipped. + if (token.prev.type == TOK.Identifier && token.next.type == TOK.LParen) + goto default; + writef(tags[DP.Not]); + break; + case TOK.Int32, TOK.Int64, TOK.Uint32, TOK.Uint64, + TOK.Float32, TOK.Float64, TOK.Float80, + TOK.Imaginary32, TOK.Imaginary64, TOK.Imaginary80: + writef(tags[DP.Number], srcText); + break; + case TOK.LParen, TOK.RParen, TOK.LBracket, + TOK.RBracket, TOK.LBrace, TOK.RBrace: + writef(tags[DP.Bracket], srcText); + break; + case TOK.Shebang: + writef(tags[DP.Shebang], srcText); + break; + case TOK.HashLine: + void printWS(char* start, char* end) + { + if (start != end) + writef(start[0 .. end - start]); + } + writef(tags[DP.HLineBegin]); + auto num = token.line_num; + // Print whitespace between #line and number + auto ptr = token.start + "#line".length; + printWS(ptr, num.start); + printToken(num, tags); + if (token.line_filespec) + { + auto filespec = token.line_filespec; + // Print whitespace between number and filespec + printWS(num.end, filespec.start); + writef(tags[DP.Filespec], xml_escape(filespec.srcText)); + + ptr = filespec.end; + } + else + ptr = num.end; + // Print remaining whitespace + printWS(ptr, token.end); + writef(tags[DP.HLineEnd]); + break; + default: + if (token.isKeyword()) + writef(tags[DP.Keyword], srcText); + else if (token.isSpecialToken) + writef(tags[DP.SpecialToken], srcText); + else + writef("%s", srcText); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/src/cmd/Statistics.d Thu Aug 30 12:02:04 2007 +0000 @@ -0,0 +1,78 @@ +/++ + Author: Aziz Köksal + License: GPL3 ++/ +module cmd.Statistics; +import dil.Token; +import dil.File; +import dil.Lexer; +import std.stdio; + +struct Statistics +{ + uint whitespaceCount; + uint wsTokenCount; + uint keywordCount; + uint identCount; + uint numberCount; + uint commentCount; +} + +void statistics(string fileName) +{ + auto sourceText = loadFile(fileName); + auto lx = new Lexer(sourceText, fileName); + + auto token = lx.getTokens(); + char* end = lx.text.ptr; + + Statistics stats; + // Traverse linked list. + while (token.type != TOK.EOF) + { + token = token.next; + + // Count whitespace characters + if (end != token.start) + { + stats.whitespaceCount += token.start - end; + } + + switch (token.type) + { + case TOK.Identifier: + stats.identCount++; + break; + case TOK.Comment: + stats.commentCount++; + break; + case TOK.Int32, TOK.Int64, TOK.Uint32, TOK.Uint64, + TOK.Float32, TOK.Float64, TOK.Float80, + TOK.Imaginary32, TOK.Imaginary64, TOK.Imaginary80: + stats.numberCount++; + break; + default: + if (token.isKeyword) + stats.keywordCount++; + } + + if (token.isWhitespace) + stats.wsTokenCount++; + + end = token.end; + } + writefln("Whitespace character count: %s\n" + "Whitespace token count: %s\n" + "Keyword count: %s\n" + "Identifier count: %s\n" + "Number count: %s\n" + "Comment count: %s\n" + "Lines of code: %s", + stats.whitespaceCount, + stats.wsTokenCount, + stats.keywordCount, + stats.identCount, + stats.numberCount, + stats.commentCount, + lx.loc); +}
--- a/trunk/src/main.d Thu Aug 30 10:47:03 2007 +0000 +++ b/trunk/src/main.d Thu Aug 30 12:02:04 2007 +0000 @@ -11,6 +11,8 @@ import dil.Settings; import dil.Declarations, dil.Expressions, dil.SyntaxTree; import dil.File; +import cmd.Generate; +import cmd.Statistics; void main(char[][] args) { @@ -46,6 +48,9 @@ else tokensToDoc(fileName, options); break; + case "stats", "statistics": + statistics(args[2]); + break; case "parse": if (args.length == 3) parse(args[2]); @@ -62,7 +67,8 @@ const char[] COMMANDS = " generate (gen)\n" - " help (?)\n"; + " help (?)\n" + " statistics (stats)\n"; char[] helpMain() { @@ -83,14 +89,6 @@ writefln(msg); } -enum DocOption -{ - Tokens, - Syntax = 1<<1, - HTML = 1<<2, - XML = 1<<3 -} - void parse(string fileName) { auto sourceText = loadFile(fileName); @@ -113,482 +111,3 @@ writefln(`%s(%d)P: %s`, parser.lx.fileName, error.loc, error.getMsg); } } - -char[] xml_escape(char[] text) -{ - char[] result; - foreach(c; text) - switch(c) - { - case '<': result ~= "<"; break; - case '>': result ~= ">"; break; - case '&': result ~= "&"; break; - default: result ~= c; - } - return result; -} - -char[] getShortClassName(Node n) -{ - static char[][] name_table; - if (name_table is null) - name_table = new char[][NodeKind.max+1]; - char[] name = name_table[n.kind]; - if (name !is null) - return name; - - alias std.string.find find; - name = n.classinfo.name; - name = name[find(name, ".")+1 .. $]; // Remove package name - name = name[find(name, ".")+1 .. $]; // Remove module name - char[] remove; - switch (n.category) - { - alias NodeCategory NC; - case NC.Declaration: remove = "Declaration"; break; - case NC.Statement: - if (n.kind == NodeKind.Statements) - return name; - remove = "Statement"; - break; - case NC.Expression: remove = "Expression"; break; - case NC.Type: remove = "Type"; break; - case NC.Other: return name; - default: - } - // Remove common suffix. - auto idx = find(name, remove); - if (idx != -1) - name = name[0 .. idx]; - // Store the name. - name_table[n.kind] = name; - return name; -} - -enum DocPart -{ - Head, - CompBegin, - CompEnd, - Error, - SyntaxBegin, - SyntaxEnd, - SrcBegin, - SrcEnd, - Tail, - // Tokens: - Identifier, - Comment, - StringLiteral, - CharLiteral, - Operator, - LorG, - LessEqual, - GreaterEqual, - AndLogical, - OrLogical, - NotEqual, - Not, - Number, - Bracket, - SpecialToken, - Shebang, - Keyword, - HLineBegin, - HLineEnd, - Filespec, -} - -auto html_tags = [ - // Head - `<html>`\n - `<head>`\n - `<meta http-equiv="Content-Type" content="text/html; charset=utf-8">`\n - `<link href="dil_html.css" rel="stylesheet" type="text/css">`\n - `</head>`\n - `<body>`[], - // CompBegin - `<div class="compilerinfo">`, - // CompEnd - `</div>`, - // Error - `<p class="error %s">%s(%d)%s: %s</p>`, - // SyntaxBegin - `<span class="%s %s">`, - // SyntaxEnd - `</span>`, - // SrcBegin - `<pre class="sourcecode">`, - // SrcEnd - `</pre>`, - // Tail - `</html>`, - // Identifier - `<span class="i">%s</span>`, - // Comment - `<span class="c%s">%s</span>`, - // StringLiteral - `<span class="sl">%s</span>`, - // CharLiteral - `<span class="cl">%s</span>`, - // Operator - `<span class="op">%s</span>`, - // LorG - `<span class="oplg"><></span>`, - // LessEqual - `<span class="ople"><=</span>`, - // GreaterEqual - `<span class="opge">>=</span>`, - // AndLogical - `<span class="opaa">&&</span>`, - // OrLogical - `<span class="opoo">||</span>`, - // NotEqual - `<span class="opne">!=</span>`, - // Not - `<span class="opn">!</span>`, - // Number - `<span class="n">%s</span>`, - // Bracket - `<span class="br">%s</span>`, - // SpecialToken - `<span class="st">%s</span>`, - // Shebang - `<span class="shebang">%s</span>`, - // Keyword - `<span class="k">%s</span>`, - // HLineBegin - `<span class="hl">#line`, - // HLineEnd - "</span>", - // Filespec - `<span class="fs">%s</span>`, -]; - -auto xml_tags = [ - // Head - `<?xml version="1.0"?>`\n - `<?xml-stylesheet href="dil_xml.css" type="text/css"?>`\n - `<root>`[], - // CompBegin - `<compilerinfo>`, - // CompEnd - `</compilerinfo>`, - // Error - `<error t="%s">%s(%d)%s: %s</error>`, - // SyntaxBegin - `<%s t="%s">`, - // SyntaxEnd - `</%s>`, - // SrcBegin - `<sourcecode>`, - // SrcEnd - `</sourcecode>`, - // Tail - `</root>`, - // Identifier - "<i>%s</i>", - // Comment - `<c t="%s">%s</c>`, - // StringLiteral - "<sl>%s</sl>", - // CharLiteral - "<cl>%s</cl>", - // Operator - "<op>%s</op>", - // LorG - `<op t="lg"><></op>`, - // LessEqual - `<op t="le"><=</op>`, - // GreaterEqual - `<op t="ge">>=</op>`, - // AndLogical - `<op t="aa">&&</op>`, - // OrLogical - `<op t="oo">||</op>`, - // NotEqual - `<op t="ne">!=</op>`, - // Not - `<op t="n">!</op>`, - // Number - "<n>%s</n>", - // Bracket - "<br>%s</br>", - // SpecialToken - "<st>%s</st>", - // Shebang - "<shebang>%s</shebang>", - // Keyword - "<k>%s</k>", - // HLineBegin - "<hl>#line", - // HLineEnd - "</hl>", - // Filespec - "<fs>%s</fs>", -]; - -static assert(html_tags.length == DocPart.max+1); -static assert(xml_tags.length == DocPart.max+1); - -void syntaxToDoc(string fileName, DocOption options) -{ - auto tags = options & DocOption.HTML ? html_tags : xml_tags; - auto sourceText = loadFile(fileName); - auto parser = new Parser(sourceText, fileName); - parser.start(); - auto root = parser.parseModule(); - auto lx = parser.lx; - - auto token = lx.head; - char* end = lx.text.ptr; - - writefln(tags[DocPart.Head]); - // Output error messages. - if (lx.errors.length || parser.errors.length) - { - writefln(tags[DocPart.CompBegin]); - foreach (error; lx.errors) - { - writefln(tags[DocPart.Error], "L", lx.fileName, error.loc, "L", xml_escape(error.getMsg)); - } - foreach (error; parser.errors) - { - writefln(tags[DocPart.Error], "P", lx.fileName, error.loc, "P", xml_escape(error.getMsg)); - } - writefln(tags[DocPart.CompEnd]); - } - writef(tags[DocPart.SrcBegin]); - - Node[][Token*] beginNodes, endNodes; - - void populateAAs(Node[] nodes) - { - foreach (node; nodes) - { - auto begin = node.begin; - if (begin) - { - auto end = node.end; - assert(end); - beginNodes[begin] ~= node; - endNodes[end] ~= node; - } - if (node.children.length) - populateAAs(node.children); - } - } - populateAAs(root.children); - - char[] getTag(NodeCategory nc) - { - char[] tag; - switch (nc) - { - alias NodeCategory NC; - case NC.Declaration: tag = "d"; break; - case NC.Statement: tag = "s"; break; - case NC.Expression: tag = "e"; break; - case NC.Type: tag = "t"; break; - case NC.Other: tag = "o"; break; - default: - } - return tag; - } - - // Traverse linked list and print tokens. - while (token.type != TOK.EOF) - { - token = token.next; - - // Print whitespace between previous and current token. - if (end != token.start) - writef("%s", end[0 .. token.start - end]); - - Node[]* nodes = token in beginNodes; - - if (nodes) - { - foreach (node; *nodes) - writef(tags[DocPart.SyntaxBegin], getTag(node.category), getShortClassName(node)); - } - - printToken(token, tags); - - nodes = token in endNodes; - - if (nodes) - { - foreach_reverse (node; *nodes) - if (options & DocOption.HTML) - writef(tags[DocPart.SyntaxEnd]); - else - writef(tags[DocPart.SyntaxEnd], getTag(node.category)); - } - - end = token.end; - } - writef(tags[DocPart.SrcEnd], tags[DocPart.Tail]); -} - -void tokensToDoc(string fileName, DocOption options) -{ - auto tags = options & DocOption.HTML ? html_tags : xml_tags; - auto sourceText = loadFile(fileName); - auto lx = new Lexer(sourceText, fileName); - - auto token = lx.getTokens(); - char* end = lx.text.ptr; - - writefln(tags[DocPart.Head]); - - if (lx.errors.length) - { - writefln(tags[DocPart.CompBegin]); - foreach (error; lx.errors) - { - writefln(tags[DocPart.Error], "L", lx.fileName, error.loc, "L", xml_escape(error.getMsg)); - } - writefln(tags[DocPart.CompEnd]); - } - writef(tags[DocPart.SrcBegin]); - - // Traverse linked list and print tokens. - while (token.type != TOK.EOF) - { - token = token.next; - - // Print whitespace between previous and current token. - if (end != token.start) - writef("%s", end[0 .. token.start - end]); - printToken(token, tags); - end = token.end; - } - writef(\n, tags[DocPart.SrcEnd], \n, tags[DocPart.Tail]); -} - -void printToken(Token* token, string[] tags) -{ - alias DocPart DP; - string srcText = xml_escape(token.srcText); - - switch(token.type) - { - case TOK.Identifier: - writef(tags[DP.Identifier], srcText); - break; - case TOK.Comment: - string t; - switch (token.start[1]) - { - case '/': t = "l"; break; - case '*': t = "b"; break; - case '+': t = "n"; break; - default: - assert(0); - } - writef(tags[DP.Comment], t, srcText); - break; - case TOK.String: - writef(tags[DP.StringLiteral], srcText); - break; - case TOK.CharLiteral, TOK.WCharLiteral, TOK.DCharLiteral: - writef(tags[DP.CharLiteral], srcText); - break; - case TOK.Assign, TOK.Equal, - TOK.Less, TOK.Greater, - TOK.LShiftAssign, TOK.LShift, - TOK.RShiftAssign, TOK.RShift, - TOK.URShiftAssign, TOK.URShift, - TOK.OrAssign, TOK.OrBinary, - TOK.AndAssign, TOK.AndBinary, - TOK.PlusAssign, TOK.PlusPlus, TOK.Plus, - TOK.MinusAssign, TOK.MinusMinus, TOK.Minus, - TOK.DivAssign, TOK.Div, - TOK.MulAssign, TOK.Mul, - TOK.ModAssign, TOK.Mod, - TOK.XorAssign, TOK.Xor, - TOK.CatAssign, - TOK.Tilde, - TOK.Unordered, - TOK.UorE, - TOK.UorG, - TOK.UorGorE, - TOK.UorL, - TOK.UorLorE, - TOK.LorEorG: - writef(tags[DP.Operator], srcText); - break; - case TOK.LorG: - writef(tags[DP.LorG]); - break; - case TOK.LessEqual: - writef(tags[DP.LessEqual]); - break; - case TOK.GreaterEqual: - writef(tags[DP.GreaterEqual]); - break; - case TOK.AndLogical: - writef(tags[DP.AndLogical]); - break; - case TOK.OrLogical: - writef(tags[DP.OrLogical]); - break; - case TOK.NotEqual: - writef(tags[DP.NotEqual]); - break; - case TOK.Not: - // Check if this is part of a template instantiation. - // TODO: comments aren't skipped. - if (token.prev.type == TOK.Identifier && token.next.type == TOK.LParen) - goto default; - writef(tags[DP.Not]); - break; - case TOK.Int32, TOK.Int64, TOK.Uint32, TOK.Uint64, - TOK.Float32, TOK.Float64, TOK.Float80, - TOK.Imaginary32, TOK.Imaginary64, TOK.Imaginary80: - writef(tags[DP.Number], srcText); - break; - case TOK.LParen, TOK.RParen, TOK.LBracket, - TOK.RBracket, TOK.LBrace, TOK.RBrace: - writef(tags[DP.Bracket], srcText); - break; - case TOK.Shebang: - writef(tags[DP.Shebang], srcText); - break; - case TOK.HashLine: - void printWS(char* start, char* end) - { - if (start != end) - writef(start[0 .. end - start]); - } - writef(tags[DP.HLineBegin]); - auto num = token.line_num; - // Print whitespace between #line and number - auto ptr = token.start + "#line".length; - printWS(ptr, num.start); - printToken(num, tags); - if (token.line_filespec) - { - auto filespec = token.line_filespec; - // Print whitespace between number and filespec - printWS(num.end, filespec.start); - writef(tags[DP.Filespec], xml_escape(filespec.srcText)); - - ptr = filespec.end; - } - else - ptr = num.end; - // Print remaining whitespace - printWS(ptr, token.end); - writef(tags[DP.HLineEnd]); - break; - default: - if (token.isKeyword()) - writef(tags[DP.Keyword], srcText); - else if (token.isSpecialToken) - writef(tags[DP.SpecialToken], srcText); - else - writef("%s", srcText); - } -}