Mercurial > projects > dil
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 } |