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 $&#40;DDOC_BLANKLINE&#41; 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 ~= "&lt;";
342 continue;
343 }
344 p++; // Skip '>'.
345 result ~= makeString(begin, p);
346 }
347 else
348 result ~= "&lt;";
349 continue;
350 case '(': result ~= "&#40;"; break;
351 case ')': result ~= "&#41;"; break;
352 // case '\'': result ~= "&apos;"; break; // &#39;
353 // case '"': result ~= "&quot;"; break;
354 case '>': result ~= "&gt;"; break;
355 case '&':
356 if (p+1 < end && (isalpha(p[1]) || p[1] == '#'))
357 goto default;
358 result ~= "&amp;";
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 ~= "&lt;"; break;
400 case '>': result ~= "&gt;"; break;
401 case '&': result ~= "&amp;"; 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: $&#40;SYMBOL Buffer, 123&#41;
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 }