Mercurial > projects > ldc
annotate dmd/doc.c @ 837:331a176c1f4f
Removed error on naked, not fully complete, but I'll be doing more work on it during this Christmas, and some things do work.
Fixed taking delegate of final class method. see mini/delegate3.d.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 09 Dec 2008 14:07:30 +0100 |
parents | cbd6c8073a32 |
children | 330f999ade44 |
rev | line source |
---|---|
159 | 1 |
2 // Compiler implementation of the D programming language | |
3 // Copyright (c) 1999-2008 by Digital Mars | |
4 // All Rights Reserved | |
5 // written by Walter Bright | |
6 // http://www.digitalmars.com | |
7 // License for redistribution is by either the Artistic License | |
8 // in artistic.txt, or the GNU General Public License in gnu.txt. | |
9 // See the included readme.txt for details. | |
10 | |
11 // This implements the Ddoc capability. | |
12 | |
13 #include <stdio.h> | |
14 #include <string.h> | |
15 #include <time.h> | |
16 #include <ctype.h> | |
17 #include <assert.h> | |
18 | |
19 #if IN_GCC || IN_LLVM | |
20 #include "mem.h" | |
21 #else | |
22 #if _WIN32 | |
23 #include "..\root\mem.h" | |
571
cbd6c8073a32
Changed all '#if linux || __APPLE__' to '#if POSIX' so we can support other platforms too, thanx for the suggestion anders.
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
535
diff
changeset
|
24 #elif POSIX |
159 | 25 #include "../root/mem.h" |
26 #else | |
27 #error "fix this" | |
28 #endif | |
29 #endif | |
30 | |
31 #include "root.h" | |
32 | |
33 #include "mars.h" | |
34 #include "dsymbol.h" | |
35 #include "macro.h" | |
36 #include "template.h" | |
37 #include "lexer.h" | |
38 #include "aggregate.h" | |
39 #include "declaration.h" | |
40 #include "enum.h" | |
41 #include "id.h" | |
42 #include "module.h" | |
43 #include "scope.h" | |
44 #include "hdrgen.h" | |
45 #include "doc.h" | |
46 #include "mtype.h" | |
47 | |
48 struct Escape | |
49 { | |
50 char *strings[256]; | |
51 | |
52 static char *escapeChar(unsigned c); | |
53 }; | |
54 | |
55 struct Section | |
56 { | |
57 unsigned char *name; | |
58 unsigned namelen; | |
59 | |
60 unsigned char *body; | |
61 unsigned bodylen; | |
62 | |
63 int nooutput; | |
64 | |
65 virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); | |
66 }; | |
67 | |
68 struct ParamSection : Section | |
69 { | |
70 void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); | |
71 }; | |
72 | |
73 struct MacroSection : Section | |
74 { | |
75 void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); | |
76 }; | |
77 | |
78 struct DocComment | |
79 { | |
80 Array sections; // Section*[] | |
81 | |
82 Section *summary; | |
83 Section *copyright; | |
84 Section *macros; | |
85 Macro **pmacrotable; | |
86 Escape **pescapetable; | |
87 | |
88 DocComment(); | |
89 | |
90 static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); | |
91 static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); | |
92 static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); | |
93 | |
94 void parseSections(unsigned char *comment); | |
95 void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); | |
96 }; | |
97 | |
98 | |
99 int cmp(char *stringz, void *s, size_t slen); | |
100 int icmp(char *stringz, void *s, size_t slen); | |
101 int isDitto(unsigned char *comment); | |
102 unsigned char *skipwhitespace(unsigned char *p); | |
103 unsigned skiptoident(OutBuffer *buf, unsigned i); | |
104 unsigned skippastident(OutBuffer *buf, unsigned i); | |
105 unsigned skippastURL(OutBuffer *buf, unsigned i); | |
106 void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); | |
107 void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); | |
108 void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); | |
109 Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); | |
110 | |
111 static unsigned char ddoc_default[] = "\ | |
112 DDOC = <html><head>\n\ | |
113 <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\ | |
114 <title>$(TITLE)</title>\n\ | |
115 </head><body>\n\ | |
116 <h1>$(TITLE)</h1>\n\ | |
117 $(BODY)\n\ | |
118 <hr>$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/1.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ | |
119 </body></html>\n\ | |
120 \n\ | |
121 B = <b>$0</b>\n\ | |
122 I = <i>$0</i>\n\ | |
123 U = <u>$0</u>\n\ | |
124 P = <p>$0</p>\n\ | |
125 DL = <dl>$0</dl>\n\ | |
126 DT = <dt>$0</dt>\n\ | |
127 DD = <dd>$0</dd>\n\ | |
128 TABLE = <table>$0</table>\n\ | |
129 TR = <tr>$0</tr>\n\ | |
130 TH = <th>$0</th>\n\ | |
131 TD = <td>$0</td>\n\ | |
132 OL = <ol>$0</ol>\n\ | |
133 UL = <ul>$0</ul>\n\ | |
134 LI = <li>$0</li>\n\ | |
135 BIG = <big>$0</big>\n\ | |
136 SMALL = <small>$0</small>\n\ | |
137 BR = <br>\n\ | |
138 LINK = <a href=\"$0\">$0</a>\n\ | |
139 LINK2 = <a href=\"$1\">$+</a>\n\ | |
140 \n\ | |
141 RED = <font color=red>$0</font>\n\ | |
142 BLUE = <font color=blue>$0</font>\n\ | |
143 GREEN = <font color=green>$0</font>\n\ | |
144 YELLOW =<font color=yellow>$0</font>\n\ | |
145 BLACK = <font color=black>$0</font>\n\ | |
146 WHITE = <font color=white>$0</font>\n\ | |
147 \n\ | |
148 D_CODE = <pre class=\"d_code\">$0</pre>\n\ | |
149 D_COMMENT = $(GREEN $0)\n\ | |
150 D_STRING = $(RED $0)\n\ | |
151 D_KEYWORD = $(BLUE $0)\n\ | |
152 D_PSYMBOL = $(U $0)\n\ | |
153 D_PARAM = $(I $0)\n\ | |
154 \n\ | |
155 DDOC_COMMENT = <!-- $0 -->\n\ | |
156 DDOC_DECL = $(DT $(BIG $0))\n\ | |
157 DDOC_DECL_DD = $(DD $0)\n\ | |
158 DDOC_DITTO = $(BR)$0\n\ | |
159 DDOC_SECTIONS = $0\n\ | |
160 DDOC_SUMMARY = $0$(BR)$(BR)\n\ | |
161 DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ | |
162 DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ | |
163 DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ | |
164 DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ | |
165 DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ | |
166 DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ | |
167 DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ | |
168 DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ | |
169 DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ | |
170 DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ | |
171 DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ | |
172 DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ | |
173 DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ | |
174 DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ | |
175 DDOC_SECTION_H = $(B $0)$(BR)\n\ | |
176 DDOC_SECTION = $0$(BR)$(BR)\n\ | |
177 DDOC_MEMBERS = $(DL $0)\n\ | |
178 DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ | |
179 DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ | |
180 DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ | |
181 DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ | |
182 DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ | |
183 DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ | |
184 DDOC_PARAM_ROW = $(TR $0)\n\ | |
185 DDOC_PARAM_ID = $(TD $0)\n\ | |
186 DDOC_PARAM_DESC = $(TD $0)\n\ | |
187 DDOC_BLANKLINE = $(BR)$(BR)\n\ | |
188 \n\ | |
189 DDOC_PSYMBOL = $(U $0)\n\ | |
190 DDOC_KEYWORD = $(B $0)\n\ | |
191 DDOC_PARAM = $(I $0)\n\ | |
192 \n\ | |
193 ESCAPES = /</</\n\ | |
194 />/>/\n\ | |
195 /&/&/\n\ | |
196 "; | |
197 | |
198 static char ddoc_decl_s[] = "$(DDOC_DECL "; | |
199 static char ddoc_decl_e[] = ")\n"; | |
200 | |
201 static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; | |
202 static char ddoc_decl_dd_e[] = ")\n"; | |
203 | |
204 | |
205 /**************************************************** | |
206 */ | |
207 | |
208 void Module::gendocfile() | |
209 { | |
210 static OutBuffer mbuf; | |
211 static int mbuf_done; | |
212 | |
213 OutBuffer buf; | |
214 | |
215 //printf("Module::gendocfile()\n"); | |
216 | |
217 if (!mbuf_done) // if not already read the ddoc files | |
218 { mbuf_done = 1; | |
219 | |
220 // Use our internal default | |
221 mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); | |
222 | |
223 // Override with DDOCFILE specified in the sc.ini file | |
224 char *p = getenv("DDOCFILE"); | |
225 if (p) | |
226 global.params.ddocfiles->shift(p); | |
227 | |
228 // Override with the ddoc macro files from the command line | |
229 for (int i = 0; i < global.params.ddocfiles->dim; i++) | |
230 { | |
231 FileName f((char *)global.params.ddocfiles->data[i], 0); | |
232 File file(&f); | |
233 file.readv(); | |
234 // BUG: convert file contents to UTF-8 before use | |
235 | |
236 //printf("file: '%.*s'\n", file.len, file.buffer); | |
237 mbuf.write(file.buffer, file.len); | |
238 } | |
239 } | |
240 DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); | |
241 | |
242 Scope *sc = Scope::createGlobal(this); // create root scope | |
243 sc->docbuf = &buf; | |
244 | |
245 DocComment *dc = DocComment::parse(sc, this, comment); | |
246 dc->pmacrotable = ¯otable; | |
247 dc->pescapetable = &escapetable; | |
248 | |
249 // Generate predefined macros | |
250 | |
251 // Set the title to be the name of the module | |
252 { char *p = toPrettyChars(); | |
253 Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); | |
254 } | |
255 | |
256 time_t t; | |
257 time(&t); | |
258 char *p = ctime(&t); | |
259 p = mem.strdup(p); | |
260 Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); | |
261 Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); | |
262 | |
263 char *docfilename = docfile->toChars(); | |
264 Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); | |
265 | |
266 if (dc->copyright) | |
267 { | |
268 dc->copyright->nooutput = 1; | |
269 Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); | |
270 } | |
271 | |
272 buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); | |
273 if (isDocFile) | |
274 { | |
275 size_t commentlen = strlen((char *)comment); | |
276 if (dc->macros) | |
277 { | |
278 commentlen = dc->macros->name - comment; | |
279 dc->macros->write(dc, sc, this, sc->docbuf); | |
280 } | |
281 sc->docbuf->write(comment, commentlen); | |
282 highlightText(NULL, this, sc->docbuf, 0); | |
283 } | |
284 else | |
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(¯otable, (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 //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); | |
376 OutBuffer *buf = sc->docbuf; | |
377 unsigned o; | |
378 OutBuffer b; | |
379 | |
380 b.writestring("$(DDOC_DITTO "); | |
381 o = b.offset; | |
382 toDocBuffer(&b); | |
383 //printf("b: '%.*s'\n", b.offset, b.data); | |
384 /* If 'this' is a function template, then highlightCode() was | |
385 * already run by FuncDeclaration::toDocbuffer(). | |
386 */ | |
387 TemplateDeclaration *td; | |
388 if (parent && | |
389 (td = parent->isTemplateDeclaration()) != NULL && | |
390 td->onemember == this) | |
391 { | |
392 } | |
393 else | |
394 highlightCode(sc, this, &b, o); | |
395 b.writeByte(')'); | |
396 buf->spread(sc->lastoffset, b.offset); | |
397 memcpy(buf->data + sc->lastoffset, b.data, b.offset); | |
398 sc->lastoffset += b.offset; | |
399 } | |
400 | |
401 void ScopeDsymbol::emitMemberComments(Scope *sc) | |
402 { | |
336 | 403 //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); |
159 | 404 OutBuffer *buf = sc->docbuf; |
405 | |
406 if (members) | |
407 { char *m = "$(DDOC_MEMBERS \n"; | |
408 | |
409 if (isModule()) | |
410 m = "$(DDOC_MODULE_MEMBERS \n"; | |
411 else if (isClassDeclaration()) | |
412 m = "$(DDOC_CLASS_MEMBERS \n"; | |
413 else if (isStructDeclaration()) | |
414 m = "$(DDOC_STRUCT_MEMBERS \n"; | |
415 else if (isEnumDeclaration()) | |
416 m = "$(DDOC_ENUM_MEMBERS \n"; | |
417 else if (isTemplateDeclaration()) | |
418 m = "$(DDOC_TEMPLATE_MEMBERS \n"; | |
419 | |
336 | 420 unsigned offset1 = buf->offset; // save starting offset |
159 | 421 buf->writestring(m); |
336 | 422 unsigned offset2 = buf->offset; // to see if we write anything |
159 | 423 sc = sc->push(this); |
424 for (int i = 0; i < members->dim; i++) | |
425 { | |
426 Dsymbol *s = (Dsymbol *)members->data[i]; | |
427 //printf("\ts = '%s'\n", s->toChars()); | |
428 s->emitComment(sc); | |
429 } | |
430 sc->pop(); | |
336 | 431 if (buf->offset == offset2) |
432 { | |
433 /* Didn't write out any members, so back out last write | |
434 */ | |
435 buf->offset = offset1; | |
436 } | |
437 else | |
438 buf->writestring(")\n"); | |
159 | 439 } |
440 } | |
441 | |
442 void emitProtection(OutBuffer *buf, PROT prot) | |
443 { | |
444 char *p; | |
445 | |
446 switch (prot) | |
447 { | |
448 case PROTpackage: p = "package"; break; | |
449 case PROTprotected: p = "protected"; break; | |
450 case PROTexport: p = "export"; break; | |
451 default: p = NULL; break; | |
452 } | |
453 if (p) | |
454 buf->printf("%s ", p); | |
455 } | |
456 | |
457 void Dsymbol::emitComment(Scope *sc) { } | |
458 void InvariantDeclaration::emitComment(Scope *sc) { } | |
336 | 459 #if DMDV2 |
460 void PostBlitDeclaration::emitComment(Scope *sc) { } | |
461 #endif | |
159 | 462 void DtorDeclaration::emitComment(Scope *sc) { } |
463 void StaticCtorDeclaration::emitComment(Scope *sc) { } | |
464 void StaticDtorDeclaration::emitComment(Scope *sc) { } | |
465 void ClassInfoDeclaration::emitComment(Scope *sc) { } | |
466 void ModuleInfoDeclaration::emitComment(Scope *sc) { } | |
467 void TypeInfoDeclaration::emitComment(Scope *sc) { } | |
468 | |
469 | |
470 void Declaration::emitComment(Scope *sc) | |
471 { | |
472 //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); | |
473 //printf("type = %p\n", type); | |
474 | |
475 if (protection == PROTprivate || !ident || | |
476 (!type && !isCtorDeclaration() && !isAliasDeclaration())) | |
477 return; | |
478 if (!comment) | |
479 return; | |
480 | |
481 OutBuffer *buf = sc->docbuf; | |
482 DocComment *dc = DocComment::parse(sc, this, comment); | |
483 unsigned o; | |
484 | |
485 if (!dc) | |
486 { | |
487 emitDitto(sc); | |
488 return; | |
489 } | |
490 dc->pmacrotable = &sc->module->macrotable; | |
491 | |
492 buf->writestring(ddoc_decl_s); | |
493 o = buf->offset; | |
494 toDocBuffer(buf); | |
495 highlightCode(sc, this, buf, o); | |
496 sc->lastoffset = buf->offset; | |
497 buf->writestring(ddoc_decl_e); | |
498 | |
499 buf->writestring(ddoc_decl_dd_s); | |
500 dc->writeSections(sc, this, buf); | |
501 buf->writestring(ddoc_decl_dd_e); | |
502 } | |
503 | |
504 void AggregateDeclaration::emitComment(Scope *sc) | |
505 { | |
506 //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); | |
507 if (prot() == PROTprivate) | |
508 return; | |
509 if (!comment) | |
510 return; | |
511 | |
512 OutBuffer *buf = sc->docbuf; | |
513 DocComment *dc = DocComment::parse(sc, this, comment); | |
514 | |
515 if (!dc) | |
516 { | |
517 emitDitto(sc); | |
518 return; | |
519 } | |
520 dc->pmacrotable = &sc->module->macrotable; | |
521 | |
522 buf->writestring(ddoc_decl_s); | |
523 toDocBuffer(buf); | |
524 sc->lastoffset = buf->offset; | |
525 buf->writestring(ddoc_decl_e); | |
526 | |
527 buf->writestring(ddoc_decl_dd_s); | |
528 dc->writeSections(sc, this, buf); | |
529 emitMemberComments(sc); | |
530 buf->writestring(ddoc_decl_dd_e); | |
531 } | |
532 | |
533 void TemplateDeclaration::emitComment(Scope *sc) | |
534 { | |
535 //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); | |
536 if (prot() == PROTprivate) | |
537 return; | |
538 | |
336 | 539 unsigned char *com = comment; |
159 | 540 int hasmembers = 1; |
541 | |
542 Dsymbol *ss = this; | |
543 | |
544 if (onemember) | |
545 { | |
546 ss = onemember->isAggregateDeclaration(); | |
547 if (!ss) | |
548 { | |
549 ss = onemember->isFuncDeclaration(); | |
550 if (ss) | |
336 | 551 { hasmembers = 0; |
552 if (com != ss->comment) | |
553 com = Lexer::combineComments(com, ss->comment); | |
554 } | |
159 | 555 else |
556 ss = this; | |
557 } | |
558 } | |
559 | |
336 | 560 if (!com) |
561 return; | |
562 | |
563 OutBuffer *buf = sc->docbuf; | |
564 DocComment *dc = DocComment::parse(sc, this, com); | |
565 unsigned o; | |
566 | |
159 | 567 if (!dc) |
568 { | |
569 ss->emitDitto(sc); | |
570 return; | |
571 } | |
572 dc->pmacrotable = &sc->module->macrotable; | |
573 | |
574 buf->writestring(ddoc_decl_s); | |
575 o = buf->offset; | |
576 ss->toDocBuffer(buf); | |
577 if (ss == this) | |
578 highlightCode(sc, this, buf, o); | |
579 sc->lastoffset = buf->offset; | |
580 buf->writestring(ddoc_decl_e); | |
581 | |
582 buf->writestring(ddoc_decl_dd_s); | |
583 dc->writeSections(sc, this, buf); | |
584 if (hasmembers) | |
585 ((ScopeDsymbol *)ss)->emitMemberComments(sc); | |
586 buf->writestring(ddoc_decl_dd_e); | |
587 } | |
588 | |
589 void EnumDeclaration::emitComment(Scope *sc) | |
590 { | |
591 if (prot() == PROTprivate) | |
592 return; | |
593 // if (!comment) | |
594 { if (isAnonymous() && members) | |
595 { | |
596 for (int i = 0; i < members->dim; i++) | |
597 { | |
598 Dsymbol *s = (Dsymbol *)members->data[i]; | |
599 s->emitComment(sc); | |
600 } | |
601 return; | |
602 } | |
603 } | |
604 if (!comment) | |
605 return; | |
606 if (isAnonymous()) | |
607 return; | |
608 | |
609 OutBuffer *buf = sc->docbuf; | |
610 DocComment *dc = DocComment::parse(sc, this, comment); | |
611 | |
612 if (!dc) | |
613 { | |
614 emitDitto(sc); | |
615 return; | |
616 } | |
617 dc->pmacrotable = &sc->module->macrotable; | |
618 | |
619 buf->writestring(ddoc_decl_s); | |
620 toDocBuffer(buf); | |
621 sc->lastoffset = buf->offset; | |
622 buf->writestring(ddoc_decl_e); | |
623 | |
624 buf->writestring(ddoc_decl_dd_s); | |
625 dc->writeSections(sc, this, buf); | |
626 emitMemberComments(sc); | |
627 buf->writestring(ddoc_decl_dd_e); | |
628 } | |
629 | |
630 void EnumMember::emitComment(Scope *sc) | |
631 { | |
632 //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); | |
633 if (prot() == PROTprivate) | |
634 return; | |
635 if (!comment) | |
636 return; | |
637 | |
638 OutBuffer *buf = sc->docbuf; | |
639 DocComment *dc = DocComment::parse(sc, this, comment); | |
640 unsigned o; | |
641 | |
642 if (!dc) | |
643 { | |
644 emitDitto(sc); | |
645 return; | |
646 } | |
647 dc->pmacrotable = &sc->module->macrotable; | |
648 | |
649 buf->writestring(ddoc_decl_s); | |
650 o = buf->offset; | |
651 toDocBuffer(buf); | |
652 highlightCode(sc, this, buf, o); | |
653 sc->lastoffset = buf->offset; | |
654 buf->writestring(ddoc_decl_e); | |
655 | |
656 buf->writestring(ddoc_decl_dd_s); | |
657 dc->writeSections(sc, this, buf); | |
658 buf->writestring(ddoc_decl_dd_e); | |
659 } | |
660 | |
661 /******************************* toDocBuffer **********************************/ | |
662 | |
663 void Dsymbol::toDocBuffer(OutBuffer *buf) | |
664 { | |
665 //printf("Dsymbol::toDocbuffer() %s\n", toChars()); | |
666 HdrGenState hgs; | |
667 | |
668 hgs.ddoc = 1; | |
669 toCBuffer(buf, &hgs); | |
670 } | |
671 | |
672 void prefix(OutBuffer *buf, Dsymbol *s) | |
673 { | |
674 if (s->isDeprecated()) | |
675 buf->writestring("deprecated "); | |
676 Declaration *d = s->isDeclaration(); | |
677 if (d) | |
678 { | |
679 emitProtection(buf, d->protection); | |
680 if (d->isAbstract()) | |
681 buf->writestring("abstract "); | |
682 if (d->isStatic()) | |
683 buf->writestring("static "); | |
684 if (d->isConst()) | |
685 buf->writestring("const "); | |
336 | 686 #if DMDV2 |
159 | 687 if (d->isInvariant()) |
688 buf->writestring("invariant "); | |
689 #endif | |
690 if (d->isFinal()) | |
691 buf->writestring("final "); | |
692 if (d->isSynchronized()) | |
693 buf->writestring("synchronized "); | |
694 } | |
695 } | |
696 | |
697 void Declaration::toDocBuffer(OutBuffer *buf) | |
698 { | |
699 //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); | |
700 if (ident) | |
701 { | |
702 prefix(buf, this); | |
703 | |
704 if (type) | |
705 { HdrGenState hgs; | |
706 hgs.ddoc = 1; | |
707 if (originalType) | |
708 { //originalType->print(); | |
709 originalType->toCBuffer(buf, ident, &hgs); | |
710 } | |
711 else | |
712 type->toCBuffer(buf, ident, &hgs); | |
713 } | |
714 else | |
715 buf->writestring(ident->toChars()); | |
716 buf->writestring(";\n"); | |
717 } | |
718 } | |
719 | |
720 | |
721 void AliasDeclaration::toDocBuffer(OutBuffer *buf) | |
722 { | |
723 //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); | |
724 if (ident) | |
725 { | |
726 if (isDeprecated()) | |
727 buf->writestring("deprecated "); | |
728 | |
729 emitProtection(buf, protection); | |
730 buf->writestring("alias "); | |
731 buf->writestring(toChars()); | |
732 buf->writestring(";\n"); | |
733 } | |
734 } | |
735 | |
736 | |
737 void TypedefDeclaration::toDocBuffer(OutBuffer *buf) | |
738 { | |
739 if (ident) | |
740 { | |
741 if (isDeprecated()) | |
742 buf->writestring("deprecated "); | |
743 | |
744 emitProtection(buf, protection); | |
745 buf->writestring("typedef "); | |
746 buf->writestring(toChars()); | |
747 buf->writestring(";\n"); | |
748 } | |
749 } | |
750 | |
751 | |
752 void FuncDeclaration::toDocBuffer(OutBuffer *buf) | |
753 { | |
754 //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); | |
755 if (ident) | |
756 { | |
757 TemplateDeclaration *td; | |
758 | |
759 if (parent && | |
760 (td = parent->isTemplateDeclaration()) != NULL && | |
761 td->onemember == this) | |
336 | 762 { /* It's a function template |
763 */ | |
764 HdrGenState hgs; | |
159 | 765 unsigned o = buf->offset; |
766 TypeFunction *tf = (TypeFunction *)type; | |
767 | |
768 hgs.ddoc = 1; | |
769 prefix(buf, td); | |
770 tf->next->toCBuffer(buf, NULL, &hgs); | |
771 buf->writeByte(' '); | |
772 buf->writestring(ident->toChars()); | |
773 buf->writeByte('('); | |
774 for (int i = 0; i < td->origParameters->dim; i++) | |
775 { | |
776 TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i]; | |
777 if (i) | |
510
6aee82889553
Merged DMD 1.034, array operations are not yet implemented ;)
Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
parents:
336
diff
changeset
|
778 buf->writestring(", "); |
159 | 779 tp->toCBuffer(buf, &hgs); |
780 } | |
781 buf->writeByte(')'); | |
782 Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); | |
783 buf->writestring(";\n"); | |
784 | |
785 highlightCode(NULL, this, buf, o); | |
786 } | |
787 else | |
788 { | |
789 Declaration::toDocBuffer(buf); | |
790 } | |
791 } | |
792 } | |
793 | |
794 void CtorDeclaration::toDocBuffer(OutBuffer *buf) | |
795 { | |
796 HdrGenState hgs; | |
797 | |
798 buf->writestring("this"); | |
799 Argument::argsToCBuffer(buf, &hgs, arguments, varargs); | |
800 buf->writestring(";\n"); | |
801 } | |
802 | |
803 | |
804 void AggregateDeclaration::toDocBuffer(OutBuffer *buf) | |
805 { | |
806 if (ident) | |
807 { | |
808 #if 0 | |
809 emitProtection(buf, protection); | |
810 #endif | |
811 buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); | |
812 buf->writestring(";\n"); | |
813 } | |
814 } | |
815 | |
816 void StructDeclaration::toDocBuffer(OutBuffer *buf) | |
817 { | |
818 //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); | |
819 if (ident) | |
820 { | |
821 #if 0 | |
822 emitProtection(buf, protection); | |
823 #endif | |
824 TemplateDeclaration *td; | |
825 | |
826 if (parent && | |
827 (td = parent->isTemplateDeclaration()) != NULL && | |
828 td->onemember == this) | |
829 { unsigned o = buf->offset; | |
830 td->toDocBuffer(buf); | |
831 highlightCode(NULL, this, buf, o); | |
832 } | |
833 else | |
834 { | |
835 buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); | |
836 } | |
837 buf->writestring(";\n"); | |
838 } | |
839 } | |
840 | |
841 void ClassDeclaration::toDocBuffer(OutBuffer *buf) | |
842 { | |
843 //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); | |
844 if (ident) | |
845 { | |
846 #if 0 | |
847 emitProtection(buf, protection); | |
848 #endif | |
849 TemplateDeclaration *td; | |
850 | |
851 if (parent && | |
852 (td = parent->isTemplateDeclaration()) != NULL && | |
853 td->onemember == this) | |
854 { unsigned o = buf->offset; | |
855 td->toDocBuffer(buf); | |
856 highlightCode(NULL, this, buf, o); | |
857 } | |
858 else | |
859 { | |
860 buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); | |
861 } | |
862 int any = 0; | |
863 for (int i = 0; i < baseclasses.dim; i++) | |
864 { BaseClass *bc = (BaseClass *)baseclasses.data[i]; | |
865 | |
866 if (bc->protection == PROTprivate) | |
867 continue; | |
868 if (bc->base && bc->base->ident == Id::Object) | |
869 continue; | |
870 | |
871 if (any) | |
872 buf->writestring(", "); | |
873 else | |
874 { buf->writestring(": "); | |
875 any = 1; | |
876 } | |
877 emitProtection(buf, bc->protection); | |
878 if (bc->base) | |
879 { | |
880 buf->writestring(bc->base->toPrettyChars()); | |
881 } | |
882 else | |
883 { | |
884 HdrGenState hgs; | |
885 bc->type->toCBuffer(buf, NULL, &hgs); | |
886 } | |
887 } | |
888 buf->writestring(";\n"); | |
889 } | |
890 } | |
891 | |
892 | |
893 void EnumDeclaration::toDocBuffer(OutBuffer *buf) | |
894 { | |
895 if (ident) | |
896 { | |
897 buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); | |
898 buf->writestring(";\n"); | |
899 } | |
900 } | |
901 | |
902 void EnumMember::toDocBuffer(OutBuffer *buf) | |
903 { | |
904 if (ident) | |
905 { | |
906 buf->writestring(toChars()); | |
907 } | |
908 } | |
909 | |
910 | |
911 /********************************* DocComment *********************************/ | |
912 | |
913 DocComment::DocComment() | |
914 { | |
915 memset(this, 0, sizeof(DocComment)); | |
916 } | |
917 | |
918 DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) | |
919 { unsigned idlen; | |
920 | |
921 if (sc->lastdc && isDitto(comment)) | |
922 return NULL; | |
923 | |
924 DocComment *dc = new DocComment(); | |
925 if (!comment) | |
926 return dc; | |
927 | |
928 dc->parseSections(comment); | |
929 | |
930 for (int i = 0; i < dc->sections.dim; i++) | |
931 { Section *s = (Section *)dc->sections.data[i]; | |
932 | |
933 if (icmp("copyright", s->name, s->namelen) == 0) | |
934 { | |
935 dc->copyright = s; | |
936 } | |
937 if (icmp("macros", s->name, s->namelen) == 0) | |
938 { | |
939 dc->macros = s; | |
940 } | |
941 } | |
942 | |
943 sc->lastdc = dc; | |
944 return dc; | |
945 } | |
946 | |
947 /***************************************** | |
948 * Parse next paragraph out of *pcomment. | |
949 * Update *pcomment to point past paragraph. | |
950 * Returns NULL if no more paragraphs. | |
951 * If paragraph ends in 'identifier:', | |
952 * then (*pcomment)[0 .. idlen] is the identifier. | |
953 */ | |
954 | |
955 void DocComment::parseSections(unsigned char *comment) | |
956 { unsigned char *p; | |
957 unsigned char *pstart; | |
958 unsigned char *pend; | |
959 unsigned char *q; | |
960 unsigned char *idstart; | |
961 unsigned idlen; | |
962 | |
963 unsigned char *name = NULL; | |
964 unsigned namelen = 0; | |
965 | |
966 p = comment; | |
967 while (*p) | |
968 { | |
969 p = skipwhitespace(p); | |
970 pstart = p; | |
971 | |
972 /* Find end of section, which is ended by one of: | |
973 * 'identifier:' | |
974 * '\0' | |
975 */ | |
976 idlen = 0; | |
977 while (1) | |
978 { | |
979 if (isalpha(*p) || *p == '_') | |
980 { | |
981 q = p + 1; | |
982 while (isalnum(*q) || *q == '_') | |
983 q++; | |
984 if (*q == ':') // identifier: ends it | |
985 { idlen = q - p; | |
986 idstart = p; | |
987 for (pend = p; pend > pstart; pend--) | |
988 { if (pend[-1] == '\n') | |
989 break; | |
990 } | |
991 p = q + 1; | |
992 break; | |
993 } | |
994 } | |
995 while (1) | |
996 { | |
997 if (!*p) | |
998 { pend = p; | |
999 goto L1; | |
1000 } | |
1001 if (*p == '\n') | |
1002 { p++; | |
1003 if (*p == '\n' && !summary && !namelen) | |
1004 { | |
1005 pend = p; | |
1006 p++; | |
1007 goto L1; | |
1008 } | |
1009 break; | |
1010 } | |
1011 p++; | |
1012 } | |
1013 p = skipwhitespace(p); | |
1014 } | |
1015 L1: | |
1016 | |
1017 if (namelen || pstart < pend) | |
1018 { | |
1019 Section *s; | |
1020 if (icmp("Params", name, namelen) == 0) | |
1021 s = new ParamSection(); | |
1022 else if (icmp("Macros", name, namelen) == 0) | |
1023 s = new MacroSection(); | |
1024 else | |
1025 s = new Section(); | |
1026 s->name = name; | |
1027 s->namelen = namelen; | |
1028 s->body = pstart; | |
1029 s->bodylen = pend - pstart; | |
1030 s->nooutput = 0; | |
1031 | |
1032 //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); | |
1033 | |
1034 sections.push(s); | |
1035 | |
1036 if (!summary && !namelen) | |
1037 summary = s; | |
1038 } | |
1039 | |
1040 if (idlen) | |
1041 { name = idstart; | |
1042 namelen = idlen; | |
1043 } | |
1044 else | |
1045 { name = NULL; | |
1046 namelen = 0; | |
1047 if (!*p) | |
1048 break; | |
1049 } | |
1050 } | |
1051 } | |
1052 | |
1053 void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) | |
1054 { | |
1055 //printf("DocComment::writeSections()\n"); | |
1056 if (sections.dim) | |
1057 { | |
1058 buf->writestring("$(DDOC_SECTIONS \n"); | |
1059 for (int i = 0; i < sections.dim; i++) | |
1060 { Section *sec = (Section *)sections.data[i]; | |
1061 | |
1062 if (sec->nooutput) | |
1063 continue; | |
1064 //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); | |
1065 if (sec->namelen || i) | |
1066 sec->write(this, sc, s, buf); | |
1067 else | |
1068 { | |
1069 buf->writestring("$(DDOC_SUMMARY "); | |
1070 unsigned o = buf->offset; | |
1071 buf->write(sec->body, sec->bodylen); | |
1072 highlightText(sc, s, buf, o); | |
1073 buf->writestring(")\n"); | |
1074 } | |
1075 } | |
1076 buf->writestring(")\n"); | |
1077 } | |
1078 else | |
1079 { | |
1080 buf->writestring("$(DDOC_BLANKLINE)\n"); | |
1081 } | |
1082 } | |
1083 | |
1084 /*************************************************** | |
1085 */ | |
1086 | |
1087 void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) | |
1088 { | |
1089 if (namelen) | |
1090 { | |
1091 static char *table[] = | |
1092 { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", | |
1093 "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", | |
1094 "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", | |
1095 "VERSION" }; | |
1096 | |
1097 for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) | |
1098 { | |
1099 if (icmp(table[i], name, namelen) == 0) | |
1100 { | |
1101 buf->printf("$(DDOC_%s ", table[i]); | |
1102 goto L1; | |
1103 } | |
1104 } | |
1105 | |
1106 buf->writestring("$(DDOC_SECTION "); | |
1107 // Replace _ characters with spaces | |
1108 buf->writestring("$(DDOC_SECTION_H "); | |
1109 for (unsigned u = 0; u < namelen; u++) | |
1110 { unsigned char c = name[u]; | |
1111 buf->writeByte((c == '_') ? ' ' : c); | |
1112 } | |
1113 buf->writestring(":)\n"); | |
1114 } | |
1115 else | |
1116 { | |
1117 buf->writestring("$(DDOC_DESCRIPTION "); | |
1118 } | |
1119 L1: | |
1120 unsigned o = buf->offset; | |
1121 buf->write(body, bodylen); | |
1122 highlightText(sc, s, buf, o); | |
1123 buf->writestring(")\n"); | |
1124 } | |
1125 | |
1126 /*************************************************** | |
1127 */ | |
1128 | |
1129 void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) | |
1130 { | |
1131 unsigned char *p = body; | |
1132 unsigned len = bodylen; | |
1133 unsigned char *pend = p + len; | |
1134 | |
1135 unsigned char *tempstart; | |
1136 unsigned templen; | |
1137 | |
1138 unsigned char *namestart; | |
1139 unsigned namelen = 0; // !=0 if line continuation | |
1140 | |
1141 unsigned char *textstart; | |
1142 unsigned textlen; | |
1143 | |
1144 unsigned o; | |
1145 Argument *arg; | |
1146 | |
1147 buf->writestring("$(DDOC_PARAMS \n"); | |
1148 while (p < pend) | |
1149 { | |
1150 // Skip to start of macro | |
1151 for (; 1; p++) | |
1152 { | |
1153 switch (*p) | |
1154 { | |
1155 case ' ': | |
1156 case '\t': | |
1157 continue; | |
1158 | |
1159 case '\n': | |
1160 p++; | |
1161 goto Lcont; | |
1162 | |
1163 default: | |
1164 if (!(isalpha(*p) || *p == '_')) | |
1165 { | |
1166 if (namelen) | |
1167 goto Ltext; // continuation of prev macro | |
1168 goto Lskipline; | |
1169 } | |
1170 break; | |
1171 } | |
1172 break; | |
1173 } | |
1174 tempstart = p; | |
1175 | |
1176 while (isalnum(*p) || *p == '_') | |
1177 p++; | |
1178 templen = p - tempstart; | |
1179 | |
1180 while (*p == ' ' || *p == '\t') | |
1181 p++; | |
1182 | |
1183 if (*p != '=') | |
1184 { if (namelen) | |
1185 goto Ltext; // continuation of prev macro | |
1186 goto Lskipline; | |
1187 } | |
1188 p++; | |
1189 | |
1190 if (namelen) | |
1191 { // Output existing param | |
1192 | |
1193 L1: | |
1194 //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); | |
1195 HdrGenState hgs; | |
1196 buf->writestring("$(DDOC_PARAM_ROW "); | |
1197 buf->writestring("$(DDOC_PARAM_ID "); | |
1198 o = buf->offset; | |
1199 arg = isFunctionParameter(s, namestart, namelen); | |
1200 if (arg && arg->type && arg->ident) | |
1201 arg->type->toCBuffer(buf, arg->ident, &hgs); | |
1202 else | |
1203 buf->write(namestart, namelen); | |
1204 highlightCode(sc, s, buf, o); | |
1205 buf->writestring(")\n"); | |
1206 | |
1207 buf->writestring("$(DDOC_PARAM_DESC "); | |
1208 o = buf->offset; | |
1209 buf->write(textstart, textlen); | |
1210 highlightText(sc, s, buf, o); | |
1211 buf->writestring(")"); | |
1212 buf->writestring(")\n"); | |
1213 namelen = 0; | |
1214 if (p >= pend) | |
1215 break; | |
1216 } | |
1217 | |
1218 namestart = tempstart; | |
1219 namelen = templen; | |
1220 | |
1221 while (*p == ' ' || *p == '\t') | |
1222 p++; | |
1223 textstart = p; | |
1224 | |
1225 Ltext: | |
1226 while (*p != '\n') | |
1227 p++; | |
1228 textlen = p - textstart; | |
1229 p++; | |
1230 | |
1231 Lcont: | |
1232 continue; | |
1233 | |
1234 Lskipline: | |
1235 // Ignore this line | |
1236 while (*p++ != '\n') | |
1237 ; | |
1238 } | |
1239 if (namelen) | |
1240 goto L1; // write out last one | |
1241 buf->writestring(")\n"); | |
1242 } | |
1243 | |
1244 /*************************************************** | |
1245 */ | |
1246 | |
1247 void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) | |
1248 { | |
1249 //printf("MacroSection::write()\n"); | |
1250 DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); | |
1251 } | |
1252 | |
1253 /************************************************ | |
1254 * Parse macros out of Macros: section. | |
1255 * Macros are of the form: | |
1256 * name1 = value1 | |
1257 * | |
1258 * name2 = value2 | |
1259 */ | |
1260 | |
1261 void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) | |
1262 { | |
1263 unsigned char *p = m; | |
1264 unsigned len = mlen; | |
1265 unsigned char *pend = p + len; | |
1266 | |
1267 unsigned char *tempstart; | |
1268 unsigned templen; | |
1269 | |
1270 unsigned char *namestart; | |
1271 unsigned namelen = 0; // !=0 if line continuation | |
1272 | |
1273 unsigned char *textstart; | |
1274 unsigned textlen; | |
1275 | |
1276 while (p < pend) | |
1277 { | |
1278 // Skip to start of macro | |
1279 for (; 1; p++) | |
1280 { | |
1281 if (p >= pend) | |
1282 goto Ldone; | |
1283 switch (*p) | |
1284 { | |
1285 case ' ': | |
1286 case '\t': | |
1287 continue; | |
1288 | |
1289 case '\n': | |
1290 p++; | |
1291 goto Lcont; | |
1292 | |
1293 default: | |
1294 if (!(isalpha(*p) || *p == '_')) | |
1295 { | |
1296 if (namelen) | |
1297 goto Ltext; // continuation of prev macro | |
1298 goto Lskipline; | |
1299 } | |
1300 break; | |
1301 } | |
1302 break; | |
1303 } | |
1304 tempstart = p; | |
1305 | |
1306 while (1) | |
1307 { | |
1308 if (p >= pend) | |
1309 goto Ldone; | |
1310 if (!(isalnum(*p) || *p == '_')) | |
1311 break; | |
1312 p++; | |
1313 } | |
1314 templen = p - tempstart; | |
1315 | |
1316 while (1) | |
1317 { | |
1318 if (p >= pend) | |
1319 goto Ldone; | |
1320 if (!(*p == ' ' || *p == '\t')) | |
1321 break; | |
1322 p++; | |
1323 } | |
1324 | |
1325 if (*p != '=') | |
1326 { if (namelen) | |
1327 goto Ltext; // continuation of prev macro | |
1328 goto Lskipline; | |
1329 } | |
1330 p++; | |
1331 if (p >= pend) | |
1332 goto Ldone; | |
1333 | |
1334 if (namelen) | |
1335 { // Output existing macro | |
1336 L1: | |
1337 //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); | |
1338 if (icmp("ESCAPES", namestart, namelen) == 0) | |
1339 parseEscapes(pescapetable, textstart, textlen); | |
1340 else | |
1341 Macro::define(pmacrotable, namestart, namelen, textstart, textlen); | |
1342 namelen = 0; | |
1343 if (p >= pend) | |
1344 break; | |
1345 } | |
1346 | |
1347 namestart = tempstart; | |
1348 namelen = templen; | |
1349 | |
1350 while (p < pend && (*p == ' ' || *p == '\t')) | |
1351 p++; | |
1352 textstart = p; | |
1353 | |
1354 Ltext: | |
1355 while (p < pend && *p != '\n') | |
1356 p++; | |
1357 textlen = p - textstart; | |
1358 | |
1359 // Remove trailing \r if there is one | |
1360 if (p > m && p[-1] == '\r') | |
1361 textlen--; | |
1362 | |
1363 p++; | |
1364 //printf("p = %p, pend = %p\n", p, pend); | |
1365 | |
1366 Lcont: | |
1367 continue; | |
1368 | |
1369 Lskipline: | |
1370 // Ignore this line | |
1371 while (p < pend && *p++ != '\n') | |
1372 ; | |
1373 } | |
1374 Ldone: | |
1375 if (namelen) | |
1376 goto L1; // write out last one | |
1377 } | |
1378 | |
1379 /************************************** | |
1380 * Parse escapes of the form: | |
1381 * /c/string/ | |
1382 * where c is a single character. | |
1383 * Multiple escapes can be separated | |
1384 * by whitespace and/or commas. | |
1385 */ | |
1386 | |
1387 void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) | |
1388 { Escape *escapetable = *pescapetable; | |
1389 | |
1390 if (!escapetable) | |
1391 { escapetable = new Escape; | |
1392 *pescapetable = escapetable; | |
1393 } | |
1394 unsigned char *p = textstart; | |
1395 unsigned char *pend = p + textlen; | |
1396 | |
1397 while (1) | |
1398 { | |
1399 while (1) | |
1400 { | |
1401 if (p + 4 >= pend) | |
1402 return; | |
1403 if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) | |
1404 break; | |
1405 p++; | |
1406 } | |
1407 if (p[0] != '/' || p[2] != '/') | |
1408 return; | |
1409 unsigned char c = p[1]; | |
1410 p += 3; | |
1411 unsigned char *start = p; | |
1412 while (1) | |
1413 { | |
1414 if (p >= pend) | |
1415 return; | |
1416 if (*p == '/') | |
1417 break; | |
1418 p++; | |
1419 } | |
1420 size_t len = p - start; | |
1421 char *s = (char *)memcpy(mem.malloc(len + 1), start, len); | |
1422 s[len] = 0; | |
1423 escapetable->strings[c] = s; | |
1424 //printf("%c = '%s'\n", c, s); | |
1425 p++; | |
1426 } | |
1427 } | |
1428 | |
1429 | |
1430 /****************************************** | |
1431 * Compare 0-terminated string with length terminated string. | |
1432 * Return < 0, ==0, > 0 | |
1433 */ | |
1434 | |
1435 int cmp(char *stringz, void *s, size_t slen) | |
1436 { | |
1437 size_t len1 = strlen(stringz); | |
1438 | |
1439 if (len1 != slen) | |
1440 return len1 - slen; | |
1441 return memcmp(stringz, s, slen); | |
1442 } | |
1443 | |
1444 int icmp(char *stringz, void *s, size_t slen) | |
1445 { | |
1446 size_t len1 = strlen(stringz); | |
1447 | |
1448 if (len1 != slen) | |
1449 return len1 - slen; | |
1450 return memicmp(stringz, (char *)s, slen); | |
1451 } | |
1452 | |
1453 /***************************************** | |
1454 * Return !=0 if comment consists entirely of "ditto". | |
1455 */ | |
1456 | |
1457 int isDitto(unsigned char *comment) | |
1458 { | |
1459 if (comment) | |
1460 { | |
1461 unsigned char *p = skipwhitespace(comment); | |
1462 | |
1463 if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) | |
1464 return 1; | |
1465 } | |
1466 return 0; | |
1467 } | |
1468 | |
1469 /********************************************** | |
1470 * Skip white space. | |
1471 */ | |
1472 | |
1473 unsigned char *skipwhitespace(unsigned char *p) | |
1474 { | |
1475 for (; 1; p++) | |
1476 { switch (*p) | |
1477 { | |
1478 case ' ': | |
1479 case '\t': | |
1480 case '\n': | |
1481 continue; | |
1482 } | |
1483 break; | |
1484 } | |
1485 return p; | |
1486 } | |
1487 | |
1488 | |
1489 /************************************************ | |
1490 * Scan forward to one of: | |
1491 * start of identifier | |
1492 * beginning of next line | |
1493 * end of buf | |
1494 */ | |
1495 | |
1496 unsigned skiptoident(OutBuffer *buf, unsigned i) | |
1497 { | |
1498 for (; i < buf->offset; i++) | |
1499 { | |
1500 // BUG: handle unicode alpha's | |
1501 unsigned char c = buf->data[i]; | |
1502 if (isalpha(c) || c == '_') | |
1503 break; | |
1504 if (c == '\n') | |
1505 break; | |
1506 } | |
1507 return i; | |
1508 } | |
1509 | |
1510 /************************************************ | |
1511 * Scan forward past end of identifier. | |
1512 */ | |
1513 | |
1514 unsigned skippastident(OutBuffer *buf, unsigned i) | |
1515 { | |
1516 for (; i < buf->offset; i++) | |
1517 { | |
1518 // BUG: handle unicode alpha's | |
1519 unsigned char c = buf->data[i]; | |
1520 if (!(isalnum(c) || c == '_')) | |
1521 break; | |
1522 } | |
1523 return i; | |
1524 } | |
1525 | |
1526 | |
1527 /************************************************ | |
1528 * Scan forward past URL starting at i. | |
1529 * We don't want to highlight parts of a URL. | |
1530 * Returns: | |
1531 * i if not a URL | |
1532 * index just past it if it is a URL | |
1533 */ | |
1534 | |
1535 unsigned skippastURL(OutBuffer *buf, unsigned i) | |
1536 { unsigned length = buf->offset - i; | |
1537 unsigned char *p = &buf->data[i]; | |
1538 unsigned j; | |
1539 unsigned sawdot = 0; | |
1540 | |
1541 if (length > 7 && memicmp((char *)p, "http://", 7) == 0) | |
1542 { | |
1543 j = 7; | |
1544 } | |
1545 else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) | |
1546 { | |
1547 j = 8; | |
1548 } | |
1549 else | |
1550 goto Lno; | |
1551 | |
1552 for (; j < length; j++) | |
1553 { unsigned char c = p[j]; | |
1554 if (isalnum(c)) | |
1555 continue; | |
1556 if (c == '-' || c == '_' || c == '?' || | |
1557 c == '=' || c == '%' || c == '&' || | |
1558 c == '/' || c == '+' || c == '#' || | |
1559 c == '~') | |
1560 continue; | |
1561 if (c == '.') | |
1562 { | |
1563 sawdot = 1; | |
1564 continue; | |
1565 } | |
1566 break; | |
1567 } | |
1568 if (sawdot) | |
1569 return i + j; | |
1570 | |
1571 Lno: | |
1572 return i; | |
1573 } | |
1574 | |
1575 | |
1576 /**************************************************** | |
1577 */ | |
1578 | |
1579 int isKeyword(unsigned char *p, unsigned len) | |
1580 { | |
1581 static char *table[] = { "true", "false", "null" }; | |
1582 | |
1583 for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) | |
1584 { | |
1585 if (cmp(table[i], p, len) == 0) | |
1586 return 1; | |
1587 } | |
1588 return 0; | |
1589 } | |
1590 | |
1591 /**************************************************** | |
1592 */ | |
1593 | |
1594 Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) | |
1595 { | |
1596 FuncDeclaration *f = s->isFuncDeclaration(); | |
1597 | |
1598 /* f->type may be NULL for template members. | |
1599 */ | |
1600 if (f && f->type) | |
1601 { | |
336 | 1602 TypeFunction *tf; |
1603 if (f->originalType) | |
1604 { | |
1605 tf = (TypeFunction *)f->originalType; | |
1606 } | |
1607 else | |
1608 tf = (TypeFunction *)f->type; | |
159 | 1609 |
1610 if (tf->parameters) | |
1611 { | |
1612 for (size_t k = 0; k < tf->parameters->dim; k++) | |
1613 { Argument *arg = (Argument *)tf->parameters->data[k]; | |
1614 | |
1615 if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) | |
1616 { | |
1617 return arg; | |
1618 } | |
1619 } | |
1620 } | |
1621 } | |
1622 return NULL; | |
1623 } | |
1624 | |
1625 /************************************************** | |
1626 * Highlight text section. | |
1627 */ | |
1628 | |
1629 void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) | |
1630 { | |
1631 //printf("highlightText()\n"); | |
1632 char *sid = s->ident->toChars(); | |
1633 FuncDeclaration *f = s->isFuncDeclaration(); | |
1634 unsigned char *p; | |
1635 char *se; | |
1636 | |
1637 int leadingBlank = 1; | |
1638 int inCode = 0; | |
1639 int inComment = 0; // in <!-- ... --> comment | |
1640 unsigned iCodeStart; // start of code section | |
1641 | |
1642 unsigned iLineStart = offset; | |
1643 | |
1644 for (unsigned i = offset; i < buf->offset; i++) | |
1645 { unsigned char c = buf->data[i]; | |
1646 | |
1647 Lcont: | |
1648 switch (c) | |
1649 { | |
1650 case ' ': | |
1651 case '\t': | |
1652 break; | |
1653 | |
1654 case '\n': | |
1655 if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" | |
1656 { | |
1657 static char blankline[] = "$(DDOC_BLANKLINE)\n"; | |
1658 | |
1659 i = buf->insert(i, blankline, sizeof(blankline) - 1); | |
1660 } | |
1661 leadingBlank = 1; | |
1662 iLineStart = i + 1; | |
1663 break; | |
1664 | |
1665 case '<': | |
1666 leadingBlank = 0; | |
1667 if (inCode) | |
1668 break; | |
1669 p = &buf->data[i]; | |
1670 | |
1671 // Skip over comments | |
1672 if (p[1] == '!' && p[2] == '-' && p[3] == '-') | |
1673 { unsigned j = i + 4; | |
1674 p += 4; | |
1675 while (1) | |
1676 { | |
1677 if (j == buf->offset) | |
1678 goto L1; | |
1679 if (p[0] == '-' && p[1] == '-' && p[2] == '>') | |
1680 { | |
1681 i = j + 2; // place on closing '>' | |
1682 break; | |
1683 } | |
1684 j++; | |
1685 p++; | |
1686 } | |
1687 break; | |
1688 } | |
1689 | |
1690 // Skip over HTML tag | |
1691 if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) | |
1692 { unsigned j = i + 2; | |
1693 p += 2; | |
1694 while (1) | |
1695 { | |
1696 if (j == buf->offset) | |
1697 goto L1; | |
1698 if (p[0] == '>') | |
1699 { | |
1700 i = j; // place on closing '>' | |
1701 break; | |
1702 } | |
1703 j++; | |
1704 p++; | |
1705 } | |
1706 break; | |
1707 } | |
1708 | |
1709 L1: | |
1710 // Replace '<' with '<' character entity | |
1711 se = Escape::escapeChar('<'); | |
1712 if (se) | |
1713 { size_t len = strlen(se); | |
1714 buf->remove(i, 1); | |
1715 i = buf->insert(i, se, len); | |
1716 i--; // point to ';' | |
1717 } | |
1718 break; | |
1719 | |
1720 case '>': | |
1721 leadingBlank = 0; | |
1722 if (inCode) | |
1723 break; | |
1724 // Replace '>' with '>' character entity | |
1725 se = Escape::escapeChar('>'); | |
1726 if (se) | |
1727 { size_t len = strlen(se); | |
1728 buf->remove(i, 1); | |
1729 i = buf->insert(i, se, len); | |
1730 i--; // point to ';' | |
1731 } | |
1732 break; | |
1733 | |
1734 case '&': | |
1735 leadingBlank = 0; | |
1736 if (inCode) | |
1737 break; | |
1738 p = &buf->data[i]; | |
1739 if (p[1] == '#' || isalpha(p[1])) | |
1740 break; // already a character entity | |
1741 // Replace '&' with '&' character entity | |
1742 se = Escape::escapeChar('&'); | |
1743 if (se) | |
1744 { size_t len = strlen(se); | |
1745 buf->remove(i, 1); | |
1746 i = buf->insert(i, se, len); | |
1747 i--; // point to ';' | |
1748 } | |
1749 break; | |
1750 | |
1751 case '-': | |
1752 /* A line beginning with --- delimits a code section. | |
1753 * inCode tells us if it is start or end of a code section. | |
1754 */ | |
1755 if (leadingBlank) | |
1756 { int istart = i; | |
1757 int eollen = 0; | |
1758 | |
1759 leadingBlank = 0; | |
1760 while (1) | |
1761 { | |
1762 ++i; | |
1763 if (i >= buf->offset) | |
1764 break; | |
1765 c = buf->data[i]; | |
1766 if (c == '\n') | |
1767 { eollen = 1; | |
1768 break; | |
1769 } | |
1770 if (c == '\r') | |
1771 { | |
1772 eollen = 1; | |
1773 if (i + 1 >= buf->offset) | |
1774 break; | |
1775 if (buf->data[i + 1] == '\n') | |
1776 { eollen = 2; | |
1777 break; | |
1778 } | |
1779 } | |
1780 // BUG: handle UTF PS and LS too | |
1781 if (c != '-') | |
1782 goto Lcont; | |
1783 } | |
1784 if (i - istart < 3) | |
1785 goto Lcont; | |
1786 | |
1787 // We have the start/end of a code section | |
1788 | |
1789 // Remove the entire --- line, including blanks and \n | |
1790 buf->remove(iLineStart, i - iLineStart + eollen); | |
1791 i = iLineStart; | |
1792 | |
1793 if (inCode) | |
1794 { | |
1795 inCode = 0; | |
1796 // The code section is from iCodeStart to i | |
1797 OutBuffer codebuf; | |
1798 | |
1799 codebuf.write(buf->data + iCodeStart, i - iCodeStart); | |
1800 codebuf.writeByte(0); | |
1801 highlightCode2(sc, s, &codebuf, 0); | |
1802 buf->remove(iCodeStart, i - iCodeStart); | |
1803 i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); | |
1804 i = buf->insert(i, ")\n", 2); | |
1805 i--; | |
1806 } | |
1807 else | |
1808 { static char pre[] = "$(D_CODE \n"; | |
1809 | |
1810 inCode = 1; | |
1811 i = buf->insert(i, pre, sizeof(pre) - 1); | |
1812 iCodeStart = i; | |
1813 i--; // place i on > | |
1814 } | |
1815 } | |
1816 break; | |
1817 | |
1818 default: | |
1819 leadingBlank = 0; | |
1820 if (sc && !inCode && (isalpha(c) || c == '_')) | |
1821 { unsigned j; | |
1822 | |
1823 j = skippastident(buf, i); | |
1824 if (j > i) | |
1825 { | |
1826 unsigned k = skippastURL(buf, i); | |
1827 if (k > i) | |
1828 { i = k - 1; | |
1829 break; | |
1830 } | |
1831 | |
1832 if (buf->data[i] == '_') // leading '_' means no highlight | |
1833 { | |
1834 buf->remove(i, 1); | |
1835 i = j - 1; | |
1836 } | |
1837 else | |
1838 { | |
1839 if (cmp(sid, buf->data + i, j - i) == 0) | |
1840 { | |
1841 i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; | |
1842 break; | |
1843 } | |
1844 else if (isKeyword(buf->data + i, j - i)) | |
1845 { | |
1846 i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; | |
1847 break; | |
1848 } | |
1849 else | |
1850 { | |
1851 if (f && isFunctionParameter(f, buf->data + i, j - i)) | |
1852 { | |
1853 //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); | |
1854 i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; | |
1855 break; | |
1856 } | |
1857 } | |
1858 i = j - 1; | |
1859 } | |
1860 } | |
1861 } | |
1862 break; | |
1863 } | |
1864 } | |
1865 Ldone: | |
1866 ; | |
1867 } | |
1868 | |
1869 /************************************************** | |
1870 * Highlight code for DDOC section. | |
1871 */ | |
1872 | |
1873 void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) | |
1874 { | |
1875 char *sid = s->ident->toChars(); | |
1876 FuncDeclaration *f = s->isFuncDeclaration(); | |
1877 | |
1878 //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); | |
1879 for (unsigned i = offset; i < buf->offset; i++) | |
1880 { unsigned char c = buf->data[i]; | |
1881 char *se; | |
1882 | |
1883 se = Escape::escapeChar(c); | |
1884 if (se) | |
1885 { | |
1886 size_t len = strlen(se); | |
1887 buf->remove(i, 1); | |
1888 i = buf->insert(i, se, len); | |
1889 i--; // point to ';' | |
1890 } | |
1891 else if (isalpha(c) || c == '_') | |
1892 { unsigned j; | |
1893 | |
1894 j = skippastident(buf, i); | |
1895 if (j > i) | |
1896 { | |
1897 if (cmp(sid, buf->data + i, j - i) == 0) | |
1898 { | |
1899 i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; | |
1900 continue; | |
1901 } | |
1902 else if (f) | |
1903 { | |
1904 if (isFunctionParameter(f, buf->data + i, j - i)) | |
1905 { | |
1906 //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); | |
1907 i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; | |
1908 continue; | |
1909 } | |
1910 } | |
1911 i = j - 1; | |
1912 } | |
1913 } | |
1914 } | |
1915 } | |
1916 | |
1917 /**************************************** | |
1918 */ | |
1919 | |
1920 void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) | |
1921 { | |
1922 for (; p < pend; p++) | |
1923 { char *s = Escape::escapeChar(*p); | |
1924 if (s) | |
1925 buf->writestring(s); | |
1926 else | |
1927 buf->writeByte(*p); | |
1928 } | |
1929 } | |
1930 | |
1931 /************************************************** | |
1932 * Highlight code for CODE section. | |
1933 */ | |
1934 | |
1935 | |
1936 void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) | |
1937 { | |
1938 char *sid = s->ident->toChars(); | |
1939 FuncDeclaration *f = s->isFuncDeclaration(); | |
1940 unsigned errorsave = global.errors; | |
1941 Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); | |
1942 Token tok; | |
1943 OutBuffer res; | |
1944 unsigned char *lastp = buf->data; | |
1945 char *highlight; | |
1946 | |
1947 //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); | |
1948 res.reserve(buf->offset); | |
1949 while (1) | |
1950 { | |
1951 lex.scan(&tok); | |
1952 highlightCode3(&res, lastp, tok.ptr); | |
1953 highlight = NULL; | |
1954 switch (tok.value) | |
1955 { | |
1956 case TOKidentifier: | |
1957 if (!sc) | |
1958 break; | |
1959 if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) | |
1960 { | |
1961 highlight = "$(D_PSYMBOL "; | |
1962 break; | |
1963 } | |
1964 else if (f) | |
1965 { | |
1966 if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) | |
1967 { | |
1968 //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); | |
1969 highlight = "$(D_PARAM "; | |
1970 break; | |
1971 } | |
1972 } | |
1973 break; | |
1974 | |
1975 case TOKcomment: | |
1976 highlight = "$(D_COMMENT "; | |
1977 break; | |
1978 | |
1979 case TOKstring: | |
1980 highlight = "$(D_STRING "; | |
1981 break; | |
1982 | |
1983 default: | |
1984 if (tok.isKeyword()) | |
1985 highlight = "$(D_KEYWORD "; | |
1986 break; | |
1987 } | |
1988 if (highlight) | |
1989 res.writestring(highlight); | |
1990 highlightCode3(&res, tok.ptr, lex.p); | |
1991 if (highlight) | |
1992 res.writeByte(')'); | |
1993 if (tok.value == TOKeof) | |
1994 break; | |
1995 lastp = lex.p; | |
1996 } | |
1997 buf->setsize(offset); | |
1998 buf->write(&res); | |
1999 global.errors = errorsave; | |
2000 } | |
2001 | |
2002 /*************************************** | |
2003 * Find character string to replace c with. | |
2004 */ | |
2005 | |
2006 char *Escape::escapeChar(unsigned c) | |
2007 { char *s; | |
2008 | |
2009 switch (c) | |
2010 { | |
2011 case '<': | |
2012 s = "<"; | |
2013 break; | |
2014 case '>': | |
2015 s = ">"; | |
2016 break; | |
2017 case '&': | |
2018 s = "&"; | |
2019 break; | |
2020 default: | |
2021 s = NULL; | |
2022 break; | |
2023 } | |
2024 return s; | |
2025 } | |
2026 |