changeset 744:7173ece1b696

Wrapped some macro functions inside struct MacroExpander. Warning messages from the macro expansion pass are collected now. Tidied up predefined.ddoc a bit, and added some macros. Added two messages to struct MSG. Added another opCatAssign to class InfoManager.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sat, 09 Feb 2008 22:54:31 +0100
parents 764f660e3909
children 7299159c3a19
files trunk/src/cmd/DDoc.d trunk/src/dil/Information.d trunk/src/dil/Location.d trunk/src/dil/Messages.d trunk/src/dil/doc/Macro.d trunk/src/main.d trunk/src/predefined.ddoc
diffstat 7 files changed, 220 insertions(+), 166 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/cmd/DDoc.d	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/cmd/DDoc.d	Sat Feb 09 22:54:31 2008 +0100
@@ -61,13 +61,20 @@
     // Generate documentation.
     auto dest = new FilePath(destDir);
     dest.append(mod.getFQN() ~ ".html");
+    InfoManager infoMan2; // Collects warnings from the macro expander.
     if (verbose)
+    {
       Stdout.formatln("{} > {}", mod.filePath, dest);
-    writeDocFile(dest.toString(), mod, mtable, incUndoc);
+      infoMan2 = new InfoManager();
+    }
+    writeDocFile(dest.toString(), mod, mtable, incUndoc, infoMan2);
+    if (infoMan2)
+      infoMan ~= infoMan2.info;
   }
 }
 
-void writeDocFile(string dest, Module mod, MacroTable mtable, bool incUndoc)
+void writeDocFile(string dest, Module mod, MacroTable mtable, bool incUndoc,
+                  InfoManager infoMan)
 {
   // Create a macro environment for this module.
   mtable = new MacroTable(mtable);
@@ -87,7 +94,7 @@
   // Set BODY macro to the text produced by the DDocEmitter.
   mtable.insert("BODY", doc.text);
   // Do the macro expansion pass.
-  auto fileText = expandMacros(mtable, "$(DDOC)");
+  auto fileText = MacroExpander.expand(mtable, "$(DDOC)", mod.filePath, infoMan);
   // Finally write the file out to the harddisk.
   auto file = new File(dest);
   file.write(fileText);
--- a/trunk/src/dil/Information.d	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/dil/Information.d	Sat Feb 09 22:54:31 2008 +0100
@@ -22,6 +22,11 @@
   {
     this.info ~= info;
   }
+
+  void opCatAssign(Information[] info)
+  {
+    this.info ~= info;
+  }
 }
 
 class Problem : Information
--- a/trunk/src/dil/Location.d	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/dil/Location.d	Sat Feb 09 22:54:31 2008 +0100
@@ -11,7 +11,7 @@
 {
   char[] filePath;
   size_t lineNum;
-  char* lineBegin, to; // Used to calculate column.
+  char* lineBegin, to; /// Used to calculate column.
 
   this(char[] filePath, size_t lineNum)
   {
--- a/trunk/src/dil/Messages.d	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/dil/Messages.d	Sat Feb 09 22:54:31 2008 +0100
@@ -105,6 +105,9 @@
   auto InvalidUTF32Character = "invalid UTF-32 character '\\U{:X8}'.";
   auto UTF16FileMustBeDivisibleBy2 = "the byte length of a UTF-16 source file must be divisible by 2.";
   auto UTF32FileMustBeDivisibleBy4 = "the byte length of a UTF-32 source file must be divisible by 4.";
+  // DDoc macros:
+  auto UndefinedDDocMacro = "DDoc macro '{}' is undefined";
+  auto UnterminatedDDocMacro = "DDoc macro '{}' has no closing ')'";
   // Parser messages:
   auto ModuleDeclarationNotFirst = "a module declaration is only allowed as the first declaration in a file";
   auto StringPostfixMismatch = "string literal has mistmatching postfix character";
--- a/trunk/src/dil/doc/Macro.d	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/dil/doc/Macro.d	Sat Feb 09 22:54:31 2008 +0100
@@ -7,6 +7,8 @@
 import dil.doc.Parser;
 import dil.lexer.Funcs;
 import dil.Unicode;
+import dil.Information;
+import dil.Messages;
 import common;
 
 class Macro
@@ -81,183 +83,213 @@
   }
 }
 
