changeset 322:ed4ef0173793

- Moved out large TOK switch case to function printToken(). - Renamed tokensToXML() to tokensToDoc() and added parameter 'options'. - Not using string literals anymore to print XML tags. Created an enum and two tables, for XML and HTML, with entries for every tag that needs to be printed. - Added function getShortClassName() which returns the short class name of a class that inherits from Node. - Added new styles to and changed some in format.css.
author aziz
date Mon, 20 Aug 2007 19:59:04 +0000
parents ae7f48182cb1
children 6259fb93e3dd
files trunk/src/format.css trunk/src/main.d
diffstat 2 files changed, 443 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/format.css	Mon Aug 20 19:47:03 2007 +0000
+++ b/trunk/src/format.css	Mon Aug 20 19:59:04 2007 +0000
@@ -1,5 +1,5 @@
 @charset "utf-8";
-compilerinfo, sourcetext {
+compilerinfo, sourcecode {
   display: block;
   white-space: pre;
   font-family: Monospace;
@@ -17,9 +17,9 @@
 /* Keyword */
 k { color: darkblue; font-weight: bold; }
 /* Line and block comments */
-c[c=l], c[c=b] { color: green; }
+c[t=l], c[t=b] { color: green; }
 /* Nested comments */
-c[c=n] { color: darkgreen; }
+c[t=n] { color: darkgreen; }
 /* Identifier */
 i { color: black; }
 /* String literal */
@@ -35,10 +35,22 @@
 /* When the first line starts with #! it's a "shebang" */
 shebang { color: gray; }
 /* Particular operators */
-op[c=aa] { content: "and"; } /*&& ∧*/
-op[c=oo] { content: "or"; } /*|| ∨*/
-op[c=n] { content: "¬"; } /*!*/
-op[c=ne] { content: "≠"; } /*!=*/
-op[c=le] { content: "≤"; } /*<=*/
-op[c=ge] { content: "≥"; } /*>=*/
-op[c=lg] { content: "≶"; } /*<>*/
+op[t=aa] { content: "and"; } /*&& ∧*/
+op[t=oo] { content: "or"; } /*|| ∨*/
+op[t=n] { content: "¬"; } /*!*/
+op[t=ne] { content: "≠"; } /*!=*/
+op[t=le] { content: "≤"; } /*<=*/
+op[t=ge] { content: "≥"; } /*>=*/
+op[t=lg] { content: "≶"; } /*<>*/
+
+/*
+d = Declaration
+s = Statement
+e = Expression
+t = Type
+o = Other
+*/
+/* d { background-color: #FFDDDD; } */
+/* e { background-color: #DDDDFF;} */
+d[t=Module] i, d[t=Import] i { color: blue; }
+t i { color: #119; }
\ No newline at end of file
--- a/trunk/src/main.d	Mon Aug 20 19:47:03 2007 +0000
+++ b/trunk/src/main.d	Mon Aug 20 19:59:04 2007 +0000
@@ -23,8 +23,30 @@
   switch (command)
   {
   case "hl", "highlight":
-    if (args.length == 3)
-      tokensToXML(args[2]);
+    char[] fileName;
+    DocOption options;
+    foreach (arg; args[2..$])
+    {
+      switch (arg)
+      {
+      case "--tokens":
+        options |= DocOption.Tokens; break;
+      case "--syntax":
+        options |= DocOption.Syntax; break;
+      case "--xml":
+        options |= DocOption.XML; break;
+      case "--html":
+        options |= DocOption.HTML; break;
+      default:
+        fileName = arg;
+      }
+    }
+    if (!(options & (DocOption.XML | DocOption.HTML)))
+      options |= DocOption.XML; // Default to XML.
+    if (options & DocOption.Syntax)
+      syntaxToDoc(fileName, options);
+    else
+      tokensToDoc(fileName, options);
     break;
   case "parse":
     if (args.length == 3)
@@ -34,6 +56,14 @@
   }
 }
 
+enum DocOption
+{
+  Tokens,
+  Syntax = 1<<1,
+  HTML = 1<<2,
+  XML = 1<<3
+}
+
 void parse(string fileName)
 {
   auto sourceText = cast(char[]) std.file.read(fileName);
@@ -71,27 +101,305 @@
   return result;
 }
 
-void tokensToXML(string fileName)
+char[] getShortClassName(Node n)
+{
+  alias std.string.find find;
+  char[] name = n.classinfo.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];
+  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,
+}
+
+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">&lt;&gt;</span>`,
+  // LessEqual
+  `<span class="ople">&lt;=</span>`,
+  // GreaterEqual
+  `<span class="opge">&gt;=</span>`,
+  // AndLogical
+  `<span class="opaa">&amp;&amp;</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>`,
+];
+
+auto xml_tags = [
+  // Head
+  `<?xml version="1.0"?>`\n
+  `<?xml-stylesheet href="format.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">&lt;&gt;</op>`,
+  // LessEqual
+  `<op t="le">&lt;=</op>`,
+  // GreaterEqual
+  `<op t="ge">&gt;=</op>`,
+  // AndLogical
+  `<op t="aa">&amp;&amp;</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>",
+];
+
+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 = cast(char[]) std.file.read(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 = cast(char[]) std.file.read(fileName);
   auto lx = new Lexer(sourceText, fileName);
 
   auto token = lx.getTokens();
   char* end = lx.text.ptr;
 
-  writefln(`<?xml version="1.0"?>`\n
-         `<?xml-stylesheet href="format.css" type="text/css"?>`\n
-         `<root>`);
+  writefln(tags[DocPart.Head]);
+
   if (lx.errors.length)
   {
-    writefln("<compilerinfo>");
+    writefln(tags[DocPart.CompBegin]);
     foreach (error; lx.errors)
     {
-      writefln(`<error t="%s">%s(%d): %s</error>`, "l", lx.fileName, error.loc, xml_escape(error.getMsg));
+      writefln(tags[DocPart.Error], "L", lx.fileName, error.loc, "L", xml_escape(error.getMsg));
     }
-    writefln("</compilerinfo>");
+    writefln(tags[DocPart.CompEnd]);
   }
-  writef(`<sourcetext>`);
+  writef(tags[DocPart.SrcBegin]);
 
   // Traverse linked list and print tokens.
   while (token.type != TOK.EOF)
@@ -101,103 +409,108 @@
     // Print whitespace between previous and current token.
     if (end != token.start)
       writef("%s", xml_escape(end[0 .. token.start - end]));
-
-    string srcText = xml_escape(token.srcText);
-
-    switch(token.type)
-    {
-    case TOK.Identifier:
-      writef("<i>%s</i>", srcText);
-      break;
-    case TOK.Comment:
-      string c;
-      switch (token.start[1])
-      {
-      case '/': c = "l"; break;
-      case '*': c = "b"; break;
-      case '+': c = "n"; break;
-      default:
-        assert(0);
-      }
-      writef(`<c c="%s">%s</c>`, c, srcText);
-      break;
-    case TOK.String:
-      writef("<sl>%s</sl>", srcText);
-      break;
-    case TOK.CharLiteral, TOK.WCharLiteral, TOK.DCharLiteral:
-      writef("<cl>%s</cl>", 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("<op>%s</op>", srcText);
-      break;
-    case TOK.LorG:
-      writef(`<op c="lg">&lt;&gt;</op>`);
-      break;
-    case TOK.LessEqual:
-      writef(`<op c="le">&lt;=</op>`);
-      break;
-    case TOK.GreaterEqual:
-      writef(`<op c="ge">&gt;=</op>`);
-      break;
-    case TOK.AndLogical:
-      writef(`<op c="aa">&amp;&amp;</op>`);
-      break;
-    case TOK.OrLogical:
-      writef(`<op c="oo">||</op>`);
-      break;
-    case TOK.NotEqual:
-      writef(`<op c="ne">!=</op>`);
-      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(`<op c="n">!</op>`);
-      break;
-    case TOK.Int32, TOK.Int64, TOK.Uint32, TOK.Uint64,
-         TOK.Float32, TOK.Float64, TOK.Float80,
-         TOK.Imaginary32, TOK.Imaginary64, TOK.Imaginary80:
-      writef("<n>%s</n>", srcText);
-      break;
-    case TOK.LParen, TOK.RParen, TOK.LBracket,
-         TOK.RBracket, TOK.LBrace, TOK.RBrace:
-      writef("<br>%s</br>", srcText);
-      break;
-    case TOK.Special:
-      writef("<st>%s</st>", srcText);
-      break;
-    case TOK.Shebang:
-      writef("<shebang>%s</shebang>", srcText);
-      break;
-    default:
-      if (token.isKeyword())
-        writef("<k>%s</k>", srcText);
-      else
-        writef("%s", srcText);
-    }
+    printToken(token, tags);
     end = token.end;
   }
-  writef("\n</sourcetext>\n</root>");
-}
\ No newline at end of file
+  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.Special:
+    writef(tags[DP.SpecialToken], srcText);
+    break;
+  case TOK.Shebang:
+    writef(tags[DP.Shebang], srcText);
+    break;
+  default:
+    if (token.isKeyword())
+      writef(tags[DP.Keyword], srcText);
+    else
+      writef("%s", srcText);
+  }
+}