Internally these would treat the cast same as a normal conversion from int[7] to int[], which allows code at CTFE to erroneously succeed where it would raise a SEGV at run-time.
1 |
/**
|
|
2 |
* Functions for raising errors.
|
|
3 |
*
|
|
4 |
* Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
|
|
5 |
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
|
|
6 |
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
|
7 |
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d)
|
|
8 |
* Documentation: https://dlang.org/phobos/dmd_errors.html
|
|
9 |
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errors.d
|
|
10 |
*/
|
|
11 |
|
|
12 |
module dmd.errors; |
|
13 |
|
|
14 |
import core.stdc.stdarg; |
|
15 |
import core.stdc.stdio; |
|
16 |
import core.stdc.stdlib; |
|
17 |
import core.stdc.string; |
|
18 |
import dmd.globals; |
|
19 |
import dmd.root.outbuffer; |
|
20 |
import dmd.root.rmem; |
|
21 |
import dmd.root.string; |
|
22 |
import dmd.console; |
|
23 |
|
|
24 |
nothrow: |
|
25 |
|
|
26 |
/**
|
|
27 |
* Color highlighting to classify messages
|
|
28 |
*/
|
|
29 |
enum Classification |
|
30 |
{
|
|
31 |
error = Color.brightRed, /// for errors |
|
32 |
gagged = Color.brightBlue, /// for gagged errors |
|
33 |
warning = Color.brightYellow, /// for warnings |
|
34 |
deprecation = Color.brightCyan, /// for deprecations |
|
35 |
tip = Color.brightGreen, /// for tip messages |
|
36 |
}
|
|
37 |
|
|
38 |
/**
|
|
39 |
* Print an error message, increasing the global error count.
|
|
40 |
* Params:
|
|
41 |
* loc = location of error
|
|
42 |
* format = printf-style format specification
|
|
43 |
* ... = printf-style variadic arguments
|
|
44 |
*/
|
|
45 |
extern (C++) void error(const ref Loc loc, const(char)* format, ...) |
|
46 |
{
|
|
47 | 1 |
va_list ap; |
48 | 1 |
va_start(ap, format); |
49 | 1 |
verror(loc, format, ap); |
50 | 1 |
va_end(ap); |
51 |
}
|
|
52 |
|
|
53 |
/**
|
|
54 |
* Same as above, but allows Loc() literals to be passed.
|
|
55 |
* Params:
|
|
56 |
* loc = location of error
|
|
57 |
* format = printf-style format specification
|
|
58 |
* ... = printf-style variadic arguments
|
|
59 |
*/
|
|
60 |
extern (D) void error(Loc loc, const(char)* format, ...) |
|
61 |
{
|
|
62 |
va_list ap; |
|
63 |
va_start(ap, format); |
|
64 |
verror(loc, format, ap); |
|
65 |
va_end(ap); |
|
66 |
}
|
|
67 |
|
|
68 |
/**
|
|
69 |
* Same as above, but takes a filename and line information arguments as separate parameters.
|
|
70 |
* Params:
|
|
71 |
* filename = source file of error
|
|
72 |
* linnum = line in the source file
|
|
73 |
* charnum = column number on the line
|
|
74 |
* format = printf-style format specification
|
|
75 |
* ... = printf-style variadic arguments
|
|
76 |
*/
|
|
77 |
extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) |
|
78 |
{
|
|
79 | 1 |
const loc = Loc(filename, linnum, charnum); |
80 | 1 |
va_list ap; |
81 | 1 |
va_start(ap, format); |
82 | 1 |
verror(loc, format, ap); |
83 | 1 |
va_end(ap); |
84 |
}
|
|
85 |
|
|
86 |
/**
|
|
87 |
* Print additional details about an error message.
|
|
88 |
* Doesn't increase the error count or print an additional error prefix.
|
|
89 |
* Params:
|
|
90 |
* loc = location of error
|
|
91 |
* format = printf-style format specification
|
|
92 |
* ... = printf-style variadic arguments
|
|
93 |
*/
|
|
94 |
extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...) |
|
95 |
{
|
|
96 | 1 |
va_list ap; |
97 | 1 |
va_start(ap, format); |
98 | 1 |
verrorSupplemental(loc, format, ap); |
99 | 1 |
va_end(ap); |
100 |
}
|
|
101 |
|
|
102 |
/**
|
|
103 |
* Print a warning message, increasing the global warning count.
|
|
104 |
* Params:
|
|
105 |
* loc = location of warning
|
|
106 |
* format = printf-style format specification
|
|
107 |
* ... = printf-style variadic arguments
|
|
108 |
*/
|
|
109 |
extern (C++) void warning(const ref Loc loc, const(char)* format, ...) |
|
110 |
{
|
|
111 | 1 |
va_list ap; |
112 | 1 |
va_start(ap, format); |
113 | 1 |
vwarning(loc, format, ap); |
114 | 1 |
va_end(ap); |
115 |
}
|
|
116 |
|
|
117 |
/**
|
|
118 |
* Print additional details about a warning message.
|
|
119 |
* Doesn't increase the warning count or print an additional warning prefix.
|
|
120 |
* Params:
|
|
121 |
* loc = location of warning
|
|
122 |
* format = printf-style format specification
|
|
123 |
* ... = printf-style variadic arguments
|
|
124 |
*/
|
|
125 |
extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...) |
|
126 |
{
|
|
127 | 1 |
va_list ap; |
128 | 1 |
va_start(ap, format); |
129 | 1 |
vwarningSupplemental(loc, format, ap); |
130 | 1 |
va_end(ap); |
131 |
}
|
|
132 |
|
|
133 |
/**
|
|
134 |
* Print a deprecation message, may increase the global warning or error count
|
|
135 |
* depending on whether deprecations are ignored.
|
|
136 |
* Params:
|
|
137 |
* loc = location of deprecation
|
|
138 |
* format = printf-style format specification
|
|
139 |
* ... = printf-style variadic arguments
|
|
140 |
*/
|
|
141 |
extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...) |
|
142 |
{
|
|
143 | 1 |
va_list ap; |
144 | 1 |
va_start(ap, format); |
145 | 1 |
vdeprecation(loc, format, ap); |
146 | 1 |
va_end(ap); |
147 |
}
|
|
148 |
|
|
149 |
/**
|
|
150 |
* Print additional details about a deprecation message.
|
|
151 |
* Doesn't increase the error count, or print an additional deprecation prefix.
|
|
152 |
* Params:
|
|
153 |
* loc = location of deprecation
|
|
154 |
* format = printf-style format specification
|
|
155 |
* ... = printf-style variadic arguments
|
|
156 |
*/
|
|
157 |
extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) |
|
158 |
{
|
|
159 | 1 |
va_list ap; |
160 | 1 |
va_start(ap, format); |
161 | 1 |
vdeprecationSupplemental(loc, format, ap); |
162 | 1 |
va_end(ap); |
163 |
}
|
|
164 |
|
|
165 |
/**
|
|
166 |
* Print a verbose message.
|
|
167 |
* Doesn't prefix or highlight messages.
|
|
168 |
* Params:
|
|
169 |
* loc = location of message
|
|
170 |
* format = printf-style format specification
|
|
171 |
* ... = printf-style variadic arguments
|
|
172 |
*/
|
|
173 |
extern (C++) void message(const ref Loc loc, const(char)* format, ...) |
|
174 |
{
|
|
175 | 1 |
va_list ap; |
176 | 1 |
va_start(ap, format); |
177 | 1 |
vmessage(loc, format, ap); |
178 | 1 |
va_end(ap); |
179 |
}
|
|
180 |
|
|
181 |
/**
|
|
182 |
* Same as above, but doesn't take a location argument.
|
|
183 |
* Params:
|
|
184 |
* format = printf-style format specification
|
|
185 |
* ... = printf-style variadic arguments
|
|
186 |
*/
|
|
187 |
extern (C++) void message(const(char)* format, ...) |
|
188 |
{
|
|
189 | 1 |
va_list ap; |
190 | 1 |
va_start(ap, format); |
191 | 1 |
vmessage(Loc.initial, format, ap); |
192 | 1 |
va_end(ap); |
193 |
}
|
|
194 |
|
|
195 |
/**
|
|
196 |
* The type of the diagnostic handler
|
|
197 |
* see verrorPrint for arguments
|
|
198 |
* Returns: true if error handling is done, false to continue printing to stderr
|
|
199 |
*/
|
|
200 |
alias DiagnosticHandler = bool delegate(const ref Loc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2); |
|
201 |
|
|
202 |
/**
|
|
203 |
* The diagnostic handler.
|
|
204 |
* If non-null it will be called for every diagnostic message issued by the compiler.
|
|
205 |
* If it returns false, the message will be printed to stderr as usual.
|
|
206 |
*/
|
|
207 |
__gshared DiagnosticHandler diagnosticHandler; |
|
208 |
|
|
209 |
/**
|
|
210 |
* Print a tip message with the prefix and highlighting.
|
|
211 |
* Params:
|
|
212 |
* format = printf-style format specification
|
|
213 |
* ... = printf-style variadic arguments
|
|
214 |
*/
|
|
215 |
extern (C++) void tip(const(char)* format, ...) |
|
216 |
{
|
|
217 | 1 |
va_list ap; |
218 | 1 |
va_start(ap, format); |
219 | 1 |
vtip(format, ap); |
220 | 1 |
va_end(ap); |
221 |
}
|
|
222 |
|
|
223 |
/**
|
|
224 |
* Just print to stderr, doesn't care about gagging.
|
|
225 |
* (format,ap) text within backticks gets syntax highlighted.
|
|
226 |
* Params:
|
|
227 |
* loc = location of error
|
|
228 |
* headerColor = color to set `header` output to
|
|
229 |
* header = title of error message
|
|
230 |
* format = printf-style format specification
|
|
231 |
* ap = printf-style variadic arguments
|
|
232 |
* p1 = additional message prefix
|
|
233 |
* p2 = additional message prefix
|
|
234 |
*/
|
|
235 |
private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* header, |
|
236 |
const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) |
|
237 |
{
|
|
238 | 1 |
if (diagnosticHandler && diagnosticHandler(loc, headerColor, header, format, ap, p1, p2)) |
239 |
return; |
|
240 |
|
|
241 | 1 |
if (global.params.showGaggedErrors && global.gag) |
242 | 1 |
fprintf(stderr, "(spec:%d) ", global.gag); |
243 | 1 |
Console* con = cast(Console*)global.console; |
244 | 1 |
const p = loc.toChars(); |
245 | 1 |
if (con) |
246 | 1 |
con.setColorBright(true); |
247 | 1 |
if (*p) |
248 |
{
|
|
249 | 1 |
fprintf(stderr, "%s: ", p); |
250 | 1 |
mem.xfree(cast(void*)p); |
251 |
}
|
|
252 | 1 |
if (con) |
253 | 1 |
con.setColor(headerColor); |
254 | 1 |
fputs(header, stderr); |
255 | 1 |
if (con) |
256 | 1 |
con.resetColor(); |
257 | 1 |
OutBuffer tmp; |
258 | 1 |
if (p1) |
259 |
{
|
|
260 | 1 |
tmp.writestring(p1); |
261 | 1 |
tmp.writestring(" "); |
262 |
}
|
|
263 | 1 |
if (p2) |
264 |
{
|
|
265 | 1 |
tmp.writestring(p2); |
266 | 1 |
tmp.writestring(" "); |
267 |
}
|
|
268 | 1 |
tmp.vprintf(format, ap); |
269 |
|
|
270 | 1 |
if (con && strchr(tmp.peekChars(), '`')) |
271 |
{
|
|
272 | 1 |
colorSyntaxHighlight(tmp); |
273 | 1 |
writeHighlights(con, tmp); |
274 |
}
|
|
275 |
else
|
|
276 | 1 |
fputs(tmp.peekChars(), stderr); |
277 | 1 |
fputc('\n', stderr); |
278 |
|
|
279 | 1 |
if (global.params.printErrorContext && |
280 |
// ignore invalid files
|
|
281 | 1 |
loc != Loc.initial && |
282 |
// ignore mixins for now
|
|
283 | 1 |
!loc.filename.strstr(".d-mixin-") && |
284 | 1 |
!global.params.mixinOut) |
285 |
{
|
|
286 |
import dmd.filecache : FileCache; |
|
287 | 1 |
auto fllines = FileCache.fileCache.addOrGetFile(loc.filename.toDString()); |
288 |
|
|
289 | 1 |
if (loc.linnum - 1 < fllines.lines.length) |
290 |
{
|
|
291 | 1 |
auto line = fllines.lines[loc.linnum - 1]; |
292 | 1 |
if (loc.charnum < line.length) |
293 |
{
|
|
294 | 1 |
fprintf(stderr, "%.*s\n", cast(int)line.length, line.ptr); |
295 | 1 |
foreach (_; 1 .. loc.charnum) |
296 | 1 |
fputc(' ', stderr); |
297 |
|
|
298 | 1 |
fputc('^', stderr); |
299 | 1 |
fputc('\n', stderr); |
300 |
}
|
|
301 |
}
|
|
302 |
}
|
|
303 | 1 |
fflush(stderr); // ensure it gets written out in case of compiler aborts |
304 |
}
|
|
305 |
|
|
306 |
/**
|
|
307 |
* Same as $(D error), but takes a va_list parameter, and optionally additional message prefixes.
|
|
308 |
* Params:
|
|
309 |
* loc = location of error
|
|
310 |
* format = printf-style format specification
|
|
311 |
* ap = printf-style variadic arguments
|
|
312 |
* p1 = additional message prefix
|
|
313 |
* p2 = additional message prefix
|
|
314 |
* header = title of error message
|
|
315 |
*/
|
|
316 |
extern (C++) void verror(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null, const(char)* header = "Error: ") |
|
317 |
{
|
|
318 | 1 |
global.errors++; |
319 | 1 |
if (!global.gag) |
320 |
{
|
|
321 | 1 |
verrorPrint(loc, Classification.error, header, format, ap, p1, p2); |
322 | 1 |
if (global.params.errorLimit && global.errors >= global.params.errorLimit) |
323 | 1 |
fatal(); // moderate blizzard of cascading messages |
324 |
}
|
|
325 |
else
|
|
326 |
{
|
|
327 | 1 |
if (global.params.showGaggedErrors) |
328 | 1 |
verrorPrint(loc, Classification.gagged, header, format, ap, p1, p2); |
329 | 1 |
global.gaggedErrors++; |
330 |
}
|
|
331 |
}
|
|
332 |
|
|
333 |
/**
|
|
334 |
* Same as $(D errorSupplemental), but takes a va_list parameter.
|
|
335 |
* Params:
|
|
336 |
* loc = location of error
|
|
337 |
* format = printf-style format specification
|
|
338 |
* ap = printf-style variadic arguments
|
|
339 |
*/
|
|
340 |
extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) |
|
341 |
{
|
|
342 | 1 |
Color color; |
343 | 1 |
if (global.gag) |
344 |
{
|
|
345 | 1 |
if (!global.params.showGaggedErrors) |
346 | 1 |
return; |
347 |
color = Classification.gagged; |
|
348 |
}
|
|
349 |
else
|
|
350 | 1 |
color = Classification.error; |
351 | 1 |
verrorPrint(loc, color, " ", format, ap); |
352 |
}
|
|
353 |
|
|
354 |
/**
|
|
355 |
* Same as $(D warning), but takes a va_list parameter.
|
|
356 |
* Params:
|
|
357 |
* loc = location of warning
|
|
358 |
* format = printf-style format specification
|
|
359 |
* ap = printf-style variadic arguments
|
|
360 |
*/
|
|
361 |
extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) |
|
362 |
{
|
|
363 | 1 |
if (global.params.warnings != DiagnosticReporting.off) |
364 |
{
|
|
365 | 1 |
if (!global.gag) |
366 |
{
|
|
367 | 1 |
verrorPrint(loc, Classification.warning, "Warning: ", format, ap); |
368 | 1 |
if (global.params.warnings == DiagnosticReporting.error) |
369 | 1 |
global.warnings++; |
370 |
}
|
|
371 |
else
|
|
372 |
{
|
|
373 |
global.gaggedWarnings++; |
|
374 |
}
|
|
375 |
}
|
|
376 |
}
|
|
377 |
|
|
378 |
/**
|
|
379 |
* Same as $(D warningSupplemental), but takes a va_list parameter.
|
|
380 |
* Params:
|
|
381 |
* loc = location of warning
|
|
382 |
* format = printf-style format specification
|
|
383 |
* ap = printf-style variadic arguments
|
|
384 |
*/
|
|
385 |
extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) |
|
386 |
{
|
|
387 | 1 |
if (global.params.warnings != DiagnosticReporting.off && !global.gag) |
388 | 1 |
verrorPrint(loc, Classification.warning, " ", format, ap); |
389 |
}
|
|
390 |
|
|
391 |
/**
|
|
392 |
* Same as $(D deprecation), but takes a va_list parameter, and optionally additional message prefixes.
|
|
393 |
* Params:
|
|
394 |
* loc = location of deprecation
|
|
395 |
* format = printf-style format specification
|
|
396 |
* ap = printf-style variadic arguments
|
|
397 |
* p1 = additional message prefix
|
|
398 |
* p2 = additional message prefix
|
|
399 |
*/
|
|
400 |
extern (C++) void vdeprecation(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) |
|
401 |
{
|
|
402 | 1 |
__gshared const(char)* header = "Deprecation: "; |
403 | 1 |
if (global.params.useDeprecated == DiagnosticReporting.error) |
404 | 1 |
verror(loc, format, ap, p1, p2, header); |
405 | 1 |
else if (global.params.useDeprecated == DiagnosticReporting.inform) |
406 |
{
|
|
407 | 1 |
if (!global.gag) |
408 |
{
|
|
409 | 1 |
verrorPrint(loc, Classification.deprecation, header, format, ap, p1, p2); |
410 |
}
|
|
411 |
else
|
|
412 |
{
|
|
413 | 1 |
global.gaggedWarnings++; |
414 |
}
|
|
415 |
}
|
|
416 |
}
|
|
417 |
|
|
418 |
/**
|
|
419 |
* Same as $(D message), but takes a va_list parameter.
|
|
420 |
* Params:
|
|
421 |
* loc = location of message
|
|
422 |
* format = printf-style format specification
|
|
423 |
* ap = printf-style variadic arguments
|
|
424 |
*/
|
|
425 |
extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) |
|
426 |
{
|
|
427 | 1 |
const p = loc.toChars(); |
428 | 1 |
if (*p) |
429 |
{
|
|
430 | 1 |
fprintf(stdout, "%s: ", p); |
431 | 1 |
mem.xfree(cast(void*)p); |
432 |
}
|
|
433 | 1 |
OutBuffer tmp; |
434 | 1 |
tmp.vprintf(format, ap); |
435 | 1 |
fputs(tmp.peekChars(), stdout); |
436 | 1 |
fputc('\n', stdout); |
437 | 1 |
fflush(stdout); // ensure it gets written out in case of compiler aborts |
438 |
}
|
|
439 |
|
|
440 |
/**
|
|
441 |
* Same as $(D tip), but takes a va_list parameter.
|
|
442 |
* Params:
|
|
443 |
* format = printf-style format specification
|
|
444 |
* ap = printf-style variadic arguments
|
|
445 |
*/
|
|
446 |
extern (C++) void vtip(const(char)* format, va_list ap) |
|
447 |
{
|
|
448 | 1 |
if (!global.gag) |
449 |
{
|
|
450 | 1 |
Loc loc = Loc.init; |
451 | 1 |
verrorPrint(loc, Classification.tip, " Tip: ", format, ap); |
452 |
}
|
|
453 |
}
|
|
454 |
|
|
455 |
/**
|
|
456 |
* Same as $(D deprecationSupplemental), but takes a va_list parameter.
|
|
457 |
* Params:
|
|
458 |
* loc = location of deprecation
|
|
459 |
* format = printf-style format specification
|
|
460 |
* ap = printf-style variadic arguments
|
|
461 |
*/
|
|
462 |
extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) |
|
463 |
{
|
|
464 | 1 |
if (global.params.useDeprecated == DiagnosticReporting.error) |
465 | 1 |
verrorSupplemental(loc, format, ap); |
466 |
else if (global.params.useDeprecated == DiagnosticReporting.inform && !global.gag) |
|
467 |
verrorPrint(loc, Classification.deprecation, " ", format, ap); |
|
468 |
}
|
|
469 |
|
|
470 |
/**
|
|
471 |
* Call this after printing out fatal error messages to clean up and exit
|
|
472 |
* the compiler.
|
|
473 |
*/
|
|
474 |
extern (C++) void fatal() |
|
475 |
{
|
|
476 |
version (none) |
|
477 |
{
|
|
478 |
halt(); |
|
479 |
}
|
|
480 | 1 |
exit(EXIT_FAILURE); |
481 |
}
|
|
482 |
|
|
483 |
/**
|
|
484 |
* Try to stop forgetting to remove the breakpoints from
|
|
485 |
* release builds.
|
|
486 |
*/
|
|
487 |
extern (C++) void halt() |
|
488 |
{
|
|
489 |
assert(0); |
|
490 |
}
|
|
491 |
|
|
492 |
/**
|
|
493 |
* Scan characters in `buf`. Assume text enclosed by `...`
|
|
494 |
* is D source code, and color syntax highlight it.
|
|
495 |
* Modify contents of `buf` with highlighted result.
|
|
496 |
* Many parallels to ddoc.highlightText().
|
|
497 |
* Params:
|
|
498 |
* buf = text containing `...` code to highlight
|
|
499 |
*/
|
|
500 |
private void colorSyntaxHighlight(ref OutBuffer buf) |
|
501 |
{
|
|
502 |
//printf("colorSyntaxHighlight('%.*s')\n", cast(int)buf.length, buf.data);
|
|
503 | 1 |
bool inBacktick = false; |
504 | 1 |
size_t iCodeStart = 0; |
505 | 1 |
size_t offset = 0; |
506 | 1 |
for (size_t i = offset; i < buf.length; ++i) |
507 |
{
|
|
508 | 1 |
char c = buf[i]; |
509 | 1 |
switch (c) |
510 |
{
|
|
511 | 1 |
case '`': |
512 | 1 |
if (inBacktick) |
513 |
{
|
|
514 | 1 |
inBacktick = false; |
515 | 1 |
OutBuffer codebuf; |
516 | 1 |
codebuf.write(buf[iCodeStart + 1 .. i]); |
517 | 1 |
codebuf.writeByte(0); |
518 |
// escape the contents, but do not perform highlighting except for DDOC_PSYMBOL
|
|
519 | 1 |
colorHighlightCode(codebuf); |
520 | 1 |
buf.remove(iCodeStart, i - iCodeStart + 1); // also trimming off the current ` |
521 | 1 |
immutable pre = ""; |
522 | 1 |
i = buf.insert(iCodeStart, pre); |
523 | 1 |
i = buf.insert(i, codebuf[]); |
524 | 1 |
i--; // point to the ending ) so when the for loop does i++, it will see the next character |
525 | 1 |
break; |
526 |
}
|
|
527 | 1 |
inBacktick = true; |
528 | 1 |
iCodeStart = i; |
529 | 1 |
break; |
530 |
|
|
531 | 1 |
default: |
532 | 1 |
break; |
533 |
}
|
|
534 |
}
|
|
535 |
}
|
|
536 |
|
|
537 |
|
|
538 |
/**
|
|
539 |
* Embed these highlighting commands in the text stream.
|
|
540 |
* HIGHLIGHT.Escape indicates a Color follows.
|
|
541 |
*/
|
|
542 |
enum HIGHLIGHT : ubyte |
|
543 |
{
|
|
544 |
Default = Color.black, // back to whatever the console is set at |
|
545 |
Escape = '\xFF', // highlight Color follows |
|
546 |
Identifier = Color.white, |
|
547 |
Keyword = Color.white, |
|
548 |
Literal = Color.white, |
|
549 |
Comment = Color.darkGray, |
|
550 |
Other = Color.cyan, // other tokens |
|
551 |
}
|
|
552 |
|
|
553 |
/**
|
|
554 |
* Highlight code for CODE section.
|
|
555 |
* Rewrite the contents of `buf` with embedded highlights.
|
|
556 |
* Analogous to doc.highlightCode2()
|
|
557 |
*/
|
|
558 |
|
|
559 |
private void colorHighlightCode(ref OutBuffer buf) |
|
560 |
{
|
|
561 |
import dmd.lexer; |
|
562 |
import dmd.tokens; |
|
563 |
|
|
564 | 1 |
__gshared int nested; |
565 | 1 |
if (nested) |
566 |
{
|
|
567 |
// Should never happen, but don't infinitely recurse if it does
|
|
568 |
--nested; |
|
569 |
return; |
|
570 |
}
|
|
571 | 1 |
++nested; |
572 |
|
|
573 | 1 |
auto gaggedErrorsSave = global.startGagging(); |
574 | 1 |
scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1); |
575 | 1 |
OutBuffer res; |
576 | 1 |
const(char)* lastp = cast(char*)buf[].ptr; |
577 |
//printf("colorHighlightCode('%.*s')\n", cast(int)(buf.length - 1), buf.data);
|
|
578 | 1 |
res.reserve(buf.length); |
579 | 1 |
res.writeByte(HIGHLIGHT.Escape); |
580 | 1 |
res.writeByte(HIGHLIGHT.Other); |
581 | 1 |
while (1) |
582 |
{
|
|
583 | 1 |
Token tok; |
584 | 1 |
lex.scan(&tok); |
585 | 1 |
res.writestring(lastp[0 .. tok.ptr - lastp]); |
586 | 1 |
HIGHLIGHT highlight; |
587 | 1 |
switch (tok.value) |
588 |
{
|
|
589 | 1 |
case TOK.identifier: |
590 | 1 |
highlight = HIGHLIGHT.Identifier; |
591 | 1 |
break; |
592 |
case TOK.comment: |
|
593 |
highlight = HIGHLIGHT.Comment; |
|
594 |
break; |
|
595 |
case TOK.int32Literal: |
|
596 |
..
|
|
597 |
case TOK.dcharLiteral: |
|
598 |
case TOK.string_: |
|
599 |
highlight = HIGHLIGHT.Literal; |
|
600 |
break; |
|
601 | 1 |
default: |
602 | 1 |
if (tok.isKeyword()) |
603 |
highlight = HIGHLIGHT.Keyword; |
|
604 | 1 |
break; |
605 |
}
|
|
606 | 1 |
if (highlight != HIGHLIGHT.Default) |
607 |
{
|
|
608 | 1 |
res.writeByte(HIGHLIGHT.Escape); |
609 | 1 |
res.writeByte(highlight); |
610 | 1 |
res.writestring(tok.ptr[0 .. lex.p - tok.ptr]); |
611 | 1 |
res.writeByte(HIGHLIGHT.Escape); |
612 | 1 |
res.writeByte(HIGHLIGHT.Other); |
613 |
}
|
|
614 |
else
|
|
615 | 1 |
res.writestring(tok.ptr[0 .. lex.p - tok.ptr]); |
616 | 1 |
if (tok.value == TOK.endOfFile) |
617 | 1 |
break; |
618 | 1 |
lastp = lex.p; |
619 |
}
|
|
620 | 1 |
res.writeByte(HIGHLIGHT.Escape); |
621 | 1 |
res.writeByte(HIGHLIGHT.Default); |
622 |
//printf("res = '%.*s'\n", cast(int)buf.length, buf.data);
|
|
623 | 1 |
buf.setsize(0); |
624 | 1 |
buf.write(&res); |
625 | 1 |
global.endGagging(gaggedErrorsSave); |
626 | 1 |
--nested; |
627 |
}
|
|
628 |
|
|
629 |
/**
|
|
630 |
* Write the buffer contents with embedded highlights to stderr.
|
|
631 |
* Params:
|
|
632 |
* buf = highlighted text
|
|
633 |
*/
|
|
634 |
private void writeHighlights(Console* con, ref const OutBuffer buf) |
|
635 |
{
|
|
636 | 1 |
bool colors; |
637 |
scope (exit) |
|
638 |
{
|
|
639 |
/* Do not mess up console if highlighting aborts
|
|
640 |
*/
|
|
641 | 1 |
if (colors) |
642 |
con.resetColor(); |
|
643 |
}
|
|
644 |
|
|
645 | 1 |
for (size_t i = 0; i < buf.length; ++i) |
646 |
{
|
|
647 | 1 |
const c = buf[i]; |
648 | 1 |
if (c == HIGHLIGHT.Escape) |
649 |
{
|
|
650 | 1 |
const color = buf[++i]; |
651 | 1 |
if (color == HIGHLIGHT.Default) |
652 |
{
|
|
653 | 1 |
con.resetColor(); |
654 | 1 |
colors = false; |
655 |
}
|
|
656 |
else
|
|
657 | 1 |
if (color == Color.white) |
658 |
{
|
|
659 | 1 |
con.resetColor(); |
660 | 1 |
con.setColorBright(true); |
661 | 1 |
colors = true; |
662 |
}
|
|
663 |
else
|
|
664 |
{
|
|
665 | 1 |
con.setColor(cast(Color)color); |
666 | 1 |
colors = true; |
667 |
}
|
|
668 |
}
|
|
669 |
else
|
|
670 | 1 |
fputc(c, con.fp); |
671 |
}
|
|
672 |
}
|
Read our documentation on viewing source code .