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