1 /** 2 * Functions for raising errors. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://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.errorsink; 19 import dmd.globals; 20 import dmd.location; 21 import dmd.common.outbuffer; 22 import dmd.root.rmem; 23 import dmd.root.string; 24 import dmd.console; 25 26 nothrow: 27 28 /*************************** 29 * Error message sink for D compiler. 30 */ 31 class ErrorSinkCompiler : ErrorSink 32 { 33 nothrow: 34 extern (C++): 35 override: 36 37 void error(const ref Loc loc, const(char)* format, ...) 38 { 39 va_list ap; 40 va_start(ap, format); 41 verror(loc, format, ap); 42 va_end(ap); 43 } 44 45 void errorSupplemental(const ref Loc loc, const(char)* format, ...) 46 { 47 va_list ap; 48 va_start(ap, format); 49 verrorSupplemental(loc, format, ap); 50 va_end(ap); 51 } 52 53 void warning(const ref Loc loc, const(char)* format, ...) 54 { 55 va_list ap; 56 va_start(ap, format); 57 vwarning(loc, format, ap); 58 va_end(ap); 59 } 60 61 void deprecation(const ref Loc loc, const(char)* format, ...) 62 { 63 va_list ap; 64 va_start(ap, format); 65 vdeprecation(loc, format, ap); 66 va_end(ap); 67 } 68 69 void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) 70 { 71 va_list ap; 72 va_start(ap, format); 73 vdeprecationSupplemental(loc, format, ap); 74 va_end(ap); 75 } 76 77 void message(const ref Loc loc, const(char)* format, ...) 78 { 79 va_list ap; 80 va_start(ap, format); 81 vmessage(loc, format, ap); 82 va_end(ap); 83 } 84 } 85 86 87 /** 88 * Color highlighting to classify messages 89 */ 90 enum Classification : Color 91 { 92 error = Color.brightRed, /// for errors 93 gagged = Color.brightBlue, /// for gagged errors 94 warning = Color.brightYellow, /// for warnings 95 deprecation = Color.brightCyan, /// for deprecations 96 tip = Color.brightGreen, /// for tip messages 97 } 98 99 100 static if (__VERSION__ < 2092) 101 private extern (C++) void noop(const ref Loc loc, const(char)* format, ...) {} 102 else 103 pragma(printf) private extern (C++) void noop(const ref Loc loc, const(char)* format, ...) {} 104 105 106 package auto previewErrorFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow 107 { 108 if (featureState == FeatureState.enabled) 109 return &error; 110 else if (featureState == FeatureState.disabled || isDeprecated) 111 return &noop; 112 else 113 return &deprecation; 114 } 115 116 package auto previewSupplementalFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow 117 { 118 if (featureState == FeatureState.enabled) 119 return &errorSupplemental; 120 else if (featureState == FeatureState.disabled || isDeprecated) 121 return &noop; 122 else 123 return &deprecationSupplemental; 124 } 125 126 127 /** 128 * Print an error message, increasing the global error count. 129 * Params: 130 * loc = location of error 131 * format = printf-style format specification 132 * ... = printf-style variadic arguments 133 */ 134 static if (__VERSION__ < 2092) 135 extern (C++) void error(const ref Loc loc, const(char)* format, ...) 136 { 137 va_list ap; 138 va_start(ap, format); 139 verror(loc, format, ap); 140 va_end(ap); 141 } 142 else 143 pragma(printf) extern (C++) void error(const ref Loc loc, const(char)* format, ...) 144 { 145 va_list ap; 146 va_start(ap, format); 147 verror(loc, format, ap); 148 va_end(ap); 149 } 150 151 /** 152 * Same as above, but takes a filename and line information arguments as separate parameters. 153 * Params: 154 * filename = source file of error 155 * linnum = line in the source file 156 * charnum = column number on the line 157 * format = printf-style format specification 158 * ... = printf-style variadic arguments 159 */ 160 static if (__VERSION__ < 2092) 161 extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) 162 { 163 const loc = Loc(filename, linnum, charnum); 164 va_list ap; 165 va_start(ap, format); 166 verror(loc, format, ap); 167 va_end(ap); 168 } 169 else 170 pragma(printf) extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...) 171 { 172 const loc = Loc(filename, linnum, charnum); 173 va_list ap; 174 va_start(ap, format); 175 verror(loc, format, ap); 176 va_end(ap); 177 } 178 179 /** 180 * Print additional details about an error message. 181 * Doesn't increase the error count or print an additional error prefix. 182 * Params: 183 * loc = location of error 184 * format = printf-style format specification 185 * ... = printf-style variadic arguments 186 */ 187 static if (__VERSION__ < 2092) 188 extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...) 189 { 190 va_list ap; 191 va_start(ap, format); 192 verrorSupplemental(loc, format, ap); 193 va_end(ap); 194 } 195 else 196 pragma(printf) extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...) 197 { 198 va_list ap; 199 va_start(ap, format); 200 verrorSupplemental(loc, format, ap); 201 va_end(ap); 202 } 203 204 /** 205 * Print a warning message, increasing the global warning count. 206 * Params: 207 * loc = location of warning 208 * format = printf-style format specification 209 * ... = printf-style variadic arguments 210 */ 211 static if (__VERSION__ < 2092) 212 extern (C++) void warning(const ref Loc loc, const(char)* format, ...) 213 { 214 va_list ap; 215 va_start(ap, format); 216 vwarning(loc, format, ap); 217 va_end(ap); 218 } 219 else 220 pragma(printf) extern (C++) void warning(const ref Loc loc, const(char)* format, ...) 221 { 222 va_list ap; 223 va_start(ap, format); 224 vwarning(loc, format, ap); 225 va_end(ap); 226 } 227 228 /** 229 * Print additional details about a warning message. 230 * Doesn't increase the warning count or print an additional warning prefix. 231 * Params: 232 * loc = location of warning 233 * format = printf-style format specification 234 * ... = printf-style variadic arguments 235 */ 236 static if (__VERSION__ < 2092) 237 extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...) 238 { 239 va_list ap; 240 va_start(ap, format); 241 vwarningSupplemental(loc, format, ap); 242 va_end(ap); 243 } 244 else 245 pragma(printf) extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...) 246 { 247 va_list ap; 248 va_start(ap, format); 249 vwarningSupplemental(loc, format, ap); 250 va_end(ap); 251 } 252 253 /** 254 * Print a deprecation message, may increase the global warning or error count 255 * depending on whether deprecations are ignored. 256 * Params: 257 * loc = location of deprecation 258 * format = printf-style format specification 259 * ... = printf-style variadic arguments 260 */ 261 static if (__VERSION__ < 2092) 262 extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...) 263 { 264 va_list ap; 265 va_start(ap, format); 266 vdeprecation(loc, format, ap); 267 va_end(ap); 268 } 269 else 270 pragma(printf) extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...) 271 { 272 va_list ap; 273 va_start(ap, format); 274 vdeprecation(loc, format, ap); 275 va_end(ap); 276 } 277 278 /** 279 * Print additional details about a deprecation message. 280 * Doesn't increase the error count, or print an additional deprecation prefix. 281 * Params: 282 * loc = location of deprecation 283 * format = printf-style format specification 284 * ... = printf-style variadic arguments 285 */ 286 static if (__VERSION__ < 2092) 287 extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) 288 { 289 va_list ap; 290 va_start(ap, format); 291 vdeprecationSupplemental(loc, format, ap); 292 va_end(ap); 293 } 294 else 295 pragma(printf) extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) 296 { 297 va_list ap; 298 va_start(ap, format); 299 vdeprecationSupplemental(loc, format, ap); 300 va_end(ap); 301 } 302 303 /** 304 * Print a verbose message. 305 * Doesn't prefix or highlight messages. 306 * Params: 307 * loc = location of message 308 * format = printf-style format specification 309 * ... = printf-style variadic arguments 310 */ 311 static if (__VERSION__ < 2092) 312 extern (C++) void message(const ref Loc loc, const(char)* format, ...) 313 { 314 va_list ap; 315 va_start(ap, format); 316 vmessage(loc, format, ap); 317 va_end(ap); 318 } 319 else 320 pragma(printf) extern (C++) void message(const ref Loc loc, const(char)* format, ...) 321 { 322 va_list ap; 323 va_start(ap, format); 324 vmessage(loc, format, ap); 325 va_end(ap); 326 } 327 328 /** 329 * Same as above, but doesn't take a location argument. 330 * Params: 331 * format = printf-style format specification 332 * ... = printf-style variadic arguments 333 */ 334 static if (__VERSION__ < 2092) 335 extern (C++) void message(const(char)* format, ...) 336 { 337 va_list ap; 338 va_start(ap, format); 339 vmessage(Loc.initial, format, ap); 340 va_end(ap); 341 } 342 else 343 pragma(printf) extern (C++) void message(const(char)* format, ...) 344 { 345 va_list ap; 346 va_start(ap, format); 347 vmessage(Loc.initial, format, ap); 348 va_end(ap); 349 } 350 351 /** 352 * The type of the diagnostic handler 353 * see verrorPrint for arguments 354 * Returns: true if error handling is done, false to continue printing to stderr 355 */ 356 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); 357 358 /** 359 * The diagnostic handler. 360 * If non-null it will be called for every diagnostic message issued by the compiler. 361 * If it returns false, the message will be printed to stderr as usual. 362 */ 363 __gshared DiagnosticHandler diagnosticHandler; 364 365 /** 366 * Print a tip message with the prefix and highlighting. 367 * Params: 368 * format = printf-style format specification 369 * ... = printf-style variadic arguments 370 */ 371 static if (__VERSION__ < 2092) 372 extern (C++) void tip(const(char)* format, ...) 373 { 374 va_list ap; 375 va_start(ap, format); 376 vtip(format, ap); 377 va_end(ap); 378 } 379 else 380 pragma(printf) extern (C++) void tip(const(char)* format, ...) 381 { 382 va_list ap; 383 va_start(ap, format); 384 vtip(format, ap); 385 va_end(ap); 386 } 387 388 /** 389 * Just print to stderr, doesn't care about gagging. 390 * (format,ap) text within backticks gets syntax highlighted. 391 * Params: 392 * loc = location of error 393 * headerColor = color to set `header` output to 394 * header = title of error message 395 * format = printf-style format specification 396 * ap = printf-style variadic arguments 397 * p1 = additional message prefix 398 * p2 = additional message prefix 399 */ 400 private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* header, 401 const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) 402 { 403 if (diagnosticHandler && diagnosticHandler(loc, headerColor, header, format, ap, p1, p2)) 404 return; 405 406 if (global.params.showGaggedErrors && global.gag) 407 fprintf(stderr, "(spec:%d) ", global.gag); 408 Console con = cast(Console) global.console; 409 const p = loc.toChars(); 410 if (con) 411 con.setColorBright(true); 412 if (*p) 413 { 414 fprintf(stderr, "%s: ", p); 415 mem.xfree(cast(void*)p); 416 } 417 if (con) 418 con.setColor(headerColor); 419 fputs(header, stderr); 420 if (con) 421 con.resetColor(); 422 OutBuffer tmp; 423 if (p1) 424 { 425 tmp.writestring(p1); 426 tmp.writestring(" "); 427 } 428 if (p2) 429 { 430 tmp.writestring(p2); 431 tmp.writestring(" "); 432 } 433 tmp.vprintf(format, ap); 434 435 if (con && strchr(tmp.peekChars(), '`')) 436 { 437 colorSyntaxHighlight(tmp); 438 writeHighlights(con, tmp); 439 } 440 else 441 fputs(tmp.peekChars(), stderr); 442 fputc('\n', stderr); 443 444 __gshared Loc old_loc; 445 if (global.params.printErrorContext && 446 // ignore supplemental messages with same loc 447 (loc != old_loc || strchr(header, ':')) && 448 // ignore invalid files 449 loc != Loc.initial && 450 // ignore mixins for now 451 !loc.filename.strstr(".d-mixin-") && 452 !global.params.mixinOut.doOutput) 453 { 454 import dmd.root.filename : FileName; 455 const fileName = FileName(loc.filename.toDString); 456 if (auto file = global.fileManager.lookup(fileName)) 457 { 458 const(char)[][] lines = global.fileManager.getLines(fileName); 459 if (loc.linnum - 1 < lines.length) 460 { 461 auto line = lines[loc.linnum - 1]; 462 if (loc.charnum < line.length) 463 { 464 fprintf(stderr, "%.*s\n", cast(int)line.length, line.ptr); 465 // The number of column bytes and the number of display columns 466 // occupied by a character are not the same for non-ASCII charaters. 467 // https://issues.dlang.org/show_bug.cgi?id=21849 468 size_t c = 0; 469 while (c < loc.charnum - 1) 470 { 471 import dmd.root.utf : utf_decodeChar; 472 dchar u; 473 const msg = utf_decodeChar(line, c, u); 474 assert(msg is null, msg); 475 fputc(' ', stderr); 476 } 477 fputc('^', stderr); 478 fputc('\n', stderr); 479 } 480 } 481 } 482 } 483 old_loc = loc; 484 fflush(stderr); // ensure it gets written out in case of compiler aborts 485 } 486 487 /** 488 * Same as $(D error), but takes a va_list parameter, and optionally additional message prefixes. 489 * Params: 490 * loc = location of error 491 * format = printf-style format specification 492 * ap = printf-style variadic arguments 493 * p1 = additional message prefix 494 * p2 = additional message prefix 495 * header = title of error message 496 */ 497 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: ") 498 { 499 global.errors++; 500 if (!global.gag) 501 { 502 verrorPrint(loc, Classification.error, header, format, ap, p1, p2); 503 if (global.params.errorLimit && global.errors >= global.params.errorLimit) 504 fatal(); // moderate blizzard of cascading messages 505 } 506 else 507 { 508 if (global.params.showGaggedErrors) 509 verrorPrint(loc, Classification.gagged, header, format, ap, p1, p2); 510 global.gaggedErrors++; 511 } 512 } 513 514 /** 515 * Same as $(D errorSupplemental), but takes a va_list parameter. 516 * Params: 517 * loc = location of error 518 * format = printf-style format specification 519 * ap = printf-style variadic arguments 520 */ 521 static if (__VERSION__ < 2092) 522 extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) 523 { 524 _verrorSupplemental(loc, format, ap); 525 } 526 else 527 pragma(printf) extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) 528 { 529 _verrorSupplemental(loc, format, ap); 530 } 531 532 private void _verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) 533 { 534 Color color; 535 if (global.gag) 536 { 537 if (!global.params.showGaggedErrors) 538 return; 539 color = Classification.gagged; 540 } 541 else 542 color = Classification.error; 543 544 verrorPrint(loc, color, " ", format, ap); 545 } 546 547 /** 548 * Same as $(D warning), but takes a va_list parameter. 549 * Params: 550 * loc = location of warning 551 * format = printf-style format specification 552 * ap = printf-style variadic arguments 553 */ 554 static if (__VERSION__ < 2092) 555 extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) 556 { 557 _vwarning(loc, format, ap); 558 } 559 else 560 pragma(printf) extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap) 561 { 562 _vwarning(loc, format, ap); 563 } 564 565 private void _vwarning(const ref Loc loc, const(char)* format, va_list ap) 566 { 567 if (global.params.warnings != DiagnosticReporting.off) 568 { 569 if (!global.gag) 570 { 571 verrorPrint(loc, Classification.warning, "Warning: ", format, ap); 572 if (global.params.warnings == DiagnosticReporting.error) 573 global.warnings++; 574 } 575 else 576 { 577 global.gaggedWarnings++; 578 } 579 } 580 } 581 582 /** 583 * Same as $(D warningSupplemental), but takes a va_list parameter. 584 * Params: 585 * loc = location of warning 586 * format = printf-style format specification 587 * ap = printf-style variadic arguments 588 */ 589 static if (__VERSION__ < 2092) 590 extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) 591 { 592 _vwarningSupplemental(loc, format, ap); 593 } 594 else 595 pragma(printf) extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) 596 { 597 _vwarningSupplemental(loc, format, ap); 598 } 599 600 private void _vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) 601 { 602 if (global.params.warnings != DiagnosticReporting.off && !global.gag) 603 verrorPrint(loc, Classification.warning, " ", format, ap); 604 } 605 606 /** 607 * Same as $(D deprecation), but takes a va_list parameter, and optionally additional message prefixes. 608 * Params: 609 * loc = location of deprecation 610 * format = printf-style format specification 611 * ap = printf-style variadic arguments 612 * p1 = additional message prefix 613 * p2 = additional message prefix 614 */ 615 extern (C++) void vdeprecation(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) 616 { 617 static immutable header = "Deprecation: "; 618 if (global.params.useDeprecated == DiagnosticReporting.error) 619 verror(loc, format, ap, p1, p2, header.ptr); 620 else if (global.params.useDeprecated == DiagnosticReporting.inform) 621 { 622 if (!global.gag) 623 { 624 verrorPrint(loc, Classification.deprecation, header.ptr, format, ap, p1, p2); 625 } 626 else 627 { 628 global.gaggedWarnings++; 629 } 630 } 631 } 632 633 /** 634 * Same as $(D message), but takes a va_list parameter. 635 * Params: 636 * loc = location of message 637 * format = printf-style format specification 638 * ap = printf-style variadic arguments 639 */ 640 static if (__VERSION__ < 2092) 641 extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) 642 { 643 _vmessage(loc, format, ap); 644 } 645 else 646 pragma(printf) extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap) 647 { 648 _vmessage(loc, format, ap); 649 } 650 651 private void _vmessage(const ref Loc loc, const(char)* format, va_list ap) 652 { 653 const p = loc.toChars(); 654 if (*p) 655 { 656 fprintf(stdout, "%s: ", p); 657 mem.xfree(cast(void*)p); 658 } 659 OutBuffer tmp; 660 tmp.vprintf(format, ap); 661 fputs(tmp.peekChars(), stdout); 662 fputc('\n', stdout); 663 fflush(stdout); // ensure it gets written out in case of compiler aborts 664 } 665 666 /** 667 * Same as $(D tip), but takes a va_list parameter. 668 * Params: 669 * format = printf-style format specification 670 * ap = printf-style variadic arguments 671 */ 672 static if (__VERSION__ < 2092) 673 extern (C++) void vtip(const(char)* format, va_list ap) 674 { 675 _vtip(format, ap); 676 } 677 else 678 pragma(printf) extern (C++) void vtip(const(char)* format, va_list ap) 679 { 680 _vtip(format, ap); 681 } 682 private void _vtip(const(char)* format, va_list ap) 683 { 684 if (!global.gag) 685 { 686 Loc loc = Loc.init; 687 verrorPrint(loc, Classification.tip, " Tip: ", format, ap); 688 } 689 } 690 691 /** 692 * Same as $(D deprecationSupplemental), but takes a va_list parameter. 693 * Params: 694 * loc = location of deprecation 695 * format = printf-style format specification 696 * ap = printf-style variadic arguments 697 */ 698 static if (__VERSION__ < 2092) 699 extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) 700 { 701 _vdeprecationSupplemental(loc, format, ap); 702 } 703 else 704 pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) 705 { 706 _vdeprecationSupplemental(loc, format, ap); 707 } 708 709 private void _vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) 710 { 711 if (global.params.useDeprecated == DiagnosticReporting.error) 712 verrorSupplemental(loc, format, ap); 713 else if (global.params.useDeprecated == DiagnosticReporting.inform && !global.gag) 714 verrorPrint(loc, Classification.deprecation, " ", format, ap); 715 } 716 717 /** 718 * The type of the fatal error handler 719 * Returns: true if error handling is done, false to do exit(EXIT_FAILURE) 720 */ 721 alias FatalErrorHandler = bool delegate(); 722 723 /** 724 * The fatal error handler. 725 * If non-null it will be called for every fatal() call issued by the compiler. 726 */ 727 __gshared FatalErrorHandler fatalErrorHandler; 728 729 /** 730 * Call this after printing out fatal error messages to clean up and exit the 731 * compiler. You can also set a fatalErrorHandler to override this behaviour. 732 */ 733 extern (C++) void fatal() 734 { 735 if (fatalErrorHandler && fatalErrorHandler()) 736 return; 737 738 exit(EXIT_FAILURE); 739 } 740 741 /** 742 * Try to stop forgetting to remove the breakpoints from 743 * release builds. 744 */ 745 extern (C++) void halt() 746 { 747 assert(0); 748 } 749 750 /** 751 * Scan characters in `buf`. Assume text enclosed by `...` 752 * is D source code, and color syntax highlight it. 753 * Modify contents of `buf` with highlighted result. 754 * Many parallels to ddoc.highlightText(). 755 * Params: 756 * buf = text containing `...` code to highlight 757 */ 758 private void colorSyntaxHighlight(ref OutBuffer buf) 759 { 760 //printf("colorSyntaxHighlight('%.*s')\n", cast(int)buf.length, buf[].ptr); 761 bool inBacktick = false; 762 size_t iCodeStart = 0; 763 size_t offset = 0; 764 for (size_t i = offset; i < buf.length; ++i) 765 { 766 char c = buf[i]; 767 switch (c) 768 { 769 case '`': 770 if (inBacktick) 771 { 772 inBacktick = false; 773 OutBuffer codebuf; 774 codebuf.write(buf[iCodeStart .. i]); 775 codebuf.writeByte(0); 776 // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL 777 colorHighlightCode(codebuf); 778 buf.remove(iCodeStart, i - iCodeStart); 779 immutable pre = ""; 780 i = buf.insert(iCodeStart, pre); 781 i = buf.insert(i, codebuf[]); 782 break; 783 } 784 inBacktick = true; 785 iCodeStart = i + 1; 786 break; 787 788 default: 789 break; 790 } 791 } 792 } 793 794 795 /** 796 * Embed these highlighting commands in the text stream. 797 * HIGHLIGHT.Escape indicates a Color follows. 798 */ 799 enum HIGHLIGHT : ubyte 800 { 801 Default = Color.black, // back to whatever the console is set at 802 Escape = '\xFF', // highlight Color follows 803 Identifier = Color.white, 804 Keyword = Color.white, 805 Literal = Color.white, 806 Comment = Color.darkGray, 807 Other = Color.cyan, // other tokens 808 } 809 810 /** 811 * Highlight code for CODE section. 812 * Rewrite the contents of `buf` with embedded highlights. 813 * Analogous to doc.highlightCode2() 814 */ 815 816 private void colorHighlightCode(ref OutBuffer buf) 817 { 818 import dmd.lexer; 819 import dmd.tokens; 820 821 __gshared int nested; 822 if (nested) 823 { 824 // Should never happen, but don't infinitely recurse if it does 825 --nested; 826 return; 827 } 828 ++nested; 829 830 __gshared ErrorSinkNull errorSinkNull; 831 if (!errorSinkNull) 832 errorSinkNull = new ErrorSinkNull; 833 834 scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, errorSinkNull, &global.compileEnv); 835 OutBuffer res; 836 const(char)* lastp = cast(char*)buf[].ptr; 837 //printf("colorHighlightCode('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr); 838 res.reserve(buf.length); 839 res.writeByte(HIGHLIGHT.Escape); 840 res.writeByte(HIGHLIGHT.Other); 841 while (1) 842 { 843 Token tok; 844 lex.scan(&tok); 845 res.writestring(lastp[0 .. tok.ptr - lastp]); 846 HIGHLIGHT highlight; 847 switch (tok.value) 848 { 849 case TOK.identifier: 850 highlight = HIGHLIGHT.Identifier; 851 break; 852 case TOK.comment: 853 highlight = HIGHLIGHT.Comment; 854 break; 855 case TOK.int32Literal: 856 .. 857 case TOK.dcharLiteral: 858 case TOK.string_: 859 highlight = HIGHLIGHT.Literal; 860 break; 861 default: 862 if (tok.isKeyword()) 863 highlight = HIGHLIGHT.Keyword; 864 break; 865 } 866 if (highlight != HIGHLIGHT.Default) 867 { 868 res.writeByte(HIGHLIGHT.Escape); 869 res.writeByte(highlight); 870 res.writestring(tok.ptr[0 .. lex.p - tok.ptr]); 871 res.writeByte(HIGHLIGHT.Escape); 872 res.writeByte(HIGHLIGHT.Other); 873 } 874 else 875 res.writestring(tok.ptr[0 .. lex.p - tok.ptr]); 876 if (tok.value == TOK.endOfFile) 877 break; 878 lastp = lex.p; 879 } 880 res.writeByte(HIGHLIGHT.Escape); 881 res.writeByte(HIGHLIGHT.Default); 882 //printf("res = '%.*s'\n", cast(int)buf.length, buf[].ptr); 883 buf.setsize(0); 884 buf.write(&res); 885 --nested; 886 } 887 888 /** 889 * Write the buffer contents with embedded highlights to stderr. 890 * Params: 891 * buf = highlighted text 892 */ 893 private void writeHighlights(Console con, ref const OutBuffer buf) 894 { 895 bool colors; 896 scope (exit) 897 { 898 /* Do not mess up console if highlighting aborts 899 */ 900 if (colors) 901 con.resetColor(); 902 } 903 904 for (size_t i = 0; i < buf.length; ++i) 905 { 906 const c = buf[i]; 907 if (c == HIGHLIGHT.Escape) 908 { 909 const color = buf[++i]; 910 if (color == HIGHLIGHT.Default) 911 { 912 con.resetColor(); 913 colors = false; 914 } 915 else 916 if (color == Color.white) 917 { 918 con.resetColor(); 919 con.setColorBright(true); 920 colors = true; 921 } 922 else 923 { 924 con.setColor(cast(Color)color); 925 colors = true; 926 } 927 } 928 else 929 fputc(c, con.fp); 930 } 931 }