1 /** 2 * Code for generating .json descriptions of the module when passing the `-X` flag to dmd. 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/json.d, _json.d) 8 * Documentation: https://dlang.org/phobos/dmd_json.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/json.d 10 */ 11 12 module dmd.json; 13 14 import core.stdc.stdio; 15 import core.stdc..string; 16 import dmd.aggregate; 17 import dmd.arraytypes; 18 import dmd.attrib; 19 import dmd.cond; 20 import dmd.dclass; 21 import dmd.declaration; 22 import dmd.denum; 23 import dmd.dimport; 24 import dmd.dmodule; 25 import dmd.dsymbol; 26 import dmd.dtemplate; 27 import dmd.errors; 28 import dmd.expression; 29 import dmd.func; 30 import dmd.globals; 31 import dmd.hdrgen; 32 import dmd.id; 33 import dmd.identifier; 34 import dmd.mtype; 35 import dmd.root.outbuffer; 36 import dmd.root.rootobject; 37 import dmd.root..string; 38 import dmd.visitor; 39 40 version(Windows) { 41 extern (C) char* getcwd(char* buffer, size_t maxlen); 42 } else { 43 import core.sys.posix.unistd : getcwd; 44 } 45 46 private extern (C++) final class ToJsonVisitor : Visitor 47 { 48 alias visit = Visitor.visit; 49 public: 50 OutBuffer* buf; 51 int indentLevel; 52 const(char)[] filename; 53 54 extern (D) this(OutBuffer* buf) 55 { 56 this.buf = buf; 57 } 58 59 60 void indent() 61 { 62 if (buf.length >= 1 && (*buf)[buf.length - 1] == '\n') 63 for (int i = 0; i < indentLevel; i++) 64 buf.writeByte(' '); 65 } 66 67 void removeComma() 68 { 69 if (buf.length >= 2 && (*buf)[buf.length - 2] == ',' && ((*buf)[buf.length - 1] == '\n' || (*buf)[buf.length - 1] == ' ')) 70 buf.setsize(buf.length - 2); 71 } 72 73 void comma() 74 { 75 if (indentLevel > 0) 76 buf.writestring(",\n"); 77 } 78 79 void stringStart() 80 { 81 buf.writeByte('\"'); 82 } 83 84 void stringEnd() 85 { 86 buf.writeByte('\"'); 87 } 88 89 extern(D) void stringPart(const char[] s) 90 { 91 foreach (char c; s) 92 { 93 switch (c) 94 { 95 case '\n': 96 buf.writestring("\\n"); 97 break; 98 case '\r': 99 buf.writestring("\\r"); 100 break; 101 case '\t': 102 buf.writestring("\\t"); 103 break; 104 case '\"': 105 buf.writestring("\\\""); 106 break; 107 case '\\': 108 buf.writestring("\\\\"); 109 break; 110 case '\b': 111 buf.writestring("\\b"); 112 break; 113 case '\f': 114 buf.writestring("\\f"); 115 break; 116 default: 117 if (c < 0x20) 118 buf.printf("\\u%04x", c); 119 else 120 { 121 // Note that UTF-8 chars pass through here just fine 122 buf.writeByte(c); 123 } 124 break; 125 } 126 } 127 } 128 129 // Json value functions 130 /********************************* 131 * Encode string into buf, and wrap it in double quotes. 132 */ 133 extern(D) void value(const char[] s) 134 { 135 stringStart(); 136 stringPart(s); 137 stringEnd(); 138 } 139 140 void value(int value) 141 { 142 if (value < 0) 143 { 144 buf.writeByte('-'); 145 value = -value; 146 } 147 buf.print(value); 148 } 149 150 void valueBool(bool value) 151 { 152 buf.writestring(value ? "true" : "false"); 153 } 154 155 /********************************* 156 * Item is an intented value and a comma, for use in arrays 157 */ 158 extern(D) void item(const char[] s) 159 { 160 indent(); 161 value(s); 162 comma(); 163 } 164 165 void item(int i) 166 { 167 indent(); 168 value(i); 169 comma(); 170 } 171 172 void itemBool(const bool b) 173 { 174 indent(); 175 valueBool(b); 176 comma(); 177 } 178 179 // Json array functions 180 void arrayStart() 181 { 182 indent(); 183 buf.writestring("[\n"); 184 indentLevel++; 185 } 186 187 void arrayEnd() 188 { 189 indentLevel--; 190 removeComma(); 191 if (buf.length >= 2 && (*buf)[buf.length - 2] == '[' && (*buf)[buf.length - 1] == '\n') 192 buf.setsize(buf.length - 1); 193 else if (!(buf.length >= 1 && (*buf)[buf.length - 1] == '[')) 194 { 195 buf.writestring("\n"); 196 indent(); 197 } 198 buf.writestring("]"); 199 comma(); 200 } 201 202 // Json object functions 203 void objectStart() 204 { 205 indent(); 206 buf.writestring("{\n"); 207 indentLevel++; 208 } 209 210 void objectEnd() 211 { 212 indentLevel--; 213 removeComma(); 214 if (buf.length >= 2 && (*buf)[buf.length - 2] == '{' && (*buf)[buf.length - 1] == '\n') 215 buf.setsize(buf.length - 1); 216 else 217 { 218 buf.writestring("\n"); 219 indent(); 220 } 221 buf.writestring("}"); 222 comma(); 223 } 224 225 // Json object property functions 226 extern(D) void propertyStart(const char[] name) 227 { 228 indent(); 229 value(name); 230 buf.writestring(" : "); 231 } 232 233 /** 234 Write the given string object property only if `s` is not null. 235 236 Params: 237 name = the name of the object property 238 s = the string value of the object property 239 */ 240 extern(D) void property(const char[] name, const char[] s) 241 { 242 if (s is null) 243 return; 244 propertyStart(name); 245 value(s); 246 comma(); 247 } 248 249 /** 250 Write the given string object property. 251 252 Params: 253 name = the name of the object property 254 s = the string value of the object property 255 */ 256 extern(D) void requiredProperty(const char[] name, const char[] s) 257 { 258 propertyStart(name); 259 if (s is null) 260 buf.writestring("null"); 261 else 262 value(s); 263 comma(); 264 } 265 266 extern(D) void property(const char[] name, int i) 267 { 268 propertyStart(name); 269 value(i); 270 comma(); 271 } 272 273 extern(D) void propertyBool(const char[] name, const bool b) 274 { 275 propertyStart(name); 276 valueBool(b); 277 comma(); 278 } 279 280 extern(D) void property(const char[] name, TRUST trust) 281 { 282 final switch (trust) 283 { 284 case TRUST.default_: 285 // Should not be printed 286 //property(name, "default"); 287 break; 288 case TRUST.system: return property(name, "system"); 289 case TRUST.trusted: return property(name, "trusted"); 290 case TRUST.safe: return property(name, "safe"); 291 } 292 } 293 294 extern(D) void property(const char[] name, PURE purity) 295 { 296 final switch (purity) 297 { 298 case PURE.impure: 299 // Should not be printed 300 //property(name, "impure"); 301 break; 302 case PURE.weak: return property(name, "weak"); 303 case PURE.const_: return property(name, "const"); 304 case PURE.strong: return property(name, "strong"); 305 case PURE.fwdref: return property(name, "fwdref"); 306 } 307 } 308 309 extern(D) void property(const char[] name, const LINK linkage) 310 { 311 final switch (linkage) 312 { 313 case LINK.default_: 314 // Should not be printed 315 //property(name, "default"); 316 break; 317 case LINK.d: 318 // Should not be printed 319 //property(name, "d"); 320 break; 321 case LINK.system: 322 // Should not be printed 323 //property(name, "system"); 324 break; 325 case LINK.c: return property(name, "c"); 326 case LINK.cpp: return property(name, "cpp"); 327 case LINK.windows: return property(name, "windows"); 328 case LINK.pascal: return property(name, "pascal"); 329 case LINK.objc: return property(name, "objc"); 330 } 331 } 332 333 extern(D) void propertyStorageClass(const char[] name, StorageClass stc) 334 { 335 stc &= STCStorageClass; 336 if (stc) 337 { 338 propertyStart(name); 339 arrayStart(); 340 while (stc) 341 { 342 auto p = stcToString(stc); 343 assert(p.length); 344 item(p); 345 } 346 arrayEnd(); 347 } 348 } 349 350 extern(D) void property(const char[] linename, const char[] charname, const ref Loc loc) 351 { 352 if (loc.isValid()) 353 { 354 if (auto filename = loc.filename.toDString) 355 { 356 if (filename != this.filename) 357 { 358 this.filename = filename; 359 property("file", filename); 360 } 361 } 362 if (loc.linnum) 363 { 364 property(linename, loc.linnum); 365 if (loc.charnum) 366 property(charname, loc.charnum); 367 } 368 } 369 } 370 371 extern(D) void property(const char[] name, Type type) 372 { 373 if (type) 374 { 375 property(name, type.toString()); 376 } 377 } 378 379 extern(D) void property(const char[] name, const char[] deconame, Type type) 380 { 381 if (type) 382 { 383 if (type.deco) 384 property(deconame, type.deco.toDString); 385 else 386 property(name, type.toString()); 387 } 388 } 389 390 extern(D) void property(const char[] name, Parameters* parameters) 391 { 392 if (parameters is null || parameters.dim == 0) 393 return; 394 propertyStart(name); 395 arrayStart(); 396 if (parameters) 397 { 398 for (size_t i = 0; i < parameters.dim; i++) 399 { 400 Parameter p = (*parameters)[i]; 401 objectStart(); 402 if (p.ident) 403 property("name", p.ident.toString()); 404 property("type", "deco", p.type); 405 propertyStorageClass("storageClass", p.storageClass); 406 if (p.defaultArg) 407 property("default", p.defaultArg.toString()); 408 objectEnd(); 409 } 410 } 411 arrayEnd(); 412 } 413 414 /* ========================================================================== */ 415 void jsonProperties(Dsymbol s) 416 { 417 if (s.isModule()) 418 return; 419 if (!s.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes 420 { 421 property("name", s.toString()); 422 property("kind", s.kind.toDString); 423 } 424 if (s.prot().kind != Prot.Kind.public_) // TODO: How about package(names)? 425 property("protection", protectionToString(s.prot().kind)); 426 if (EnumMember em = s.isEnumMember()) 427 { 428 if (em.origValue) 429 property("value", em.origValue.toString()); 430 } 431 property("comment", s.comment.toDString); 432 property("line", "char", s.loc); 433 } 434 435 void jsonProperties(Declaration d) 436 { 437 if (d.storage_class & STC.local) 438 return; 439 jsonProperties(cast(Dsymbol)d); 440 propertyStorageClass("storageClass", d.storage_class); 441 property("linkage", d.linkage); 442 property("type", "deco", d.type); 443 // Emit originalType if it differs from type 444 if (d.type != d.originalType && d.originalType) 445 { 446 auto ostr = d.originalType.toString(); 447 if (d.type) 448 { 449 auto tstr = d.type.toString(); 450 if (ostr != tstr) 451 { 452 //printf("tstr = %s, ostr = %s\n", tstr, ostr); 453 property("originalType", ostr); 454 } 455 } 456 else 457 property("originalType", ostr); 458 } 459 } 460 461 void jsonProperties(TemplateDeclaration td) 462 { 463 jsonProperties(cast(Dsymbol)td); 464 if (td.onemember && td.onemember.isCtorDeclaration()) 465 property("name", "this"); // __ctor -> this 466 else 467 property("name", td.ident.toString()); // Foo(T) -> Foo 468 } 469 470 /* ========================================================================== */ 471 override void visit(Dsymbol s) 472 { 473 } 474 475 override void visit(Module s) 476 { 477 objectStart(); 478 if (s.md) 479 property("name", s.md.toString()); 480 property("kind", s.kind.toDString); 481 filename = s.srcfile.toString(); 482 property("file", filename); 483 property("comment", s.comment.toDString); 484 propertyStart("members"); 485 arrayStart(); 486 for (size_t i = 0; i < s.members.dim; i++) 487 { 488 (*s.members)[i].accept(this); 489 } 490 arrayEnd(); 491 objectEnd(); 492 } 493 494 override void visit(Import s) 495 { 496 if (s.id == Id.object) 497 return; 498 objectStart(); 499 propertyStart("name"); 500 stringStart(); 501 if (s.packages && s.packages.dim) 502 { 503 for (size_t i = 0; i < s.packages.dim; i++) 504 { 505 const pid = (*s.packages)[i]; 506 stringPart(pid.toString()); 507 buf.writeByte('.'); 508 } 509 } 510 stringPart(s.id.toString()); 511 stringEnd(); 512 comma(); 513 property("kind", s.kind.toDString); 514 property("comment", s.comment.toDString); 515 property("line", "char", s.loc); 516 if (s.prot().kind != Prot.Kind.public_) 517 property("protection", protectionToString(s.prot().kind)); 518 if (s.aliasId) 519 property("alias", s.aliasId.toString()); 520 bool hasRenamed = false; 521 bool hasSelective = false; 522 for (size_t i = 0; i < s.aliases.dim; i++) 523 { 524 // avoid empty "renamed" and "selective" sections 525 if (hasRenamed && hasSelective) 526 break; 527 else if (s.aliases[i]) 528 hasRenamed = true; 529 else 530 hasSelective = true; 531 } 532 if (hasRenamed) 533 { 534 // import foo : alias1 = target1; 535 propertyStart("renamed"); 536 objectStart(); 537 for (size_t i = 0; i < s.aliases.dim; i++) 538 { 539 const name = s.names[i]; 540 const _alias = s.aliases[i]; 541 if (_alias) 542 property(_alias.toString(), name.toString()); 543 } 544 objectEnd(); 545 } 546 if (hasSelective) 547 { 548 // import foo : target1; 549 propertyStart("selective"); 550 arrayStart(); 551 foreach (i, name; s.names) 552 { 553 if (!s.aliases[i]) 554 item(name.toString()); 555 } 556 arrayEnd(); 557 } 558 objectEnd(); 559 } 560 561 override void visit(AttribDeclaration d) 562 { 563 Dsymbols* ds = d.include(null); 564 if (ds) 565 { 566 for (size_t i = 0; i < ds.dim; i++) 567 { 568 Dsymbol s = (*ds)[i]; 569 s.accept(this); 570 } 571 } 572 } 573 574 override void visit(ConditionalDeclaration d) 575 { 576 if (d.condition.inc != Include.notComputed) 577 { 578 visit(cast(AttribDeclaration)d); 579 return; // Don't visit the if/else bodies again below 580 } 581 Dsymbols* ds = d.decl ? d.decl : d.elsedecl; 582 for (size_t i = 0; i < ds.dim; i++) 583 { 584 Dsymbol s = (*ds)[i]; 585 s.accept(this); 586 } 587 } 588 589 override void visit(TypeInfoDeclaration d) 590 { 591 } 592 593 override void visit(PostBlitDeclaration d) 594 { 595 } 596 597 override void visit(Declaration d) 598 { 599 objectStart(); 600 //property("unknown", "declaration"); 601 jsonProperties(d); 602 objectEnd(); 603 } 604 605 override void visit(AggregateDeclaration d) 606 { 607 objectStart(); 608 jsonProperties(d); 609 ClassDeclaration cd = d.isClassDeclaration(); 610 if (cd) 611 { 612 if (cd.baseClass && cd.baseClass.ident != Id.Object) 613 { 614 property("base", cd.baseClass.toPrettyChars(true).toDString); 615 } 616 if (cd.interfaces.length) 617 { 618 propertyStart("interfaces"); 619 arrayStart(); 620 foreach (b; cd.interfaces) 621 { 622 item(b.sym.toPrettyChars(true).toDString); 623 } 624 arrayEnd(); 625 } 626 } 627 if (d.members) 628 { 629 propertyStart("members"); 630 arrayStart(); 631 for (size_t i = 0; i < d.members.dim; i++) 632 { 633 Dsymbol s = (*d.members)[i]; 634 s.accept(this); 635 } 636 arrayEnd(); 637 } 638 objectEnd(); 639 } 640 641 override void visit(FuncDeclaration d) 642 { 643 objectStart(); 644 jsonProperties(d); 645 TypeFunction tf = cast(TypeFunction)d.type; 646 if (tf && tf.ty == Tfunction) 647 property("parameters", tf.parameterList.parameters); 648 property("endline", "endchar", d.endloc); 649 if (d.foverrides.dim) 650 { 651 propertyStart("overrides"); 652 arrayStart(); 653 for (size_t i = 0; i < d.foverrides.dim; i++) 654 { 655 FuncDeclaration fd = d.foverrides[i]; 656 item(fd.toPrettyChars().toDString); 657 } 658 arrayEnd(); 659 } 660 if (d.fdrequire) 661 { 662 propertyStart("in"); 663 d.fdrequire.accept(this); 664 } 665 if (d.fdensure) 666 { 667 propertyStart("out"); 668 d.fdensure.accept(this); 669 } 670 objectEnd(); 671 } 672 673 override void visit(TemplateDeclaration d) 674 { 675 objectStart(); 676 // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one 677 property("kind", "template"); 678 jsonProperties(d); 679 propertyStart("parameters"); 680 arrayStart(); 681 for (size_t i = 0; i < d.parameters.dim; i++) 682 { 683 TemplateParameter s = (*d.parameters)[i]; 684 objectStart(); 685 property("name", s.ident.toString()); 686 687 if (auto type = s.isTemplateTypeParameter()) 688 { 689 if (s.isTemplateThisParameter()) 690 property("kind", "this"); 691 else 692 property("kind", "type"); 693 property("type", "deco", type.specType); 694 property("default", "defaultDeco", type.defaultType); 695 } 696 697 if (auto value = s.isTemplateValueParameter()) 698 { 699 property("kind", "value"); 700 property("type", "deco", value.valType); 701 if (value.specValue) 702 property("specValue", value.specValue.toString()); 703 if (value.defaultValue) 704 property("defaultValue", value.defaultValue.toString()); 705 } 706 707 if (auto _alias = s.isTemplateAliasParameter()) 708 { 709 property("kind", "alias"); 710 property("type", "deco", _alias.specType); 711 if (_alias.specAlias) 712 property("specAlias", _alias.specAlias.toString()); 713 if (_alias.defaultAlias) 714 property("defaultAlias", _alias.defaultAlias.toString()); 715 } 716 717 if (auto tuple = s.isTemplateTupleParameter()) 718 { 719 property("kind", "tuple"); 720 } 721 722 objectEnd(); 723 } 724 arrayEnd(); 725 Expression expression = d.constraint; 726 if (expression) 727 { 728 property("constraint", expression.toString()); 729 } 730 propertyStart("members"); 731 arrayStart(); 732 for (size_t i = 0; i < d.members.dim; i++) 733 { 734 Dsymbol s = (*d.members)[i]; 735 s.accept(this); 736 } 737 arrayEnd(); 738 objectEnd(); 739 } 740 741 override void visit(EnumDeclaration d) 742 { 743 if (d.isAnonymous()) 744 { 745 if (d.members) 746 { 747 for (size_t i = 0; i < d.members.dim; i++) 748 { 749 Dsymbol s = (*d.members)[i]; 750 s.accept(this); 751 } 752 } 753 return; 754 } 755 objectStart(); 756 jsonProperties(d); 757 property("base", "baseDeco", d.memtype); 758 if (d.members) 759 { 760 propertyStart("members"); 761 arrayStart(); 762 for (size_t i = 0; i < d.members.dim; i++) 763 { 764 Dsymbol s = (*d.members)[i]; 765 s.accept(this); 766 } 767 arrayEnd(); 768 } 769 objectEnd(); 770 } 771 772 override void visit(EnumMember s) 773 { 774 objectStart(); 775 jsonProperties(cast(Dsymbol)s); 776 property("type", "deco", s.origType); 777 objectEnd(); 778 } 779 780 override void visit(VarDeclaration d) 781 { 782 if (d.storage_class & STC.local) 783 return; 784 objectStart(); 785 jsonProperties(d); 786 if (d._init) 787 property("init", d._init.toString()); 788 if (d.isField()) 789 property("offset", d.offset); 790 if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT) 791 property("align", d.alignment); 792 objectEnd(); 793 } 794 795 override void visit(TemplateMixin d) 796 { 797 objectStart(); 798 jsonProperties(d); 799 objectEnd(); 800 } 801 802 /** 803 Generate an array of module objects that represent the syntax of each 804 "root module". 805 806 Params: 807 modules = array of the "root modules" 808 */ 809 private void generateModules(Modules* modules) 810 { 811 arrayStart(); 812 if (modules) 813 { 814 foreach (m; *modules) 815 { 816 if (global.params.verbose) 817 message("json gen %s", m.toChars()); 818 m.accept(this); 819 } 820 } 821 arrayEnd(); 822 } 823 824 /** 825 Generate the "compilerInfo" object which contains information about the compiler 826 such as the filename, version, supported features, etc. 827 */ 828 private void generateCompilerInfo() 829 { 830 objectStart(); 831 requiredProperty("vendor", global.vendor); 832 requiredProperty("version", global._version); 833 property("__VERSION__", global.versionNumber()); 834 requiredProperty("interface", determineCompilerInterface()); 835 property("size_t", size_t.sizeof); 836 propertyStart("platforms"); 837 arrayStart(); 838 if (global.params.isWindows) 839 { 840 item("windows"); 841 } 842 else 843 { 844 item("posix"); 845 if (global.params.isLinux) 846 item("linux"); 847 else if (global.params.isOSX) 848 item("osx"); 849 else if (global.params.isFreeBSD) 850 { 851 item("freebsd"); 852 item("bsd"); 853 } 854 else if (global.params.isOpenBSD) 855 { 856 item("openbsd"); 857 item("bsd"); 858 } 859 else if (global.params.isSolaris) 860 { 861 item("solaris"); 862 item("bsd"); 863 } 864 } 865 arrayEnd(); 866 867 propertyStart("architectures"); 868 arrayStart(); 869 if (global.params.is64bit) 870 item("x86_64"); 871 else 872 version(X86) item("x86"); 873 arrayEnd(); 874 875 propertyStart("predefinedVersions"); 876 arrayStart(); 877 if (global.versionids) 878 { 879 foreach (const versionid; *global.versionids) 880 { 881 item(versionid.toString()); 882 } 883 } 884 arrayEnd(); 885 886 propertyStart("supportedFeatures"); 887 { 888 objectStart(); 889 scope(exit) objectEnd(); 890 propertyBool("includeImports", true); 891 } 892 objectEnd(); 893 } 894 895 /** 896 Generate the "buildInfo" object which contains information specific to the 897 current build such as CWD, importPaths, configFile, etc. 898 */ 899 private void generateBuildInfo() 900 { 901 objectStart(); 902 requiredProperty("cwd", getcwd(null, 0).toDString); 903 requiredProperty("argv0", global.params.argv0); 904 requiredProperty("config", global.inifilename); 905 requiredProperty("libName", global.params.libname); 906 907 propertyStart("importPaths"); 908 arrayStart(); 909 if (global.params.imppath) 910 { 911 foreach (importPath; *global.params.imppath) 912 { 913 item(importPath.toDString); 914 } 915 } 916 arrayEnd(); 917 918 propertyStart("objectFiles"); 919 arrayStart(); 920 foreach (objfile; global.params.objfiles) 921 { 922 item(objfile.toDString); 923 } 924 arrayEnd(); 925 926 propertyStart("libraryFiles"); 927 arrayStart(); 928 foreach (lib; global.params.libfiles) 929 { 930 item(lib.toDString); 931 } 932 arrayEnd(); 933 934 propertyStart("ddocFiles"); 935 arrayStart(); 936 foreach (ddocFile; global.params.ddocfiles) 937 { 938 item(ddocFile.toDString); 939 } 940 arrayEnd(); 941 942 requiredProperty("mapFile", global.params.mapfile); 943 requiredProperty("resourceFile", global.params.resfile); 944 requiredProperty("defFile", global.params.deffile); 945 946 objectEnd(); 947 } 948 949 /** 950 Generate the "semantics" object which contains a 'modules' field representing 951 semantic information about all the modules used in the compilation such as 952 module name, isRoot, contentImportedFiles, etc. 953 */ 954 private void generateSemantics() 955 { 956 objectStart(); 957 propertyStart("modules"); 958 arrayStart(); 959 foreach (m; Module.amodules) 960 { 961 objectStart(); 962 requiredProperty("name", m.md ? m.md.toString() : null); 963 requiredProperty("file", m.srcfile.toString()); 964 propertyBool("isRoot", m.isRoot()); 965 if(m.contentImportedFiles.dim > 0) 966 { 967 propertyStart("contentImports"); 968 arrayStart(); 969 foreach (file; m.contentImportedFiles) 970 { 971 item(file.toDString); 972 } 973 arrayEnd(); 974 } 975 objectEnd(); 976 } 977 arrayEnd(); 978 objectEnd(); 979 } 980 } 981 982 extern (C++) void json_generate(OutBuffer* buf, Modules* modules) 983 { 984 scope ToJsonVisitor json = new ToJsonVisitor(buf); 985 // write trailing newline 986 scope(exit) buf.writeByte('\n'); 987 988 if (global.params.jsonFieldFlags == 0) 989 { 990 // Generate the original format, which is just an array 991 // of modules representing their syntax. 992 json.generateModules(modules); 993 json.removeComma(); 994 } 995 else 996 { 997 // Generate the new format which is an object where each 998 // output option is its own field. 999 1000 json.objectStart(); 1001 if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo) 1002 { 1003 json.propertyStart("compilerInfo"); 1004 json.generateCompilerInfo(); 1005 } 1006 if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo) 1007 { 1008 json.propertyStart("buildInfo"); 1009 json.generateBuildInfo(); 1010 } 1011 if (global.params.jsonFieldFlags & JsonFieldFlags.modules) 1012 { 1013 json.propertyStart("modules"); 1014 json.generateModules(modules); 1015 } 1016 if (global.params.jsonFieldFlags & JsonFieldFlags.semantics) 1017 { 1018 json.propertyStart("semantics"); 1019 json.generateSemantics(); 1020 } 1021 json.objectEnd(); 1022 } 1023 } 1024 1025 /** 1026 A string listing the name of each JSON field. Useful for errors messages. 1027 */ 1028 enum jsonFieldNames = () { 1029 string s; 1030 string prefix = ""; 1031 foreach (idx, enumName; __traits(allMembers, JsonFieldFlags)) 1032 { 1033 static if (idx > 0) 1034 { 1035 s ~= prefix ~ "`" ~ enumName ~ "`"; 1036 prefix = ", "; 1037 } 1038 } 1039 return s; 1040 }(); 1041 1042 /** 1043 Parse the given `fieldName` and return its corresponding JsonFieldFlags value. 1044 1045 Params: 1046 fieldName = the field name to parse 1047 1048 Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value 1049 corresponding to the given fieldName. 1050 */ 1051 extern (C++) JsonFieldFlags tryParseJsonField(const(char)* fieldName) 1052 { 1053 auto fieldNameString = fieldName.toDString(); 1054 foreach (idx, enumName; __traits(allMembers, JsonFieldFlags)) 1055 { 1056 static if (idx > 0) 1057 { 1058 if (fieldNameString == enumName) 1059 return __traits(getMember, JsonFieldFlags, enumName); 1060 } 1061 } 1062 return JsonFieldFlags.none; 1063 } 1064 1065 /** 1066 Determines and returns the compiler interface which is one of `dmd`, `ldc`, 1067 `gdc` or `sdc`. Returns `null` if no interface can be determined. 1068 */ 1069 private extern(D) string determineCompilerInterface() 1070 { 1071 if (global.vendor == "Digital Mars D") 1072 return "dmd"; 1073 if (global.vendor == "LDC") 1074 return "ldc"; 1075 if (global.vendor == "GNU D") 1076 return "gdc"; 1077 if (global.vendor == "SDC") 1078 return "sdc"; 1079 return null; 1080 }