# HG changeset patch # User Aziz K?ksal # Date 1201952377 -3600 # Node ID 0b8a6e876b6d141769c4cdccef7f49608d9fb311 # Parent 5dd17d4568ce5e6f70effb4bde0a955be1e79d24 Added scanArguments() and expandArguments() to dil.doc.Macro. diff -r 5dd17d4568ce -r 0b8a6e876b6d trunk/src/dil/doc/Macro.d --- 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] == '-') // ". + while (++p + 2 < textEnd) + if (*p == '-' && p[1] == '-' && p[2] == '>') + { + p += 3; + continue Loop; + } + p = textEnd; // p += 2; + } // or + 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; +}