comparison trunk/src/dil/doc/Macro.d @ 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
comparison
equal deleted inserted replaced
723:5dd17d4568ce 724:0b8a6e876b6d
139 while (p+3 < textEnd) // minimum 4 chars: $(x) 139 while (p+3 < textEnd) // minimum 4 chars: $(x)
140 { 140 {
141 if (*p == '$' && p[1] == '(') 141 if (*p == '$' && p[1] == '(')
142 { 142 {
143 // Copy string between macros. 143 // Copy string between macros.
144 result ~= makeString(macroEnd, p); 144 if (macroEnd !is p)
145 result ~= makeString(macroEnd, p);
145 p += 2; 146 p += 2;
146 auto idBegin = p; 147 auto idBegin = p;
147 if (isidbeg(*p) || isUnicodeAlpha(p, textEnd)) // IdStart 148 if (isidbeg(*p) || isUnicodeAlpha(p, textEnd)) // IdStart
148 { 149 {
149 do // IdChar* 150 do // IdChar*
150 p++; 151 p++;
151 while (p < textEnd && (isident(*p) || isUnicodeAlpha(p, textEnd))) 152 while (p < textEnd && (isident(*p) || isUnicodeAlpha(p, textEnd)))
153 // Create macro name.
152 auto macroName = makeString(idBegin, p); 154 auto macroName = makeString(idBegin, p);
153 if (*p == ')') 155 // Get arguments.
154 { 156 auto args = scanArguments(p, textEnd);
155 p++; 157 // TODO: still expand macro if no closing bracket was found?
156 macroEnd = p; 158 if (p == textEnd)
157 } 159 break; // No closing bracket found.
160 assert(*p == ')');
161 p++;
162 macroEnd = p;
163
158 auto macro_ = table.search(macroName); 164 auto macro_ = table.search(macroName);
159 if (macro_) 165 if (macro_)
160 { 166 result ~= expandArguments(macro_.text, args);
161 result ~= macro_.text; 167 continue;
162 } 168 }
163 } 169 }
164 } 170 p++;
165 p++; 171 }
166 } 172 if (macroEnd < textEnd)
173 result ~= makeString(macroEnd, textEnd);
167 return result; 174 return result;
168 } 175 }
169 176
177 /// Scans until the closing ')' is found.
178 /// Returns [$0, $1, $2 ...].
179 char[][] scanArguments(ref char* p, char* textEnd)
180 {
181 // D specs: "The argument text can contain nested parentheses,
182 // "" or '' strings, comments, or tags."
183 uint level = 1; // Nesting level of the parentheses.
184 char[][] args;
185
186 // Skip leading spaces.
187 while (p < textEnd && isspace(*p))
188 p++;
189
190 char* arg0Begin = p; // Whole argument list.
191 char* argBegin = p;
192 Loop:
193 while (p < textEnd)
194 {
195 switch (*p)
196 {
197 case ',':
198 // Add a new argument.
199 args ~= makeString(argBegin, p);
200 while (++p < textEnd && isspace(*p))
201 {}
202 argBegin = p;
203 continue;
204 case '(':
205 level++;
206 break;
207 case ')':
208 if (--level == 0)
209 break Loop;
210 break;
211 case '"', '\'':
212 auto c = *p;
213 while (++p < textEnd && *p != c) // Scan to next " or '.
214 {}
215 assert(*p == c || p == textEnd);
216 if (p == textEnd)
217 break Loop;
218 break;
219 case '<':
220 if (p+3 < textEnd && p[1] == '!' && p[2] == '-' && p[3] == '-') // <!--
221 {
222 p += 3;
223 // Scan to closing "-->".
224 while (++p + 2 < textEnd)
225 if (*p == '-' && p[1] == '-' && p[2] == '>')
226 {
227 p += 3;
228 continue Loop;
229 }
230 p = textEnd; // p += 2;
231 } // <tag ...> or </tag>
232 else if (p+1 < textEnd && (isalpha(p[1]) || p[1] == '/'))
233 while (++p < textEnd && *p != '>') // Skip to closing '>'.
234 {}
235 if (p == textEnd)
236 break Loop;
237 break;
238 default:
239 }
240 p++;
241 }
242 assert(*p == ')' && level == 0 || p == textEnd);
243 if (arg0Begin is p)
244 return null;
245 // arg0 spans the whole argument list.
246 auto arg0 = makeString(arg0Begin, p);
247 // Add last argument.
248 args ~= makeString(argBegin, p);
249 return arg0 ~ args;
250 }
251
252 /// Expands "$+", "$0" - "$9" with args[n] in text.
253 /// Params:
254 /// text = the text to scan for argument placeholders.
255 /// args = the first element, args[0], is the whole argument string and
256 /// the following elements are slices into it.
257 /// The array is empty if there are no arguments.
258 char[] expandArguments(char[] text, char[][] args)
259 in { assert(args.length != 1, "zero or more than 1 args expected"); }
260 body
261 {
262 char[] result;
263 char* p = text.ptr;
264 char* textEnd = p + text.length;
265 char* placeholderEnd = p;
266
267 while (p+1 < textEnd)
268 {
269 if (*p == '$' && (p[1] == '+' || isdigit(p[1])))
270 {
271 // Copy string between argument placeholders.
272 if (placeholderEnd !is p)
273 result ~= makeString(placeholderEnd, p);
274 p++;
275 placeholderEnd = p + 1; // Set new argument end.
276
277 if (args.length == 0)
278 continue;
279
280 if (*p == '+')
281 { // $+ = $2 to $n
282 if (args.length > 1)
283 result ~= makeString(args[2].ptr, args[0].ptr + args[0].length);
284 }
285 else
286 { // 0 - 9
287 uint nthArg = *p - '0';
288 if (nthArg < args.length)
289 result ~= args[nthArg];
290 }
291 }
292 p++;
293 }
294 if (placeholderEnd < textEnd)
295 result ~= makeString(placeholderEnd, textEnd);
296 return result;
297 }