changeset 401:fcdf7ac5ad27

Improved statistics generation. Now multiple files can be passed to the stats/statistics command. Whitespace characters are counted correctly as well.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sat, 22 Sep 2007 19:49:54 +0200
parents a0fa0dcfa50a
children 22d65b2bef4f
files trunk/src/cmd/Statistics.d trunk/src/main.d
diffstat 2 files changed, 108 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/cmd/Statistics.d	Sat Sep 22 18:24:54 2007 +0200
+++ b/trunk/src/cmd/Statistics.d	Sat Sep 22 19:49:54 2007 +0200
@@ -16,27 +16,91 @@
   uint identCount;
   uint numberCount;
   uint commentCount;
+  uint linesOfCode;
+
+  void opAddAssign(Statistics s)
+  {
+    this.whitespaceCount += s.whitespaceCount;
+    this.wsTokenCount    += s.wsTokenCount;
+    this.keywordCount    += s.keywordCount;
+    this.identCount      += s.identCount;
+    this.numberCount     += s.numberCount;
+    this.commentCount    += s.commentCount;
+    this.linesOfCode     += s.linesOfCode;
+  }
 }
 
-void execute(string fileName)
+void execute(string[] filePaths)
 {
-  auto sourceText = loadFile(fileName);
-  auto lx = new Lexer(sourceText, fileName);
+  Statistics[] stats;
+  foreach (filePath; filePaths)
+    stats ~= getStatistics(filePath);
+
+  Statistics total;
+
+  foreach (i, ref stat; stats)
+  {
+    total += stat;
+    Stdout.formatln(
+      "----\n"
+      "File: {0}\n"
+      "Whitespace character count: {1}\n"
+      "Whitespace token count: {2}\n"
+      "Keyword count: {3}\n"
+      "Identifier count: {4}\n"
+      "Number count: {5}\n"
+      "Comment count: {6}\n"
+      "Lines of code: {7}",
+      filePaths[i],
+      stat.whitespaceCount,
+      stat.wsTokenCount,
+      stat.keywordCount,
+      stat.identCount,
+      stat.numberCount,
+      stat.commentCount,
+      stat.linesOfCode
+    );
+  }
+
+  if (filePaths.length > 1)
+    Stdout.formatln(
+      "--------------------------------------------------------------------------------\n"
+      "Total:\n"
+      "Whitespace character count: {0}\n"
+      "Whitespace token count: {1}\n"
+      "Keyword count: {2}\n"
+      "Identifier count: {3}\n"
+      "Number count: {4}\n"
+      "Comment count: {5}\n"
+      "Lines of code: {6}",
+      total.whitespaceCount,
+      total.wsTokenCount,
+      total.keywordCount,
+      total.identCount,
+      total.numberCount,
+      total.commentCount,
+      total.linesOfCode
+    );
+}
+
+Statistics getStatistics(string filePath)
+{
+  auto sourceText = loadFile(filePath);
+  auto lx = new Lexer(sourceText, filePath);
 
   auto token = lx.getTokens();
 
   Statistics stats;
+
+  stats.linesOfCode = lx.loc;
   // Traverse linked list.
   while (token.type != TOK.EOF)
   {
     token = token.next;
 
     // Count whitespace characters
-    if (token.ws)
-    {
-      // TODO: naive method doesn't account for \r\n, LS and PS.
-      stats.whitespaceCount += token.start - token.ws;
-    }
+    if (token.ws !is null)
+      stats.whitespaceCount += countWhitespaceCharacters(token.ws, token.start);
 
     switch (token.type)
     {
@@ -59,19 +123,39 @@
     if (token.isWhitespace)
       stats.wsTokenCount++;
   }
-  Stdout.formatln(
-    "Whitespace character count: {0}\n"
-    "Whitespace token count: {1}\n"
-    "Keyword count: {2}\n"
-    "Identifier count: {3}\n"
-    "Number count: {4}\n"
-    "Comment count: {5}\n"
-    "Lines of code: {6}",
-    stats.whitespaceCount,
-    stats.wsTokenCount,
-    stats.keywordCount,
-    stats.identCount,
-    stats.numberCount,
-    stats.commentCount,
-    lx.loc);
+  return stats;
 }
+
+/// Counts newlines, \t, \v, \f and ' ' as whitespace characters.
+uint countWhitespaceCharacters(char* p, char* end)
+{
+  uint count;
+Loop:
+  while (1)
+  {
+    switch (*p)
+    {
+    case '\r':
+      if (p[1] == '\n')
+        ++p;
+    case '\n':
+      ++p;
+      ++count;
+      break;
+    case LS[0]:
+      if (p[1] == LS[1] && (p[2] == LS[2] || p[2] == PS[2]))
+      {
+        p += 3;
+        ++count;
+        break;
+      }
+    default:
+      if (!dil.Lexer.isspace(*p))
+        break Loop; // Exit loop.
+      ++p;
+      ++count;
+    }
+  }
+  assert(p is end);
+  return count;
+}
--- a/trunk/src/main.d	Sat Sep 22 18:24:54 2007 +0200
+++ b/trunk/src/main.d	Sat Sep 22 19:49:54 2007 +0200
@@ -88,7 +88,7 @@
     cmd.ImportGraph.execute(filePath, includePaths, regexps, levels, options);
     break;
   case "stats", "statistics":
-    cmd.Statistics.execute(args[2]);
+    cmd.Statistics.execute(args[2..$]);
     break;
   case "parse":
     if (args.length == 3)