root/branches/dmdfe/doc.c

Revision 458, 40.5 kB (checked in by Gregor, 2 years ago)

MERGE: DMD 1.011

Line 
1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2006 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // License for redistribution is by either the Artistic License
7 // in artistic.txt, or the GNU General Public License in gnu.txt.
8 // See the included readme.txt for details.
9
10 // This implements the Ddoc capability.
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <time.h>
15 #include <ctype.h>
16 #include <assert.h>
17
18 #if IN_GCC || IN_DMDFE
19 #include "mem.h"
20 #else
21 #if _WIN32
22 #include "..\root\mem.h"
23 #elif linux
24 #include "../root/mem.h"
25 #else
26 #error "fix this"
27 #endif
28 #endif
29
30 #include "root.h"
31
32 #include "mars.h"
33 #include "dsymbol.h"
34 #include "macro.h"
35 #include "template.h"
36 #include "lexer.h"
37 #include "aggregate.h"
38 #include "declaration.h"
39 #include "enum.h"
40 #include "id.h"
41 #include "module.h"
42 #include "scope.h"
43 #include "hdrgen.h"
44 #include "doc.h"
45 #include "mtype.h"
46
47 struct Escape
48 {
49     char *strings[256];
50
51     static char *escapeChar(unsigned c);
52 };
53
54 struct Section
55 {
56     unsigned char *name;
57     unsigned namelen;
58
59     unsigned char *body;
60     unsigned bodylen;
61
62     int nooutput;
63
64     virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
65 };
66
67 struct ParamSection : Section
68 {
69     void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
70 };
71
72 struct MacroSection : Section
73 {
74     void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf);
75 };
76
77 struct DocComment
78 {
79     Array sections;     // Section*[]
80
81     Section *summary;
82     Section *copyright;
83     Section *macros;
84     Macro **pmacrotable;
85     Escape **pescapetable;
86
87     DocComment();
88
89     static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment);
90     static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen);
91     static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen);
92
93     void parseSections(unsigned char *comment);
94     void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf);
95 };
96
97
98 int cmp(char *stringz, void *s, size_t slen);
99 int icmp(char *stringz, void *s, size_t slen);
100 int isDitto(unsigned char *comment);
101 unsigned char *skipwhitespace(unsigned char *p);
102 unsigned skiptoident(OutBuffer *buf, unsigned i);
103 unsigned skippastident(OutBuffer *buf, unsigned i);
104 void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
105 void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
106 void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset);
107 Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len);
108
109 static unsigned char ddoc_default[] = "\
110 DDOC =  <html><head>\n\
111     <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\
112     <title>$(TITLE)</title>\n\
113     </head><body>\n\
114     <h1>$(TITLE)</h1>\n\
115     $(BODY)\n\
116     <hr>$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/ddoc.html, Ddoc). $(COPYRIGHT))\n\
117     </body></html>\n\
118 \n\
119 B = <b>$0</b>\n\
120 I = <i>$0</i>\n\
121 U = <u>$0</u>\n\
122 P = <p>$0</p>\n\
123 DL =    <dl>$0</dl>\n\
124 DT =    <dt>$0</dt>\n\
125 DD =    <dd>$0</dd>\n\
126 TABLE = <table>$0</table>\n\
127 TR =    <tr>$0</tr>\n\
128 TH =    <th>$0</th>\n\
129 TD =    <td>$0</td>\n\
130 OL =    <ol>$0</ol>\n\
131 UL =    <ul>$0</ul>\n\
132 LI =    <li>$0</li>\n\
133 BIG =   <big>$0</big>\n\
134 SMALL = <small>$0</small>\n\
135 BR =    <br>\n\
136 LINK =  <a href=\"$0\">$0</a>\n\
137 LINK2 = <a href=\"$1\">$+</a>\n\
138 \n\
139 RED =   <font color=red>$0</font>\n\
140 BLUE =  <font color=blue>$0</font>\n\
141 GREEN = <font color=green>$0</font>\n\
142 YELLOW =<font color=yellow>$0</font>\n\
143 BLACK = <font color=black>$0</font>\n\
144 WHITE = <font color=white>$0</font>\n\
145 \n\
146 D_CODE = <pre class=\"d_code\">$0</pre>\n\
147 D_COMMENT = $(GREEN $0)\n\
148 D_STRING  = $(RED $0)\n\
149 D_KEYWORD = $(BLUE $0)\n\
150 D_PSYMBOL = $(U $0)\n\
151 D_PARAM   = $(I $0)\n\
152 \n\
153 DDOC_COMMENT   = <!-- $0 -->\n\
154 DDOC_DECL      = $(DT $(BIG $0))\n\
155 DDOC_DECL_DD   = $(DD $0)\n\
156 DDOC_DITTO     = $(BR)$0\n\
157 DDOC_SECTIONS  = $0\n\
158 DDOC_SUMMARY   = $0$(BR)$(BR)\n\
159 DDOC_DESCRIPTION = $0$(BR)$(BR)\n\
160 DDOC_AUTHORS   = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\
161 DDOC_BUGS      = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\
162 DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\
163 DDOC_DATE      = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\
164 DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\
165 DDOC_EXAMPLES  = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\
166 DDOC_HISTORY   = $(B History:)$(BR)\n$0$(BR)$(BR)\n\
167 DDOC_LICENSE   = $(B License:)$(BR)\n$0$(BR)$(BR)\n\
168 DDOC_RETURNS   = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\
169 DDOC_SEE_ALSO  = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\
170 DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\
171 DDOC_THROWS    = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\
172 DDOC_VERSION   = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\
173 DDOC_SECTION_H = $(B $0)$(BR)\n\
174 DDOC_SECTION   = $0$(BR)$(BR)\n\
175 DDOC_MEMBERS   = $(DL $0)\n\
176 DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\
177 DDOC_CLASS_MEMBERS  = $(DDOC_MEMBERS $0)\n\
178 DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\
179 DDOC_ENUM_MEMBERS   = $(DDOC_MEMBERS $0)\n\
180 DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\
181 DDOC_PARAMS    = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\
182 DDOC_PARAM_ROW = $(TR $0)\n\
183 DDOC_PARAM_ID  = $(TD $0)\n\
184 DDOC_PARAM_DESC = $(TD $0)\n\
185 DDOC_BLANKLINE  = $(BR)$(BR)\n\
186 \n\
187 DDOC_PSYMBOL    = $(U $0)\n\
188 DDOC_KEYWORD    = $(B $0)\n\
189 DDOC_PARAM  = $(I $0)\n\
190 \n\
191 ESCAPES = /</&lt;/\n\
192       />/&gt;/\n\
193       /&/&amp;/\n\
194 ";
195
196 static char ddoc_decl_s[] = "$(DDOC_DECL ";
197 static char ddoc_decl_e[] = ")\n";
198
199 static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD ";
200 static char ddoc_decl_dd_e[] = ")\n";
201
202
203 /****************************************************
204  */
205
206 void Module::gendocfile()
207 {
208     static OutBuffer mbuf;
209     static int mbuf_done;
210
211     OutBuffer buf;
212
213     //printf("Module::gendocfile()\n");
214
215     if (!mbuf_done)     // if not already read the ddoc files
216     {   mbuf_done = 1;
217
218     // Use our internal default
219     mbuf.write(ddoc_default, sizeof(ddoc_default) - 1);
220
221     // Override with DDOCFILE specified in the sc.ini file
222     char *p = getenv("DDOCFILE");
223     if (p)
224         global.params.ddocfiles->shift(p);
225
226     // Override with the ddoc macro files from the command line
227     for (int i = 0; i < global.params.ddocfiles->dim; i++)
228     {
229         FileName f((char *)global.params.ddocfiles->data[i], 0);
230         File file(&f);
231         file.readv();
232         // BUG: convert file contents to UTF-8 before use
233
234         //printf("file: '%.*s'\n", file.len, file.buffer);
235         mbuf.write(file.buffer, file.len);
236     }
237     }
238     DocComment::parseMacros(&escapetable, &macrotable, mbuf.data, mbuf.offset);
239
240     Scope *sc = Scope::createGlobal(this);  // create root scope
241     sc->docbuf = &buf;
242
243     DocComment *dc = DocComment::parse(sc, this, comment);
244     dc->pmacrotable = &macrotable;
245     dc->pescapetable = &escapetable;
246
247     // Generate predefined macros
248
249     // Set the title to be the name of the module
250     {   char *p = toPrettyChars();
251     Macro::define(&macrotable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p));
252     }
253
254     time_t t;
255     time(&t);
256     char *p = ctime(&t);
257     p = mem.strdup(p);
258     Macro::define(&macrotable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p));
259     Macro::define(&macrotable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4);
260
261     char *docfilename = docfile->toChars();
262     Macro::define(&macrotable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename));
263
264     if (dc->copyright)
265     {
266     dc->copyright->nooutput = 1;
267     Macro::define(&macrotable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen);
268     }
269
270     buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars());
271
272     if (isDocFile)
273     {
274     size_t commentlen = strlen((char *)comment);
275     if (dc->macros)
276     {
277         commentlen = dc->macros->name - comment;
278         dc->macros->write(dc, sc, this, sc->docbuf);
279     }
280     sc->docbuf->write(comment, commentlen);
281     highlightText(NULL, this, sc->docbuf, 0);
282     }
283     else
284     {
285
286     dc->writeSections(sc, this, sc->docbuf);
287     emitMemberComments(sc);
288     }
289
290     //printf("BODY= '%.*s'\n", buf.offset, buf.data);
291     Macro::define(&macrotable, (unsigned char *)"BODY", 4, buf.data, buf.offset);
292
293     OutBuffer buf2;
294     buf2.writestring("$(DDOC)\n");
295     unsigned end = buf2.offset;
296     macrotable->expand(&buf2, 0, &end, NULL, 0);
297
298 #if 1
299     /* Remove all the escape sequences from buf2,
300      * and make CR-LF the newline.
301      */
302     {
303     buf.setsize(0);
304     buf.reserve(buf2.offset);
305     unsigned char *p = buf2.data;
306     for (unsigned j = 0; j < buf2.offset; j++)
307     {
308         unsigned char c = p[j];
309         if (c == 0xFF && j + 1 < buf2.offset)
310         {
311         j++;
312         continue;
313         }
314         if (c == '\n')
315         buf.writeByte('\r');
316         else if (c == '\r')
317         {
318         buf.writestring("\r\n");
319         if (j + 1 < buf2.offset && p[j + 1] == '\n')
320         {
321             j++;
322         }
323         continue;
324         }
325         buf.writeByte(c);
326     }
327     }
328
329     // Transfer image to file
330     assert(docfile);
331     docfile->setbuffer(buf.data, buf.offset);
332     docfile->ref = 1;
333     char *pt = FileName::path(docfile->toChars());
334     if (*pt)
335     FileName::ensurePathExists(pt);
336     mem.free(pt);
337     docfile->writev();
338 #else
339     /* Remove all the escape sequences from buf2
340      */
341     {   unsigned i = 0;
342     unsigned char *p = buf2.data;
343     for (unsigned j = 0; j < buf2.offset; j++)
344     {
345         if (p[j] == 0xFF && j + 1 < buf2.offset)
346         {
347         j++;
348         continue;
349         }
350         p[i] = p[j];
351         i++;
352     }
353     buf2.setsize(i);
354     }
355
356     // Transfer image to file
357     docfile->setbuffer(buf2.data, buf2.offset);
358     docfile->ref = 1;
359     char *pt = FileName::path(docfile->toChars());
360     if (*pt)
361     FileName::ensurePathExists(pt);
362     mem.free(pt);
363     docfile->writev();
364 #endif
365 }
366
367 /******************************* emitComment **********************************/
368
369 /*
370  * Emit doc comment to documentation file
371  */
372
373 void Dsymbol::emitDitto(Scope *sc)
374 {
375     OutBuffer *buf = sc->docbuf;
376     unsigned o;
377     OutBuffer b;
378
379     b.writestring("$(DDOC_DITTO ");
380     o = b.offset;
381     toDocBuffer(&b);
382     highlightCode(sc, this, &b, o);
383     b.writeByte(')');
384     buf->spread(sc->lastoffset, b.offset);
385     memcpy(buf->data + sc->lastoffset, b.data, b.offset);
386     sc->lastoffset += b.offset;
387 }
388
389 void ScopeDsymbol::emitMemberComments(Scope *sc)
390 {
391     //printf("ScopeDsymbol::emitMemberComments()\n");
392     OutBuffer *buf = sc->docbuf;
393
394     if (members)
395     {   char *m = "$(DDOC_MEMBERS \n";
396
397     if (isModule())
398         m = "$(DDOC_MODULE_MEMBERS \n";
399     else if (isClassDeclaration())
400         m = "$(DDOC_CLASS_MEMBERS \n";
401     else if (isStructDeclaration())
402         m = "$(DDOC_STRUCT_MEMBERS \n";
403     else if (isEnumDeclaration())
404         m = "$(DDOC_ENUM_MEMBERS \n";
405     else if (isTemplateDeclaration())
406         m = "$(DDOC_TEMPLATE_MEMBERS \n";
407
408     // BUG: if no members are actually printed, we should not emit DDOC_MEMBERS
409     buf->writestring(m);
410     sc = sc->push(this);
411     for (int i = 0; i < members->dim; i++)
412     {
413         Dsymbol *s = (Dsymbol *)members->data[i];
414         //printf("\ts = '%s'\n", s->toChars());
415         s->emitComment(sc);
416     }
417     sc->pop();
418     buf->writestring(")\n");
419     }
420 }
421
422 void emitProtection(OutBuffer *buf, PROT prot)
423 {
424     char *p;
425
426     switch (prot)
427     {
428     case PROTpackage:   p = "package";   break;
429     case PROTprotected: p = "protected"; break;
430     case PROTexport:    p = "export";    break;
431     default:        p = NULL;    break;
432     }
433     if (p)
434     buf->printf("%s ", p);
435 }
436
437 void Dsymbol::emitComment(Scope *sc)           { }
438 void InvariantDeclaration::emitComment(Scope *sc)  { }
439 void DtorDeclaration::emitComment(Scope *sc)       { }
440 void StaticCtorDeclaration::emitComment(Scope *sc) { }
441 void StaticDtorDeclaration::emitComment(Scope *sc) { }
442 void ClassInfoDeclaration::emitComment(Scope *sc)  { }
443 void ModuleInfoDeclaration::emitComment(Scope *sc) { }
444 void TypeInfoDeclaration::emitComment(Scope *sc)   { }
445
446
447 void Declaration::emitComment(Scope *sc)
448 {
449     //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment);
450     //printf("type = %p\n", type);
451
452     if (protection == PROTprivate || !ident ||
453     (!type && !isCtorDeclaration() && !isAliasDeclaration()))
454     return;
455     if (!comment)
456     return;
457
458     OutBuffer *buf = sc->docbuf;
459     DocComment *dc = DocComment::parse(sc, this, comment);
460     unsigned o;
461
462     if (!dc)
463     {
464     emitDitto(sc);
465     return;
466     }
467     dc->pmacrotable = &sc->module->macrotable;
468
469     buf->writestring(ddoc_decl_s);
470     o = buf->offset;
471     toDocBuffer(buf);
472     highlightCode(sc, this, buf, o);
473     sc->lastoffset = buf->offset;
474     buf->writestring(ddoc_decl_e);
475
476     buf->writestring(ddoc_decl_dd_s);
477     dc->writeSections(sc, this, buf);
478     buf->writestring(ddoc_decl_dd_e);
479 }
480
481 void AggregateDeclaration::emitComment(Scope *sc)
482 {
483     //printf("AggregateDeclaration::emitComment() '%s'\n", toChars());
484     if (prot() == PROTprivate)
485     return;
486     if (!comment)
487     return;
488
489     OutBuffer *buf = sc->docbuf;
490     DocComment *dc = DocComment::parse(sc, this, comment);
491
492     if (!dc)
493     {
494     emitDitto(sc);
495     return;
496     }
497     dc->pmacrotable = &sc->module->macrotable;
498
499     buf->writestring(ddoc_decl_s);
500     toDocBuffer(buf);
501     sc->lastoffset = buf->offset;
502     buf->writestring(ddoc_decl_e);
503
504     buf->writestring(ddoc_decl_dd_s);
505     dc->writeSections(sc, this, buf);
506     emitMemberComments(sc);
507     buf->writestring(ddoc_decl_dd_e);
508 }
509
510 void TemplateDeclaration::emitComment(Scope *sc)
511 {
512     //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind());
513     if (prot() == PROTprivate)
514     return;
515     if (!comment)
516     return;
517
518     OutBuffer *buf = sc->docbuf;
519     DocComment *dc = DocComment::parse(sc, this, comment);
520     unsigned o;
521     int hasmembers = 1;
522
523     Dsymbol *ss = this;
524
525     if (onemember)
526     {
527     ss = onemember->isAggregateDeclaration();
528     if (!ss)
529     {
530         ss = onemember->isFuncDeclaration();
531         if (ss)
532         hasmembers = 0;
533         else
534         ss = this;
535     }
536     }
537
538     if (!dc)
539     {
540     ss->emitDitto(sc);
541     return;
542     }
543     dc->pmacrotable = &sc->module->macrotable;
544
545     buf->writestring(ddoc_decl_s);
546     o = buf->offset;
547     ss->toDocBuffer(buf);
548     if (ss == this)
549         highlightCode(sc, this, buf, o);
550     sc->lastoffset = buf->offset;
551     buf->writestring(ddoc_decl_e);
552
553     buf->writestring(ddoc_decl_dd_s);
554     dc->writeSections(sc, this, buf);
555     if (hasmembers)
556     ((ScopeDsymbol *)ss)->emitMemberComments(sc);
557     buf->writestring(ddoc_decl_dd_e);
558 }
559
560 void EnumDeclaration::emitComment(Scope *sc)
561 {
562     if (prot() == PROTprivate)
563     return;
564 //    if (!comment)
565     {   if (isAnonymous() && members)
566     {
567         for (int i = 0; i < members->dim; i++)
568         {
569         Dsymbol *s = (Dsymbol *)members->data[i];
570         s->emitComment(sc);
571         }
572         return;
573     }
574     }
575     if (!comment)
576     return;
577     if (isAnonymous())
578     return;
579
580     OutBuffer *buf = sc->docbuf;
581     DocComment *dc = DocComment::parse(sc, this, comment);
582
583     if (!dc)
584     {
585     emitDitto(sc);
586     return;
587     }
588     dc->pmacrotable = &sc->module->macrotable;
589
590     buf->writestring(ddoc_decl_s);
591     toDocBuffer(buf);
592     sc->lastoffset = buf->offset;
593     buf->writestring(ddoc_decl_e);
594
595     buf->writestring(ddoc_decl_dd_s);
596     dc->writeSections(sc, this, buf);
597     emitMemberComments(sc);
598     buf->writestring(ddoc_decl_dd_e);
599 }
600
601 void EnumMember::emitComment(Scope *sc)
602 {
603     //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment);
604     if (prot() == PROTprivate)
605     return;
606     if (!comment)
607     return;
608
609     OutBuffer *buf = sc->docbuf;
610     DocComment *dc = DocComment::parse(sc, this, comment);
611     unsigned o;
612
613     if (!dc)
614     {
615     emitDitto(sc);
616     return;
617     }
618     dc->pmacrotable = &sc->module->macrotable;
619
620     buf->writestring(ddoc_decl_s);
621     o = buf->offset;
622     toDocBuffer(buf);
623     highlightCode(sc, this, buf, o);
624     sc->lastoffset = buf->offset;
625     buf->writestring(