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