changeset 724:0b8a6e876b6d

Added scanArguments() and expandArguments() to dil.doc.Macro.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sat, 02 Feb 2008 12:39:37 +0100
parents 5dd17d4568ce
children 84291c0a9e13
files trunk/src/dil/doc/Macro.d
diffstat 1 files changed, 137 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/trunk/src/dil/doc/Macro.d	Fri Feb 01 20:51:44 2008 +0100
+++ b/trunk/src/dil/doc/Macro.d	Sat Feb 02 12:39:37 2008 +0100
@@ -141,7 +141,8 @@
     if (*p == '$' && p[1] == '(')
     {
       // Copy string between macros.
-      result ~= makeString(macroEnd, p);
+      if (macroEnd !is p)
+        result ~= makeString(macroEnd, p);
       p += 2;
       auto idBegin = p;
       if (isidbeg(*p) || isUnicodeAlpha(p, textEnd)) // IdStart
@@ -149,21 +150,148 @@
         do // IdChar*
           p++;
         while (p < textEnd && (isident(*p) || isUnicodeAlpha(p, textEnd)))
+        // Create macro name.
         auto macroName = makeString(idBegin, p);
-        if (*p == ')')
-        {
-          p++;
-          macroEnd = p;
-        }
+        // Get arguments.
+        auto args = 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;
+
         auto macro_ = table.search(macroName);
         if (macro_)
-        {
-          result ~= macro_.text;
-        }
+          result ~= expandArguments(macro_.text, args);
+        continue;
       }
     }
     p++;
   }
+  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)
+{
+  // 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++;
+
+  char* arg0Begin = p; // Whole argument list.
+  char* argBegin = p;
+Loop:
+  while (p < textEnd)
+  {
+    switch (*p)
+    {
+    case ',':
+      // 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 '>'.
+        {}
+      if (p == textEnd)
+        break Loop;
+      break;
+    default:
+    }
+    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;
+}
+
+/// 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)
+  {
+    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 (*p == '+')
+      { // $+ = $2 to $n
+        if (args.length > 1)
+          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];
+      }
+    }
+    p++;
+  }
+  if (placeholderEnd < textEnd)
+    result ~= makeString(placeholderEnd, textEnd);
+  return result;
+}