-/// Expands the macros from the table in text.
-char[] expandMacros(MacroTable table, char[] text, char[][] args = null)
+struct MacroExpander
 {
-  char[] result;
-  char* p = text.ptr;
-  char* textEnd = p + text.length;
-  char* macroEnd = p;
-  while (p+3 < textEnd) // minimum 4 chars: $(x)
+  MacroTable mtable; /// Used to look up macros.
+  InfoManager infoMan; /// Collects warning messages.
+  char[] filePath; /// Used in warning messages.
+
+  static char[] expand(MacroTable mtable, char[] text,
+                       char[] filePath,
+                       InfoManager infoMan = null)
   {
-    if (*p == '$' && p[1] == '(')
+    MacroExpander me;
+    me.mtable = mtable;
+    me.infoMan = infoMan;
+    me.filePath = filePath;
+    return me.expandMacros(text);
+  }
+
+  void warning(char[] msg, char[] macroName)
+  {
+    msg = Format(msg, macroName);
+    if (infoMan)
+      infoMan ~= new Warning(new Location(filePath, 0), msg);
+  }
+
+  /// Expands the macros from the table in text.
+  char[] expandMacros(char[] text, char[][] args = null)
+  {
+    char[] result;
+    char* p = text.ptr;
+    char* textEnd = p + text.length;
+    char* macroEnd = p;
+    while (p+3 < textEnd) // minimum 4 chars: $(x)
     {
-      // Copy string between macros.
-      if (macroEnd !is p)
-        result ~= makeString(macroEnd, p);
-      p += 2;
-      auto idBegin = p;
-      if (isidbeg(*p) || isUnicodeAlpha(p, textEnd)) // IdStart
+      if (*p == '$' && p[1] == '(')
       {
-        do // IdChar*
+        // Copy string between macros.
+        if (macroEnd !is p)
+          result ~= makeString(macroEnd, p);
+        p += 2;
+        auto idBegin = p;
+        if (isidbeg(*p) || isUnicodeAlpha(p, textEnd)) // IdStart
+        {
+          do // IdChar*
+            p++;
+          while (p < textEnd && (isident(*p) || isUnicodeAlpha(p, textEnd)))
+          // Create macro name.
+          auto macroName = makeString(idBegin, p);
+          // Get arguments.
+          auto macroArgs = scanArguments(p, textEnd);
+          // TODO: still expand macro if no closing bracket was found?
+          if (p == textEnd)
+          {
+            warning(MSG.UnterminatedDDocMacro, macroName);
+            break; // No closing bracket found.
+          }
+          assert(*p == ')');
           p++;
-        while (p < textEnd && (isident(*p) || isUnicodeAlpha(p, textEnd)))
-        // Create macro name.
-        auto macroName = makeString(idBegin, p);
-        // Get arguments.
-        auto macroArgs = scanArguments(p, textEnd);
-        // TODO: still expand macro if no closing bracket was found?
-        if (p == textEnd)
-          break; // No closing bracket found.
-        assert(*p == ')');
-        p++;
-        macroEnd = p;
+          macroEnd = p;
 
-        auto macro_ = table.search(macroName);
-        if (macro_)
-        { // Ignore recursive macro if:
-          if (macro_.callLevel != 0 &&
-               (macroArgs.length == 0 || // Macro has no arguments.
-                args.length && args[0] == macroArgs[0]) // arg0 == macroArg0.
-             )
-            continue;
-          macro_.callLevel++;
-          auto expandedText = expandArguments(macro_.text, macroArgs);
-          result ~= expandMacros(table, expandedText, macroArgs);
-          macro_.callLevel--;
+          auto macro_ = mtable.search(macroName);
+          if (macro_)
+          { // Ignore recursive macro if:
+            if (macro_.callLevel != 0 &&
+                (macroArgs.length == 0 || // Macro has no arguments.
+                  args.length && args[0] == macroArgs[0]) // arg0 == macroArg0.
+              )
+              continue;
+            macro_.callLevel++;
+            auto expandedText = expandArguments(macro_.text, macroArgs);
+            result ~= expandMacros(expandedText, macroArgs);
+            macro_.callLevel--;
+          }
+          else
+            warning(MSG.UndefinedDDocMacro, macroName);
+          continue;
         }
-        continue;
       }
+      p++;
     }
-    p++;
+    if (macroEnd < textEnd)
+      result ~= makeString(macroEnd, textEnd);
+    return result;
   }
-  if (macroEnd < textEnd)
-    result ~= makeString(macroEnd, textEnd);
-  return result;
-}
 
-/// Scans until the closing ')' is found.
-/// Returns: [$0, $1, $2 ...].
-char[][] scanArguments(ref char* p, char* textEnd)
-out(args) { assert(args.length != 1); }
-body
-{
-  // D specs: "The argument text can contain nested parentheses,
-  //           "" or '' strings, comments, or tags."
-  uint level = 1; // Nesting level of the parentheses.
-  char[][] args;
+  /// Scans until the closing ')' is found.
+  /// Returns: ['$0', $1, $2 ...].
+  char[][] scanArguments(ref char* p, char* textEnd)
+  out(args) { assert(args.length != 1); }
+  body
+  {
+    // D specs: "The argument text can contain nested parentheses,
+    //           "" or '' strings, comments, or tags."
+    uint level = 1; // Nesting level of the parentheses.
+    char[][] args;
+
+    // Skip leading spaces.
+    while (p < textEnd && isspace(*p))
+      p++;
 
-  // Skip leading spaces.
-  while (p < textEnd && isspace(*p))
-    p++;
-
-  char* arg0Begin = p; // Whole argument list.
-  char* argBegin = p;
-Loop:
-  while (p < textEnd)
-  {
-    switch (*p)
+    char* arg0Begin = p; // Whole argument list.
+    char* argBegin = p;
+  Loop:
+    while (p < textEnd)
     {
-    case ',':
-      if (level != 1) // Ignore comma if inside ().
+      switch (*p)
+      {
+      case ',':
+        if (level != 1) // Ignore comma if inside ().
+          break;
+        // Add a new argument.
+        args ~= makeString(argBegin, p);
+        while (++p < textEnd && isspace(*p))
+        {}
+        argBegin = p;
+        continue;
+      case '(':
+        level++;
         break;
-      // Add a new argument.
-      args ~= makeString(argBegin, p);
-      while (++p < textEnd && isspace(*p))
-      {}
-      argBegin = p;
-      continue;
-    case '(':
-      level++;
-      break;
-    case ')':
-      if (--level == 0)
-        break Loop;
-      break;
-    case '"', '\'':
-      auto c = *p;
-      while (++p < textEnd && *p != c) // Scan to next " or '.
-      {}
-      assert(*p == c || p == textEnd);
-      if (p == textEnd)
-        break Loop;
-      break;
-    case '<':
-      if (p+3 < textEnd && p[1] == '!' && p[2] == '-' && p[3] == '-') // <!--
-      {
-        p += 3;
-        // Scan to closing "-->".
-        while (++p + 2 < textEnd)
-          if (*p == '-' && p[1] == '-' && p[2] == '>')
-          {
-            p += 3;
-            continue Loop;
-          }
-        p = textEnd; // p += 2;
-      } // <tag ...> or </tag>
-      else if (p+1 < textEnd && (isalpha(p[1]) || p[1] == '/'))
-        while (++p < textEnd && *p != '>') // Skip to closing '>'.
+      case ')':
+        if (--level == 0)
+          break Loop;
+        break;
+      case '"', '\'':
+        auto c = *p;
+        while (++p < textEnd && *p != c) // Scan to next " or '.
         {}
-      if (p == textEnd)
-        break Loop;
-      break;
-    default:
+        assert(*p == c || p == textEnd);
+        if (p == textEnd)
+          break Loop;
+        break;
+      case '<':
+        if (p+3 < textEnd && p[1] == '!' && p[2] == '-' && p[3] == '-') // <!--
+        {
+          p += 3;
+          // Scan to closing "-->".
+          while (++p + 2 < textEnd)
+            if (*p == '-' && p[1] == '-' && p[2] == '>')
+            {
+              p += 3;
+              continue Loop;
+            }
+          p = textEnd; // p += 2;
+        } // <tag ...> or </tag>
+        else if (p+1 < textEnd && (isalpha(p[1]) || p[1] == '/'))
+          while (++p < textEnd && *p != '>') // Skip to closing '>'.
+          {}
+        if (p == textEnd)
+          break Loop;
+        break;
+      default:
+      }
+      p++;
     }
-    p++;
+    assert(*p == ')' && level == 0 || p == textEnd);
+    if (arg0Begin is p)
+      return null;
+    // arg0 spans the whole argument list.
+    auto arg0 = makeString(arg0Begin, p);
+    // Add last argument.
+    args ~= makeString(argBegin, p);
+    return arg0 ~ args;
   }
-  assert(*p == ')' && level == 0 || p == textEnd);
-  if (arg0Begin is p)
-    return null;
-  // arg0 spans the whole argument list.
-  auto arg0 = makeString(arg0Begin, p);
-  // Add last argument.
-  args ~= makeString(argBegin, p);
-  return arg0 ~ args;
-}
 
-/// Expands "$+", "$0" - "$9" with args[n] in text.
-/// Params:
-///   text = the text to scan for argument placeholders.
-///   args = the first element, args[0], is the whole argument string and
-///          the following elements are slices into it.
-///          The array is empty if there are no arguments.
-char[] expandArguments(char[] text, char[][] args)
-in { assert(args.length != 1, "zero or more than 1 args expected"); }
-body
-{
-  char[] result;
-  char* p = text.ptr;
-  char* textEnd = p + text.length;
-  char* placeholderEnd = p;
-
-  while (p+1 < textEnd)
+  /// Expands "$+", "$0" - "$9" with args[n] in text.
+  /// Params:
+  ///   text = the text to scan for argument placeholders.
+  ///   args = the first element, args[0], is the whole argument string and
+  ///          the following elements are slices into it.
+  ///          The array is empty if there are no arguments.
+  char[] expandArguments(char[] text, char[][] args)
+  in { assert(args.length != 1, "zero or more than 1 args expected"); }
+  body
   {
-    if (*p == '$' && (p[1] == '+' || isdigit(p[1])))
+    char[] result;
+    char* p = text.ptr;
+    char* textEnd = p + text.length;
+    char* placeholderEnd = p;
+
+    while (p+1 < textEnd)
     {
-      // Copy string between argument placeholders.
-      if (placeholderEnd !is p)
-        result ~= makeString(placeholderEnd, p);
-      p++;
-      placeholderEnd = p + 1; // Set new argument end.
+      if (*p == '$' && (p[1] == '+' || isdigit(p[1])))
+      {
+        // Copy string between argument placeholders.
+        if (placeholderEnd !is p)
+          result ~= makeString(placeholderEnd, p);
+        p++;
+        placeholderEnd = p + 1; // Set new argument end.
 
-      if (args.length == 0)
-        continue;
+        if (args.length == 0)
+          continue;
 
-      if (*p == '+')
-      { // $+ = $2 to $n
-        if (args.length > 2)
-          result ~= makeString(args[2].ptr, args[0].ptr + args[0].length);
+        if (*p == '+')
+        { // $+ = $2 to $n
+          if (args.length > 2)
+            result ~= makeString(args[2].ptr, args[0].ptr + args[0].length);
+        }
+        else
+        { // 0 - 9
+          uint nthArg = *p - '0';
+          if (nthArg < args.length)
+            result ~= args[nthArg];
+        }
       }
-      else
-      { // 0 - 9
-        uint nthArg = *p - '0';
-        if (nthArg < args.length)
-          result ~= args[nthArg];
-      }
+      p++;
     }
-    p++;
+    if (placeholderEnd < textEnd)
+      result ~= makeString(placeholderEnd, textEnd);
+    return result;
   }
-  if (placeholderEnd < textEnd)
-    result ~= makeString(placeholderEnd, textEnd);
-  return result;
 }
--- a/trunk/src/main.d	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/main.d	Sat Feb 09 22:54:31 2008 +0100
@@ -311,6 +311,8 @@
       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;
--- a/trunk/src/predefined.ddoc	Sat Feb 09 19:27:14 2008 +0100
+++ b/trunk/src/predefined.ddoc	Sat Feb 09 22:54:31 2008 +0100
@@ -38,17 +38,18 @@
 BLACK = <font color="black">$0</font>
 WHITE = <font color="white">$0</font>
 
-D_CODE = <pre class="d_code">$0</pre>
+D_CODE    = <pre class="d_code">$0</pre>
 D_COMMENT = $(GREEN $0)
 D_STRING  = $(RED $0)
 D_KEYWORD = $(BLUE $0)
 D_PSYMBOL = $(U $0)
-D_PARAM	  = $(I $0)
+D_PARAM   = $(I $0)
 
 DDOC_COMMENT   = <!-- $0 -->
 DDOC_DECL      = $(DT $(BIG $0))
 DDOC_DECL_DD   = $(DD $0)
 DDOC_DITTO     = $(BR)$0
+
 DDOC_SECTIONS  = $0
 DDOC_SUMMARY   = $0$(BR)$(BR)
 DDOC_DESCRIPTION = $0$(BR)$(BR)
@@ -78,14 +79,18 @@
 $0$(BR)$(BR)
 DDOC_VERSION   = $(B Version:)$(BR)
 $0$(BR)$(BR)
-DDOC_SECTION_H = $(B $0)$(BR)$(BR)
+DDOC_SECTION_H = $(B $0)$(BR)
 DDOC_SECTION   = $0$(BR)$(BR)
+
 DDOC_MEMBERS   = $(DL $0)
-DDOC_MODULE_MEMBERS   = $(DDOC_MEMBERS $0)
-DDOC_CLASS_MEMBERS    = $(DDOC_MEMBERS $0)
-DDOC_STRUCT_MEMBERS   = $(DDOC_MEMBERS $0)
-DDOC_ENUM_MEMBERS     = $(DDOC_MEMBERS $0)
-DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)
+DDOC_MODULE_MEMBERS    = $(DDOC_MEMBERS $0)
+DDOC_CLASS_MEMBERS     = $(DDOC_MEMBERS $0)
+DDOC_INTERFACE_MEMBERS = $(DDOC_MEMBERS $0)
+DDOC_STRUCT_MEMBERS    = $(DDOC_MEMBERS $0)
+DDOC_UNION_MEMBERS     = $(DDOC_MEMBERS $0)
+DDOC_TEMPLATE_MEMBERS  = $(DDOC_MEMBERS $0)
+DDOC_ENUM_MEMBERS      = $(DDOC_MEMBERS $0)
+
 DDOC_PARAMS = $(B Params:)$(BR)
 $(TABLE $0)$(BR)
 DDOC_PARAM_ROW = $(TR $0)