Mercurial > projects > dil
comparison src/cmd/DDoc.d @ 806:bcb74c9b895c
Moved out files in the trunk folder to the root.
author | Aziz K?ksal <aziz.koeksal@gmail.com> |
---|---|
date | Sun, 09 Mar 2008 00:12:19 +0100 |
parents | trunk/src/cmd/DDoc.d@c39667f1e814 |
children | a2880c95eda3 |
comparison
equal
deleted
inserted
replaced
805:a3fab8b74a7d | 806:bcb74c9b895c |
---|---|
1 /++ | |
2 Author: Aziz Köksal | |
3 License: GPL3 | |
4 +/ | |
5 module cmd.DDoc; | |
6 | |
7 import cmd.DDocXML; | |
8 import cmd.Generate; | |
9 import dil.doc.Parser; | |
10 import dil.doc.Macro; | |
11 import dil.doc.Doc; | |
12 import dil.ast.Node; | |
13 import dil.ast.Declarations, | |
14 dil.ast.Statements, | |
15 dil.ast.Expression, | |
16 dil.ast.Parameters, | |
17 dil.ast.Types; | |
18 import dil.ast.DefaultVisitor; | |
19 import dil.lexer.Token; | |
20 import dil.lexer.Funcs; | |
21 import dil.semantic.Module; | |
22 import dil.semantic.Pass1; | |
23 import dil.semantic.Symbol; | |
24 import dil.semantic.Symbols; | |
25 import dil.Compilation; | |
26 import dil.Information; | |
27 import dil.Converter; | |
28 import dil.SourceText; | |
29 import dil.Enums; | |
30 import dil.Time; | |
31 import common; | |
32 | |
33 import tango.text.Ascii : toUpper; | |
34 import tango.io.File; | |
35 import tango.io.FilePath; | |
36 | |
37 /// Executes the doc generation command. | |
38 void execute(string[] filePaths, string destDir, string[] macroPaths, | |
39 bool writeXML, bool incUndoc, bool verbose, | |
40 CompilationContext context, InfoManager infoMan) | |
41 { | |
42 // Parse macro files. | |
43 MacroTable mtable; | |
44 MacroParser mparser; | |
45 foreach (macroPath; macroPaths) | |
46 { | |
47 auto macros = mparser.parse(loadMacroFile(macroPath, infoMan)); | |
48 mtable = new MacroTable(mtable); | |
49 mtable.insert(macros); | |
50 } | |
51 | |
52 // foreach (k, v; mtable.table) | |
53 // Stdout(k)("=")(v.text); | |
54 | |
55 // For DDoc code sections. | |
56 auto tokenHL = new TokenHighlighter(infoMan, writeXML == false); | |
57 | |
58 // Process D files. | |
59 foreach (filePath; filePaths) | |
60 { | |
61 auto mod = new Module(filePath, infoMan); | |
62 // Parse the file. | |
63 mod.parse(); | |
64 if (mod.hasErrors) | |
65 continue; | |
66 | |
67 // Start semantic analysis. | |
68 auto pass1 = new SemanticPass1(mod, context); | |
69 pass1.start(); | |
70 | |
71 // Generate documentation. | |
72 auto dest = new FilePath(destDir); | |
73 dest.append(mod.getFQN() ~ (writeXML ? ".xml" : ".html")); | |
74 | |
75 InfoManager infoMan2; // Collects warnings from the macro expander. | |
76 if (verbose) | |
77 { | |
78 Stdout.formatln("{} > {}", mod.filePath, dest); | |
79 infoMan2 = new InfoManager(); | |
80 } | |
81 | |
82 writeDocFile(dest.toString(), mod, mtable, writeXML, incUndoc, tokenHL, infoMan2); | |
83 | |
84 if (infoMan2) | |
85 infoMan ~= infoMan2.info; | |
86 } | |
87 } | |
88 | |
89 void writeDocFile(string dest, Module mod, MacroTable mtable, | |
90 bool writeXML, bool incUndoc, | |
91 TokenHighlighter tokenHL, InfoManager infoMan) | |
92 { | |
93 // Create a macro environment for this module. | |
94 mtable = new MacroTable(mtable); | |
95 // Define runtime macros. | |
96 // MODPATH is not in the specs. | |
97 mtable.insert("MODPATH", mod.getFQNPath() ~ "." ~ mod.fileExtension()); | |
98 mtable.insert("TITLE", mod.getFQN()); | |
99 mtable.insert("DOCFILENAME", mod.getFQN() ~ (writeXML ? ".xml" : ".html")); | |
100 auto timeStr = Time.toString(); | |
101 mtable.insert("DATETIME", timeStr); | |
102 mtable.insert("YEAR", Time.year(timeStr)); | |
103 | |
104 DDocEmitter docEmitter; | |
105 if (writeXML) | |
106 docEmitter = new DDocXMLEmitter(mod, mtable, incUndoc, tokenHL); | |
107 else | |
108 docEmitter = new DDocEmitter(mod, mtable, incUndoc, tokenHL); | |
109 docEmitter.emit(); | |
110 // Set BODY macro to the text produced by the DDocEmitter. | |
111 mtable.insert("BODY", docEmitter.text); | |
112 // Do the macro expansion pass. | |
113 auto fileText = MacroExpander.expand(mtable, "$(DDOC)", mod.filePath, infoMan); | |
114 // fileText ~= "\n<pre>\n" ~ doc.text ~ "\n</pre>"; | |
115 // Finally write the file out to the harddisk. | |
116 auto file = new File(dest); | |
117 file.write(fileText); | |
118 } | |
119 | |
120 /// Loads a macro file. Converts any Unicode encoding to UTF-8. | |
121 string loadMacroFile(string filePath, InfoManager infoMan) | |
122 { | |
123 auto src = new SourceText(filePath); | |
124 src.load(infoMan); | |
125 auto text = src.data[0..$-1]; // Exclude '\0'. | |
126 return sanitizeText(text); | |
127 } | |
128 | |
129 /// Traverses the syntax tree and writes DDoc macros to a string buffer. | |
130 class DDocEmitter : DefaultVisitor | |
131 { | |
132 char[] text; /// The buffer that is written to. | |
133 bool includeUndocumented; | |
134 MacroTable mtable; | |
135 Module modul; | |
136 TokenHighlighter tokenHL; | |
137 | |
138 /// Constructs a DDocEmitter object. | |
139 /// Params: | |
140 /// modul = the module to generate text for. | |
141 /// mtable = the macro table. | |
142 /// includeUndocumented = whether to include undocumented symbols. | |
143 /// tokenHL = used to highlight code sections. | |
144 this(Module modul, MacroTable mtable, bool includeUndocumented, | |
145 TokenHighlighter tokenHL) | |
146 { | |
147 this.mtable = mtable; | |
148 this.includeUndocumented = includeUndocumented; | |
149 this.modul = modul; | |
150 this.tokenHL = tokenHL; | |
151 } | |
152 | |
153 /// Entry method. | |
154 char[] emit() | |
155 { | |
156 if (auto d = modul.moduleDecl) | |
157 { | |
158 if (ddoc(d)) | |
159 { | |
160 if (auto copyright = cmnt.takeCopyright()) | |
161 mtable.insert(new Macro("COPYRIGHT", copyright.text)); | |
162 writeComment(); | |
163 } | |
164 } | |
165 MEMBERS("MODULE", { visitD(modul.root); }); | |
166 return text; | |
167 } | |
168 | |
169 char[] textSpan(Token* left, Token* right) | |
170 { | |
171 //assert(left && right && (left.end <= right.start || left is right)); | |
172 //char[] result; | |
173 //TODO: filter out whitespace tokens. | |
174 return Token.textSpan(left, right); | |
175 } | |
176 | |
177 TemplateParameters tparams; /// The template parameters of the current declaration. | |
178 | |
179 DDocComment cmnt; /// Current comment. | |
180 DDocComment prevCmnt; /// Previous comment in scope. | |
181 /// An empty comment. Used for undocumented symbols. | |
182 static const DDocComment emptyCmnt; | |
183 | |
184 /// Initializes the empty comment. | |
185 static this() | |
186 { | |
187 this.emptyCmnt = new DDocComment(null, null, null); | |
188 } | |
189 | |
190 /// Keeps track of previous comments in each scope. | |
191 scope class Scope | |
192 { | |
193 DDocComment saved_prevCmnt; | |
194 bool saved_cmntIsDitto; | |
195 uint saved_prevDeclOffset; | |
196 this() | |
197 { // Save the previous comment of the parent scope. | |
198 saved_prevCmnt = this.outer.prevCmnt; | |
199 saved_cmntIsDitto = this.outer.cmntIsDitto; | |
200 saved_prevDeclOffset = this.outer.prevDeclOffset; | |
201 // Entering a new scope. Clear variables. | |
202 this.outer.prevCmnt = null; | |
203 this.outer.cmntIsDitto = false; | |
204 this.outer.prevDeclOffset = 0; | |
205 } | |
206 | |
207 ~this() | |
208 { // Restore the previous comment of the parent scope. | |
209 this.outer.prevCmnt = saved_prevCmnt; | |
210 this.outer.cmntIsDitto = saved_cmntIsDitto; | |
211 this.outer.prevDeclOffset = saved_prevDeclOffset; | |
212 } | |
213 } | |
214 | |
215 bool cmntIsDitto; /// True if current comment is "ditto". | |
216 | |
217 /// Returns the DDocComment for node. | |
218 DDocComment ddoc(Node node) | |
219 { | |
220 auto c = getDDocComment(node); | |
221 this.cmnt = null; | |
222 if (c) | |
223 { | |
224 if (c.isDitto) | |
225 { | |
226 this.cmnt = this.prevCmnt; | |
227 this.cmntIsDitto = true; | |
228 } | |
229 else | |
230 { | |
231 this.cmntIsDitto = false; | |
232 this.cmnt = c; | |
233 this.prevCmnt = c; | |
234 } | |
235 } | |
236 else if (includeUndocumented) | |
237 this.cmnt = this.emptyCmnt; | |
238 return this.cmnt; | |
239 } | |
240 | |
241 /// List of predefined, special sections. | |
242 static char[][char[]] specialSections; | |
243 static this() | |
244 { | |
245 foreach (name; ["AUTHORS", "BUGS", "COPYRIGHT", "DATE", "DEPRECATED", | |
246 "EXAMPLES", "HISTORY", "LICENSE", "RETURNS", "SEE_ALSO", | |
247 "STANDARDS", "THROWS", "VERSION"]) | |
248 specialSections[name] = name; | |
249 } | |
250 | |
251 /// Writes the DDoc comment to the text buffer. | |
252 void writeComment() | |
253 { | |
254 auto c = this.cmnt; | |
255 assert(c !is null); | |
256 if (c.sections.length == 0) | |
257 return; | |
258 write("$(DDOC_SECTIONS "); | |
259 foreach (s; c.sections) | |
260 { | |
261 if (s is c.summary) | |
262 write("\n$(DDOC_SUMMARY "); | |
263 else if (s is c.description) | |
264 write("\n$(DDOC_DESCRIPTION "); | |
265 else if (auto name = toUpper(s.name.dup) in specialSections) | |
266 write("\n$(DDOC_" ~ *name ~ " "); | |
267 else if (s.Is("params")) | |
268 { // Process parameters section. | |
269 auto ps = new ParamsSection(s.name, s.text); | |
270 write("\n$(DDOC_PARAMS "); | |
271 foreach (i, paramName; ps.paramNames) | |
272 write("\n$(DDOC_PARAM_ROW ", | |
273 "$(DDOC_PARAM_ID $(DDOC_PARAM ", paramName, "))", | |
274 "$(DDOC_PARAM_DESC ", ps.paramDescs[i], ")", | |
275 ")"); | |
276 write(")"); | |
277 continue; | |
278 } | |
279 else if (s.Is("macros")) | |
280 { // Declare the macros in this section. | |
281 auto ms = new MacrosSection(s.name, s.text); | |
282 mtable.insert(ms.macroNames, ms.macroTexts); | |
283 continue; | |
284 } | |
285 else | |
286 write("\n$(DDOC_SECTION $(DDOC_SECTION_H " ~ s.name ~ ":)"); | |
287 write(scanCommentText(s.text), ")"); | |
288 } | |
289 write(")"); | |
290 } | |
291 | |
292 /// Scans the comment text and: | |
293 /// $(UL | |
294 /// $(LI skips and leaves macro invocations unchanged) | |
295 /// $(LI skips HTML tags) | |
296 /// $(LI escapes '(', ')', '<', '>' and '&') | |
297 /// $(LI inserts $(DDOC_BLANKLINE) in place of \n\n) | |
298 /// $(LI highlights code in code sections) | |
299 /// ) | |
300 char[] scanCommentText(char[] text) | |
301 { | |
302 char* p = text.ptr; | |
303 char* end = p + text.length; | |
304 char[] result = new char[text.length]; // Reserve space. | |
305 result.length = 0; | |
306 | |
307 while (p < end) | |
308 { | |
309 switch (*p) | |
310 { | |
311 case '$': | |
312 if (auto macroEnd = MacroParser.scanMacro(p, end)) | |
313 { | |
314 result ~= makeString(p, macroEnd); // Copy macro invocation as is. | |
315 p = macroEnd; | |
316 continue; | |
317 } | |
318 goto default; | |
319 case '<': | |
320 auto begin = p; | |
321 p++; | |
322 if (p+2 < end && *p == '!' && p[1] == '-' && p[2] == '-') // <!-- | |
323 { | |
324 p += 2; // Point to 2nd '-'. | |
325 // Scan to closing "-->". | |
326 while (++p < end) | |
327 if (p+2 < end && *p == '-' && p[1] == '-' && p[2] == '>') | |
328 { | |
329 p += 3; // Point one past '>'. | |
330 break; | |
331 } | |
332 result ~= makeString(begin, p); | |
333 } // <tag ...> or </tag> | |
334 else if (p < end && (isalpha(*p) || *p == '/')) | |
335 { | |
336 while (++p < end && *p != '>') // Skip to closing '>'. | |
337 {} | |
338 if (p == end) | |
339 { // No closing '>' found. | |
340 p = begin + 1; | |
341 result ~= "<"; | |
342 continue; | |
343 } | |
344 p++; // Skip '>'. | |
345 result ~= makeString(begin, p); | |
346 } | |
347 else | |
348 result ~= "<"; | |
349 continue; | |
350 case '(': result ~= "("; break; | |
351 case ')': result ~= ")"; break; | |
352 // case '\'': result ~= "'"; break; // ' | |
353 // case '"': result ~= """; break; | |
354 case '>': result ~= ">"; break; | |
355 case '&': | |
356 if (p+1 < end && (isalpha(p[1]) || p[1] == '#')) | |
357 goto default; | |
358 result ~= "&"; | |
359 break; | |
360 case '\n': | |
361 if (!(p+1 < end && p[1] == '\n')) | |
362 goto default; | |
363 ++p; | |
364 result ~= "$(DDOC_BLANKLINE)"; | |
365 break; | |
366 case '-': | |
367 if (p+2 < end && p[1] == '-' && p[2] == '-') | |
368 { | |
369 while (p < end && *p == '-') | |
370 p++; | |
371 auto codeBegin = p; | |
372 p--; | |
373 while (++p < end) | |
374 if (p+2 < end && *p == '-' && p[1] == '-' && p[2] == '-') | |
375 break; | |
376 auto codeText = makeString(codeBegin, p); | |
377 result ~= tokenHL.highlight(codeText, modul.filePath); | |
378 while (p < end && *p == '-') | |
379 p++; | |
380 continue; | |
381 } | |
382 //goto default; | |
383 default: | |
384 result ~= *p; | |
385 } | |
386 p++; | |
387 } | |
388 return result; | |
389 } | |
390 | |
391 /// Escapes '<', '>' and '&' with named HTML entities. | |
392 char[] escape(char[] text) | |
393 { | |
394 char[] result = new char[text.length]; // Reserve space. | |
395 result.length = 0; | |
396 foreach(c; text) | |
397 switch(c) | |
398 { | |
399 case '<': result ~= "<"; break; | |
400 case '>': result ~= ">"; break; | |
401 case '&': result ~= "&"; break; | |
402 default: result ~= c; | |
403 } | |
404 if (result.length != text.length) | |
405 return result; | |
406 // Nothing escaped. Return original text. | |
407 delete result; | |
408 return text; | |
409 } | |
410 | |
411 /// Writes an array of strings to the text buffer. | |
412 void write(char[][] strings...) | |
413 { | |
414 foreach (s; strings) | |
415 text ~= s; | |
416 } | |
417 | |
418 /// Writes params to the text buffer. | |
419 void writeParams(Parameters params) | |
420 { | |
421 if (!params.items.length) | |
422 return write("()"); | |
423 write("("); | |
424 auto lastParam = params.items[$-1]; | |
425 foreach (param; params.items) | |
426 { | |
427 if (param.isCVariadic) | |
428 write("..."); | |
429 else | |
430 { | |
431 assert(param.type); | |
432 // Write storage classes. | |
433 auto typeBegin = param.type.baseType.begin; | |
434 if (typeBegin !is param.begin) // Write storage classes. | |
435 write(textSpan(param.begin, typeBegin.prevNWS), " "); | |
436 write(escape(textSpan(typeBegin, param.type.end))); // Write type. | |
437 if (param.name) | |
438 write(" $(DDOC_PARAM ", param.name.str, ")"); | |
439 if (param.isDVariadic) | |
440 write("..."); | |
441 if (param.defValue) | |
442 write(" = ", escape(textSpan(param.defValue.begin, param.defValue.end))); | |
443 } | |
444 if (param !is lastParam) | |
445 write(", "); | |
446 } | |
447 write(")"); | |
448 } | |
449 | |
450 /// Writes the current template parameters to the text buffer. | |
451 void writeTemplateParams() | |
452 { | |
453 if (!tparams) | |
454 return; | |
455 write(escape(textSpan(tparams.begin, tparams.end))); | |
456 tparams = null; | |
457 } | |
458 | |
459 /// Writes bases to the text buffer. | |
460 void writeInheritanceList(BaseClassType[] bases) | |
461 { | |
462 if (bases.length == 0) | |
463 return; | |
464 auto basesBegin = bases[0].begin.prevNWS; | |
465 if (basesBegin.kind == TOK.Colon) | |
466 basesBegin = bases[0].begin; | |
467 write(" : ", escape(textSpan(basesBegin, bases[$-1].end))); | |
468 } | |
469 | |
470 /// Writes a symbol to the text buffer. E.g: $(SYMBOL Buffer, 123) | |
471 void SYMBOL(char[] name, Declaration d) | |
472 { | |
473 auto loc = d.begin.getRealLocation(); | |
474 auto str = Format("$(SYMBOL {}, {})", name, loc.lineNum); | |
475 write(str); | |
476 // write("$(DDOC_PSYMBOL ", name, ")"); | |
477 } | |
478 | |
479 /// Offset at which to insert a declaration which have a "ditto" comment. | |
480 uint prevDeclOffset; | |
481 | |
482 /// Writes a declaration to the text buffer. | |
483 void DECL(void delegate() dg, Declaration d, bool writeSemicolon = true) | |
484 { | |
485 if (cmntIsDitto) | |
486 { alias prevDeclOffset offs; | |
487 assert(offs != 0); | |
488 auto savedText = text; | |
489 text = ""; | |
490 write("\n$(DDOC_DECL "); | |
491 dg(); | |
492 writeSemicolon && write(";"); | |
493 writeAttributes(d); | |
494 write(")"); | |
495 // Insert text at offset. | |
496 auto len = text.length; | |
497 text = savedText[0..offs] ~ text ~ savedText[offs..$]; | |
498 offs += len; // Add length of the inserted text to the offset. | |
499 return; | |
500 } | |
501 write("\n$(DDOC_DECL "); | |
502 dg(); | |
503 writeSemicolon && write(";"); | |
504 writeAttributes(d); | |
505 write(")"); | |
506 prevDeclOffset = text.length; | |
507 } | |
508 | |
509 /// Wraps the DDOC_DECL_DD macro around the text written by dg(). | |
510 void DESC(void delegate() dg) | |
511 { | |
512 if (cmntIsDitto) | |
513 return; | |
514 write("\n$(DDOC_DECL_DD "); | |
515 dg(); | |
516 write(")"); | |
517 } | |
518 | |
519 /// Wraps the DDOC_kind_MEMBERS macro around the text written by dg(). | |
520 void MEMBERS(char[] kind, void delegate() dg) | |
521 { | |
522 write("\n$(DDOC_"~kind~"_MEMBERS "); | |
523 dg(); | |
524 write(")"); | |
525 } | |
526 | |
527 /// Writes a class or interface declaration. | |
528 void writeClassOrInterface(T)(T d) | |
529 { | |
530 if (!ddoc(d)) | |
531 return d; | |
532 DECL({ | |
533 write(d.begin.srcText, " "); | |
534 SYMBOL(d.name.str, d); | |
535 writeTemplateParams(); | |
536 writeInheritanceList(d.bases); | |
537 }, d); | |
538 DESC({ | |
539 writeComment(); | |
540 MEMBERS(is(T == ClassDeclaration) ? "CLASS" : "INTERFACE", { | |
541 scope s = new Scope(); | |
542 d.decls && super.visit(d.decls); | |
543 }); | |
544 }); | |
545 } | |
546 | |
547 // templated decls are not virtual so we need these: | |
548 | |
549 /// Writes a class declaration. | |
550 void writeClass(ClassDeclaration d) { | |
551 writeClassOrInterface(d); | |
552 } | |
553 | |
554 /// Writes an interface declaration. | |
555 void writeInterface(InterfaceDeclaration d) { | |
556 writeClassOrInterface(d); | |
557 } | |
558 | |
559 /// Writes a struct or union declaration. | |
560 void writeStructOrUnion(T)(T d) | |
561 { | |
562 if (!ddoc(d)) | |
563 return d; | |
564 DECL({ | |
565 write(d.begin.srcText, d.name ? " " : ""); | |
566 if (d.name) | |
567 SYMBOL(d.name.str, d); | |
568 writeTemplateParams(); | |
569 }, d); | |
570 DESC({ | |
571 writeComment(); | |
572 MEMBERS(is(T == StructDeclaration) ? "STRUCT" : "UNION", { | |
573 scope s = new Scope(); | |
574 d.decls && super.visit(d.decls); | |
575 }); | |
576 }); | |
577 } | |
578 | |
579 // templated decls are not virtual so we need these: | |
580 | |
581 /// Writes a struct declaration. | |
582 void writeStruct(StructDeclaration d) { | |
583 writeStructOrUnion(d); | |
584 } | |
585 | |
586 /// Writes an union declaration. | |
587 void writeUnion(UnionDeclaration d) { | |
588 writeStructOrUnion(d); | |
589 } | |
590 | |
591 /// Writes an alias or typedef declaration. | |
592 void writeAliasOrTypedef(T)(T d) | |
593 { | |
594 auto prefix = is(T == AliasDeclaration) ? "alias " : "typedef "; | |
595 if (auto vd = d.decl.Is!(VariablesDeclaration)) | |
596 { | |
597 auto type = textSpan(vd.typeNode.baseType.begin, vd.typeNode.end); | |
598 foreach (name; vd.names) | |
599 DECL({ write(prefix); write(escape(type), " "); SYMBOL(name.str, d); }, d); | |
600 } | |
601 else if (auto fd = d.decl.Is!(FunctionDeclaration)) | |
602 {} | |
603 // DECL({ write(textSpan(d.begin, d.end)); }, false); | |
604 DESC({ writeComment(); }); | |
605 } | |
606 | |
607 /// Writes the attributes of a declaration in brackets. | |
608 void writeAttributes(Declaration d) | |
609 { | |
610 char[][] attributes; | |
611 | |
612 if (d.prot != Protection.None) | |
613 attributes ~= "$(PROT " ~ .toString(d.prot) ~ ")"; | |
614 | |
615 auto stc = d.stc; | |
616 stc &= ~StorageClass.Auto; // Ignore auto. | |
617 foreach (stcStr; .toStrings(stc)) | |
618 attributes ~= "$(STC " ~ stcStr ~ ")"; | |
619 | |
620 LinkageType ltype; | |
621 if (auto vd = d.Is!(VariablesDeclaration)) | |
622 ltype = vd.linkageType; | |
623 else if (auto fd = d.Is!(FunctionDeclaration)) | |
624 ltype = fd.linkageType; | |
625 | |
626 if (ltype != LinkageType.None) | |
627 attributes ~= "$(LINKAGE extern(" ~ .toString(ltype) ~ "))"; | |
628 | |
629 if (!attributes.length) | |
630 return; | |
631 | |
632 write(" $(ATTRIBUTES "); | |
633 write(attributes[0]); | |
634 foreach (attribute; attributes[1..$]) | |
635 write(", ", attribute); | |
636 write(")"); | |
637 } | |
638 | |
639 alias Declaration D; | |
640 | |
641 override: | |
642 D visit(AliasDeclaration d) | |
643 { | |
644 if (!ddoc(d)) | |
645 return d; | |
646 writeAliasOrTypedef(d); | |
647 return d; | |
648 } | |
649 | |
650 D visit(TypedefDeclaration d) | |
651 { | |
652 if (!ddoc(d)) | |
653 return d; | |
654 writeAliasOrTypedef(d); | |
655 return d; | |
656 } | |
657 | |
658 D visit(EnumDeclaration d) | |
659 { | |
660 if (!ddoc(d)) | |
661 return d; | |
662 DECL({ | |
663 write("enum", d.name ? " " : ""); | |
664 d.name && SYMBOL(d.name.str, d); | |
665 }, d); | |
666 DESC({ | |
667 writeComment(); | |
668 MEMBERS("ENUM", { scope s = new Scope(); super.visit(d); }); | |
669 }); | |
670 return d; | |
671 } | |
672 | |
673 D visit(EnumMemberDeclaration d) | |
674 { | |
675 if (!ddoc(d)) | |
676 return d; | |
677 DECL({ SYMBOL(d.name.str, d); }, d, false); | |
678 DESC({ writeComment(); }); | |
679 return d; | |
680 } | |
681 | |
682 D visit(TemplateDeclaration d) | |
683 { | |
684 this.tparams = d.tparams; | |
685 if (d.begin.kind != TOK.Template) | |
686 { // This is a templatized class/interface/struct/union/function. | |
687 super.visit(d.decls); | |
688 this.tparams = null; | |
689 return d; | |
690 } | |
691 if (!ddoc(d)) | |
692 return d; | |
693 DECL({ | |
694 write("template "); | |
695 SYMBOL(d.name.str, d); | |
696 writeTemplateParams(); | |
697 }, d); | |
698 DESC({ | |
699 writeComment(); | |
700 MEMBERS("TEMPLATE", { | |
701 scope s = new Scope(); | |
702 super.visit(d.decls); | |
703 }); | |
704 }); | |
705 return d; | |
706 } | |
707 | |
708 D visit(ClassDeclaration d) | |
709 { | |
710 writeClass(d); | |
711 return d; | |
712 } | |
713 | |
714 D visit(InterfaceDeclaration d) | |
715 { | |
716 writeInterface(d); | |
717 return d; | |
718 } | |
719 | |
720 D visit(StructDeclaration d) | |
721 { | |
722 writeStruct(d); | |
723 return d; | |
724 } | |
725 | |
726 D visit(UnionDeclaration d) | |
727 { | |
728 writeUnion(d); | |
729 return d; | |
730 } | |
731 | |
732 D visit(ConstructorDeclaration d) | |
733 { | |
734 if (!ddoc(d)) | |
735 return d; | |
736 DECL({ SYMBOL("this", d); writeParams(d.params); }, d); | |
737 DESC({ writeComment(); }); | |
738 return d; | |
739 } | |
740 | |
741 D visit(StaticConstructorDeclaration d) | |
742 { | |
743 if (!ddoc(d)) | |
744 return d; | |
745 DECL({ write("static "); SYMBOL("this", d); write("()"); }, d); | |
746 DESC({ writeComment(); }); | |
747 return d; | |
748 } | |
749 | |
750 D visit(DestructorDeclaration d) | |
751 { | |
752 if (!ddoc(d)) | |
753 return d; | |
754 DECL({ write("~"); SYMBOL("this", d); write("()"); }, d); | |
755 DESC({ writeComment(); }); | |
756 return d; | |
757 } | |
758 | |
759 D visit(StaticDestructorDeclaration d) | |
760 { | |
761 if (!ddoc(d)) | |
762 return d; | |
763 DECL({ write("static ~"); SYMBOL("this", d); write("()"); }, d); | |
764 DESC({ writeComment(); }); | |
765 return d; | |
766 } | |
767 | |
768 D visit(FunctionDeclaration d) | |
769 { | |
770 if (!ddoc(d)) | |
771 return d; | |
772 auto type = textSpan(d.returnType.baseType.begin, d.returnType.end); | |
773 DECL({ | |
774 write(escape(type), " "); | |
775 SYMBOL(d.name.str, d); | |
776 writeTemplateParams(); | |
777 writeParams(d.params); | |
778 }, d); | |
779 DESC({ writeComment(); }); | |
780 return d; | |
781 } | |
782 | |
783 D visit(NewDeclaration d) | |
784 { | |
785 if (!ddoc(d)) | |
786 return d; | |
787 DECL({ SYMBOL("new", d); writeParams(d.params); }, d); | |
788 DESC({ writeComment(); }); | |
789 return d; | |
790 } | |
791 | |
792 D visit(DeleteDeclaration d) | |
793 { | |
794 if (!ddoc(d)) | |
795 return d; | |
796 DECL({ SYMBOL("delete", d); writeParams(d.params); }, d); | |
797 DESC({ writeComment(); }); | |
798 return d; | |
799 } | |
800 | |
801 D visit(VariablesDeclaration d) | |
802 { | |
803 if (!ddoc(d)) | |
804 return d; | |
805 char[] type = "auto"; | |
806 if (d.typeNode) | |
807 type = textSpan(d.typeNode.baseType.begin, d.typeNode.end); | |
808 foreach (name; d.names) | |
809 DECL({ write(escape(type), " "); SYMBOL(name.str, d); }, d); | |
810 DESC({ writeComment(); }); | |
811 return d; | |
812 } | |
813 | |
814 D visit(InvariantDeclaration d) | |
815 { | |
816 if (!ddoc(d)) | |
817 return d; | |
818 DECL({ SYMBOL("invariant", d); }, d); | |
819 DESC({ writeComment(); }); | |
820 return d; | |
821 } | |
822 | |
823 D visit(UnittestDeclaration d) | |
824 { | |
825 if (!ddoc(d)) | |
826 return d; | |
827 DECL({ SYMBOL("unittest", d); }, d); | |
828 DESC({ writeComment(); }); | |
829 return d; | |
830 } | |
831 | |
832 D visit(DebugDeclaration d) | |
833 { | |
834 d.compiledDecls && visitD(d.compiledDecls); | |
835 return d; | |
836 } | |
837 | |
838 D visit(VersionDeclaration d) | |
839 { | |
840 d.compiledDecls && visitD(d.compiledDecls); | |
841 return d; | |
842 } | |
843 | |
844 D visit(StaticIfDeclaration d) | |
845 { | |
846 d.ifDecls && visitD(d.ifDecls); | |
847 return d; | |
848 } | |
849 } |