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