Mercurial > projects > ldc
annotate dmd/doc.c @ 690:8526cf626110
Homepage rename.
author | Christian Kamm <kamm incasoftware de> |
---|---|
date | Sun, 12 Oct 2008 18:03:34 +0200 |
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 |