2 * Code for generating .json descriptions of the module when passing the `-X` flag to dmd.
4 * Copyright: Copyright (C) 1999-2022 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
14 import core
.stdc
.stdio
;
15 import core
.stdc
.string
;
17 import dmd
.arraytypes
;
22 import dmd
.declaration
;
29 import dmd
.expression
;
34 import dmd
.identifier
;
36 import dmd
.common
.outbuffer
;
37 import dmd
.root
.rootobject
;
38 import dmd
.root
.string
;
43 extern (C
) char* getcwd(char* buffer
, size_t maxlen
);
45 import core
.sys
.posix
.unistd
: getcwd
;
48 private extern (C
++) final class ToJsonVisitor
: Visitor
50 alias visit
= Visitor
.visit
;
54 const(char)[] filename
;
56 extern (D
) this(OutBuffer
* buf
)
64 if (buf
.length
>= 1 && (*buf
)[buf
.length
- 1] == '\n')
65 for (int i
= 0; i
< indentLevel
; i
++)
71 if (buf
.length
>= 2 && (*buf
)[buf
.length
- 2] == ',' && ((*buf
)[buf
.length
- 1] == '\n' ||
(*buf
)[buf
.length
- 1] == ' '))
72 buf
.setsize(buf
.length
- 2);
78 buf
.writestring(",\n");
91 extern(D
) void stringPart(const char[] s
)
98 buf
.writestring("\\n");
101 buf
.writestring("\\r");
104 buf
.writestring("\\t");
107 buf
.writestring("\\\"");
110 buf
.writestring("\\\\");
113 buf
.writestring("\\b");
116 buf
.writestring("\\f");
120 buf
.printf("\\u%04x", c
);
123 // Note that UTF-8 chars pass through here just fine
131 // Json value functions
132 /*********************************
133 * Encode string into buf, and wrap it in double quotes.
135 extern(D
) void value(const char[] s
)
142 void value(int value
)
152 void valueBool(bool value
)
154 buf
.writestring(value ?
"true" : "false");
157 /*********************************
158 * Item is an intented value and a comma, for use in arrays
160 extern(D
) void item(const char[] s
)
174 void itemBool(const bool b
)
181 // Json array functions
185 buf
.writestring("[\n");
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] == '['))
197 buf
.writestring("\n");
200 buf
.writestring("]");
204 // Json object functions
208 buf
.writestring("{\n");
216 if (buf
.length
>= 2 && (*buf
)[buf
.length
- 2] == '{' && (*buf
)[buf
.length
- 1] == '\n')
217 buf
.setsize(buf
.length
- 1);
220 buf
.writestring("\n");
223 buf
.writestring("}");
227 // Json object property functions
228 extern(D
) void propertyStart(const char[] name
)
232 buf
.writestring(" : ");
236 Write the given string object property only if `s` is not null.
239 name = the name of the object property
240 s = the string value of the object property
242 extern(D
) void property(const char[] name
, const char[] s
)
252 Write the given string object property.
255 name = the name of the object property
256 s = the string value of the object property
258 extern(D
) void requiredProperty(const char[] name
, const char[] s
)
262 buf
.writestring("null");
268 extern(D
) void property(const char[] name
, int i
)
275 extern(D
) void propertyBool(const char[] name
, const bool b
)
282 extern(D
) void property(const char[] name
, TRUST trust
)
287 // Should not be printed
288 //property(name, "default");
290 case TRUST
.system
: return property(name
, "system");
291 case TRUST
.trusted
: return property(name
, "trusted");
292 case TRUST
.safe
: return property(name
, "safe");
296 extern(D
) void property(const char[] name
, PURE purity
)
298 final switch (purity
)
301 // Should not be printed
302 //property(name, "impure");
304 case PURE
.weak
: return property(name
, "weak");
305 case PURE
.const_
: return property(name
, "strong");
306 case PURE
.fwdref
: return property(name
, "fwdref");
310 extern(D
) void property(const char[] name
, const LINK linkage
)
312 final switch (linkage
)
315 // Should not be printed
316 //property(name, "default");
319 // Should not be printed
320 //property(name, "d");
322 case LINK
.system
: return property(name
, "system");
323 case LINK
.c
: return property(name
, "c");
324 case LINK
.cpp
: return property(name
, "cpp");
325 case LINK
.windows
: return property(name
, "windows");
326 case LINK
.objc
: return property(name
, "objc");
330 extern(D
) void propertyStorageClass(const char[] name
, StorageClass
stc)
332 stc &= STC
.visibleStorageClasses
;
339 auto p
= stcToString(stc);
347 extern(D
) void property(const char[] linename
, const char[] charname
, const ref Loc loc
)
351 if (auto filename
= loc
.filename
.toDString
)
353 if (filename
!= this.filename
)
355 this.filename
= filename
;
356 property("file", filename
);
361 property(linename
, loc
.linnum
);
363 property(charname
, loc
.charnum
);
368 extern(D
) void property(const char[] name
, Type type
)
372 property(name
, type
.toString());
376 extern(D
) void property(const char[] name
, const char[] deconame
, Type type
)
381 property(deconame
, type
.deco
.toDString
);
383 property(name
, type
.toString());
387 extern(D
) void property(const char[] name
, Parameters
* parameters
)
389 if (parameters
is null || parameters
.dim
== 0)
395 for (size_t i
= 0; i
< parameters
.dim
; i
++)
397 Parameter p
= (*parameters
)[i
];
400 property("name", p
.ident
.toString());
401 property("type", "deco", p
.type
);
402 propertyStorageClass("storageClass", p
.storageClass
);
404 property("default", p
.defaultArg
.toString());
411 /* ========================================================================== */
412 void jsonProperties(Dsymbol s
)
416 if (!s
.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
418 property("name", s
.toString());
419 if (s
.isStaticCtorDeclaration())
421 property("kind", s
.isSharedStaticCtorDeclaration()
422 ?
"shared static constructor" : "static constructor");
424 else if (s
.isStaticDtorDeclaration())
426 property("kind", s
.isSharedStaticDtorDeclaration()
427 ?
"shared static destructor" : "static destructor");
430 property("kind", s
.kind
.toDString
);
432 // TODO: How about package(names)?
433 property("protection", visibilityToString(s
.visible().kind
));
434 if (EnumMember em
= s
.isEnumMember())
437 property("value", em
.origValue
.toString());
439 property("comment", s
.comment
.toDString
);
440 property("line", "char", s
.loc
);
443 void jsonProperties(Declaration d
)
445 if (d
.storage_class
& STC
.local
)
447 jsonProperties(cast(Dsymbol
)d
);
448 propertyStorageClass("storageClass", d
.storage_class
);
449 property("linkage", d
.linkage
);
450 property("type", "deco", d
.type
);
451 // Emit originalType if it differs from type
452 if (d
.type
!= d
.originalType
&& d
.originalType
)
454 auto ostr
= d
.originalType
.toString();
457 auto tstr
= d
.type
.toString();
460 //printf("tstr = %s, ostr = %s\n", tstr, ostr);
461 property("originalType", ostr
);
465 property("originalType", ostr
);
469 void jsonProperties(TemplateDeclaration td
)
471 jsonProperties(cast(Dsymbol
)td
);
472 if (td
.onemember
&& td
.onemember
.isCtorDeclaration())
473 property("name", "this"); // __ctor -> this
475 property("name", td
.ident
.toString()); // Foo(T) -> Foo
478 /* ========================================================================== */
479 override void visit(Dsymbol s
)
483 override void visit(Module s
)
487 property("name", s
.md
.toString());
488 property("kind", s
.kind
.toDString
);
489 filename
= s
.srcfile
.toString();
490 property("file", filename
);
491 property("comment", s
.comment
.toDString
);
492 propertyStart("members");
494 for (size_t i
= 0; i
< s
.members
.dim
; i
++)
496 (*s
.members
)[i
].accept(this);
502 override void visit(Import s
)
504 if (s
.id
== Id
.object
)
507 propertyStart("name");
509 foreach (const pid
; s
.packages
){
510 stringPart(pid
.toString());
513 stringPart(s
.id
.toString());
516 property("kind", s
.kind
.toDString
);
517 property("comment", s
.comment
.toDString
);
518 property("line", "char", s
.loc
);
519 if (s
.visible().kind
!= Visibility
.Kind
.public_
)
520 property("protection", visibilityToString(s
.visible().kind
));
522 property("alias", s
.aliasId
.toString());
523 bool hasRenamed
= false;
524 bool hasSelective
= false;
525 for (size_t i
= 0; i
< s
.aliases
.dim
; i
++)
527 // avoid empty "renamed" and "selective" sections
528 if (hasRenamed
&& hasSelective
)
530 else if (s
.aliases
[i
])
537 // import foo : alias1 = target1;
538 propertyStart("renamed");
540 for (size_t i
= 0; i
< s
.aliases
.dim
; i
++)
542 const name
= s
.names
[i
];
543 const _alias
= s
.aliases
[i
];
545 property(_alias
.toString(), name
.toString());
551 // import foo : target1;
552 propertyStart("selective");
554 foreach (i
, name
; s
.names
)
557 item(name
.toString());
564 override void visit(AttribDeclaration d
)
566 Dsymbols
* ds = d
.include(null);
569 for (size_t i
= 0; i
< ds.dim
; i
++)
571 Dsymbol s
= (*ds)[i
];
577 override void visit(ConditionalDeclaration d
)
579 if (d
.condition
.inc != Include
.notComputed
)
581 visit(cast(AttribDeclaration
)d
);
582 return; // Don't visit the if/else bodies again below
584 Dsymbols
* ds = d
.decl ? d
.decl
: d
.elsedecl
;
585 for (size_t i
= 0; i
< ds.dim
; i
++)
587 Dsymbol s
= (*ds)[i
];
592 override void visit(TypeInfoDeclaration d
)
596 override void visit(PostBlitDeclaration d
)
600 override void visit(Declaration d
)
603 //property("unknown", "declaration");
608 override void visit(AggregateDeclaration d
)
612 ClassDeclaration cd
= d
.isClassDeclaration();
615 if (cd
.baseClass
&& cd
.baseClass
.ident
!= Id
.Object
)
617 property("base", cd
.baseClass
.toPrettyChars(true).toDString
);
619 if (cd
.interfaces
.length
)
621 propertyStart("interfaces");
623 foreach (b
; cd
.interfaces
)
625 item(b
.sym
.toPrettyChars(true).toDString
);
632 propertyStart("members");
634 for (size_t i
= 0; i
< d
.members
.dim
; i
++)
636 Dsymbol s
= (*d
.members
)[i
];
644 override void visit(FuncDeclaration d
)
648 TypeFunction tf
= cast(TypeFunction
)d
.type
;
649 if (tf
&& tf
.ty
== Tfunction
)
650 property("parameters", tf
.parameterList
.parameters
);
651 property("endline", "endchar", d
.endloc
);
652 if (d
.foverrides
.dim
)
654 propertyStart("overrides");
656 for (size_t i
= 0; i
< d
.foverrides
.dim
; i
++)
658 FuncDeclaration fd
= d
.foverrides
[i
];
659 item(fd
.toPrettyChars().toDString
);
666 d
.fdrequire
.accept(this);
670 propertyStart("out");
671 d
.fdensure
.accept(this);
676 override void visit(TemplateDeclaration d
)
679 // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
680 property("kind", "template");
682 propertyStart("parameters");
684 for (size_t i
= 0; i
< d
.parameters
.dim
; i
++)
686 TemplateParameter s
= (*d
.parameters
)[i
];
688 property("name", s
.ident
.toString());
690 if (auto type
= s
.isTemplateTypeParameter())
692 if (s
.isTemplateThisParameter())
693 property("kind", "this");
695 property("kind", "type");
696 property("type", "deco", type
.specType
);
697 property("default", "defaultDeco", type
.defaultType
);
700 if (auto value
= s
.isTemplateValueParameter())
702 property("kind", "value");
703 property("type", "deco", value
.valType
);
705 property("specValue", value
.specValue
.toString());
706 if (value
.defaultValue
)
707 property("defaultValue", value
.defaultValue
.toString());
710 if (auto _alias
= s
.isTemplateAliasParameter())
712 property("kind", "alias");
713 property("type", "deco", _alias
.specType
);
714 if (_alias
.specAlias
)
715 property("specAlias", _alias
.specAlias
.toString());
716 if (_alias
.defaultAlias
)
717 property("defaultAlias", _alias
.defaultAlias
.toString());
720 if (auto tuple
= s
.isTemplateTupleParameter())
722 property("kind", "tuple");
728 Expression expression
= d
.constraint
;
731 property("constraint", expression
.toString());
733 propertyStart("members");
735 for (size_t i
= 0; i
< d
.members
.dim
; i
++)
737 Dsymbol s
= (*d
.members
)[i
];
744 override void visit(EnumDeclaration d
)
750 for (size_t i
= 0; i
< d
.members
.dim
; i
++)
752 Dsymbol s
= (*d
.members
)[i
];
760 property("base", "baseDeco", d
.memtype
);
763 propertyStart("members");
765 for (size_t i
= 0; i
< d
.members
.dim
; i
++)
767 Dsymbol s
= (*d
.members
)[i
];
775 override void visit(EnumMember s
)
778 jsonProperties(cast(Dsymbol
)s
);
779 property("type", "deco", s
.origType
);
783 override void visit(VarDeclaration d
)
785 if (d
.storage_class
& STC
.local
)
790 property("init", d
._init
.toString());
792 property("offset", d
.offset
);
793 if (!d
.alignment
.isUnknown() && !d
.alignment
.isDefault())
794 property("align", d
.alignment
.get());
798 override void visit(TemplateMixin d
)
806 Generate an array of module objects that represent the syntax of each
810 modules = array of the "root modules"
812 private void generateModules(Modules
* modules
)
817 foreach (m
; *modules
)
819 if (global
.params
.verbose
)
820 message("json gen %s", m
.toChars());
828 Generate the "compilerInfo" object which contains information about the compiler
829 such as the filename, version, supported features, etc.
831 private void generateCompilerInfo()
833 import dmd
.target
: target
;
835 requiredProperty("vendor", global
.vendor
);
836 requiredProperty("version", global
.versionString());
837 property("__VERSION__", global
.versionNumber());
838 requiredProperty("interface", determineCompilerInterface());
839 property("size_t", size_t
.sizeof
);
840 propertyStart("platforms");
842 if (target
.os
== Target
.OS
.Windows
)
849 if (target
.os
== Target
.OS
.linux
)
851 else if (target
.os
== Target
.OS
.OSX
)
853 else if (target
.os
== Target
.OS
.FreeBSD
)
858 else if (target
.os
== Target
.OS
.OpenBSD
)
863 else if (target
.os
== Target
.OS
.Solaris
)
871 propertyStart("architectures");
873 item(target
.architectureName
);
876 propertyStart("predefinedVersions");
878 if (global
.versionids
)
880 foreach (const versionid
; *global
.versionids
)
882 item(versionid
.toString());
887 propertyStart("supportedFeatures");
890 scope(exit
) objectEnd();
891 propertyBool("includeImports", true);
897 Generate the "buildInfo" object which contains information specific to the
898 current build such as CWD, importPaths, configFile, etc.
900 private void generateBuildInfo()
903 requiredProperty("cwd", getcwd(null, 0).toDString
);
904 requiredProperty("argv0", global
.params
.argv0
);
905 requiredProperty("config", global
.inifilename
);
906 requiredProperty("libName", global
.params
.libname
);
908 propertyStart("importPaths");
910 if (global
.params
.imppath
)
912 foreach (importPath
; *global
.params
.imppath
)
914 item(importPath
.toDString
);
919 propertyStart("objectFiles");
921 foreach (objfile
; global
.params
.objfiles
)
923 item(objfile
.toDString
);
927 propertyStart("libraryFiles");
929 foreach (lib
; global
.params
.libfiles
)
935 propertyStart("ddocFiles");
937 foreach (ddocFile
; global
.params
.ddocfiles
)
939 item(ddocFile
.toDString
);
943 requiredProperty("mapFile", global
.params
.mapfile
);
944 requiredProperty("resourceFile", global
.params
.resfile
);
945 requiredProperty("defFile", global
.params
.deffile
);
951 Generate the "semantics" object which contains a 'modules' field representing
952 semantic information about all the modules used in the compilation such as
953 module name, isRoot, contentImportedFiles, etc.
955 private void generateSemantics()
958 propertyStart("modules");
960 foreach (m
; Module
.amodules
)
963 requiredProperty("name", m
.md ? m
.md
.toString() : null);
964 requiredProperty("file", m
.srcfile
.toString());
965 propertyBool("isRoot", m
.isRoot());
966 if(m
.contentImportedFiles
.dim
> 0)
968 propertyStart("contentImports");
970 foreach (file
; m
.contentImportedFiles
)
972 item(file
.toDString
);
983 extern (C
++) void json_generate(OutBuffer
* buf
, Modules
* modules
)
985 scope ToJsonVisitor json
= new ToJsonVisitor(buf
);
986 // write trailing newline
987 scope(exit
) buf
.writeByte('\n');
989 if (global
.params
.jsonFieldFlags
== 0)
991 // Generate the original format, which is just an array
992 // of modules representing their syntax.
993 json
.generateModules(modules
);
998 // Generate the new format which is an object where each
999 // output option is its own field.
1002 if (global
.params
.jsonFieldFlags
& JsonFieldFlags
.compilerInfo
)
1004 json
.propertyStart("compilerInfo");
1005 json
.generateCompilerInfo();
1007 if (global
.params
.jsonFieldFlags
& JsonFieldFlags
.buildInfo
)
1009 json
.propertyStart("buildInfo");
1010 json
.generateBuildInfo();
1012 if (global
.params
.jsonFieldFlags
& JsonFieldFlags
.modules
)
1014 json
.propertyStart("modules");
1015 json
.generateModules(modules
);
1017 if (global
.params
.jsonFieldFlags
& JsonFieldFlags
.semantics
)
1019 json
.propertyStart("semantics");
1020 json
.generateSemantics();
1027 A string listing the name of each JSON field. Useful for errors messages.
1029 enum jsonFieldNames
= () {
1032 foreach (idx
, enumName
; __traits(allMembers
, JsonFieldFlags
))
1036 s
~= prefix
~ "`" ~ enumName
~ "`";
1044 Parse the given `fieldName` and return its corresponding JsonFieldFlags value.
1047 fieldName = the field name to parse
1049 Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value
1050 corresponding to the given fieldName.
1052 extern (C
++) JsonFieldFlags
tryParseJsonField(const(char)* fieldName
)
1054 auto fieldNameString
= fieldName
.toDString();
1055 foreach (idx
, enumName
; __traits(allMembers
, JsonFieldFlags
))
1059 if (fieldNameString
== enumName
)
1060 return __traits(getMember
, JsonFieldFlags
, enumName
);
1063 return JsonFieldFlags
.none
;
1067 Determines and returns the compiler interface which is one of `dmd`, `ldc`,
1068 `gdc` or `sdc`. Returns `null` if no interface can be determined.
1070 private extern(D
) string
determineCompilerInterface()
1072 if (global
.vendor
== "Digital Mars D")
1074 if (global
.vendor
== "LDC")
1076 if (global
.vendor
== "GNU D")
1078 if (global
.vendor
== "SDC")