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