1 /**
2  * Development utility for printing AST nodes by their internal name, instead of as D source code.
3  *
4  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:     Stefan Koch
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/asttypename.d, _asttypename.d)
8  * Documentation:  https://dlang.org/phobos/dmd_asttypename.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/asttypename.d
10  */
11 
12 module dmd.asttypename;
13 
14 import dmd.ast_node;
15 import dmd.attrib;
16 import dmd.aliasthis;
17 import dmd.aggregate;
18 import dmd.cond;
19 import dmd.ctfeexpr;
20 import dmd.dclass;
21 import dmd.declaration;
22 import dmd.denum;
23 import dmd.dimport;
24 import dmd.declaration;
25 import dmd.dstruct;
26 import dmd.dsymbol;
27 import dmd.dtemplate;
28 import dmd.dversion;
29 import dmd.expression;
30 import dmd.func;
31 import dmd.denum;
32 import dmd.dimport;
33 import dmd.dmodule;
34 import dmd.mtype;
35 import dmd.identifier;
36 import dmd.init;
37 import dmd.root.complex;
38 import dmd.rootobject;
39 import dmd.statement;
40 import dmd.staticassert;
41 import dmd.nspace;
42 import dmd.visitor;
43 
44 /// Returns: the typename of the dynamic ast-node-type
45 /// (this is a development tool, do not use in actual code)
46 string astTypeName(RootObject node)
47 {
48     final switch (node.dyncast())
49     {
50         case DYNCAST.object:
51             return "RootObject";
52         case DYNCAST.identifier:
53             return "Identifier";
54         case DYNCAST.tuple:
55             return "Tuple";
56 
57         case DYNCAST.expression:
58             return astTypeName(cast(Expression) node);
59         case DYNCAST.dsymbol:
60             return astTypeName(cast(Dsymbol) node);
61         case DYNCAST.type:
62             return astTypeName(cast(Type) node);
63         case DYNCAST.parameter:
64             return astTypeName(cast(Parameter) node);
65         case DYNCAST.statement:
66             return astTypeName(cast(Statement) node);
67         case DYNCAST.condition:
68             return astTypeName(cast(Condition) node);
69         case DYNCAST.templateparameter:
70             return astTypeName(cast(TemplateParameter) node);
71         case DYNCAST.initializer:
72             return astTypeName(cast(Initializer) node);
73     }
74 }
75 
76 extern(D) enum mixin_string =
77 ({
78     string astTypeNameFunctions;
79     string visitOverloads;
80 
81     foreach (ov; __traits(getOverloads, Visitor, "visit"))
82     {
83         static if (is(typeof(ov) P == function))
84         {
85             static if (is(P[0] S == super) && is(S[0] == ASTNode))
86             {
87                 astTypeNameFunctions ~= `
88 string astTypeName(` ~ P[0].stringof ~ ` node)
89 {
90     scope tsv = new AstTypeNameVisitor;
91     node.accept(tsv);
92     return tsv.typeName;
93 }
94 `;
95             }
96 
97             visitOverloads ~= `
98     override void visit (` ~ P[0].stringof ~ ` _)
99     {
100         typeName = "` ~ P[0].stringof ~ `";
101     }
102 `;
103         }
104     }
105 
106     return astTypeNameFunctions ~ `
107 private extern(C++) final class AstTypeNameVisitor : Visitor
108 {
109     alias visit = Visitor.visit;
110 public :
111     string typeName;
112 ` ~ visitOverloads ~ "}";
113 }());
114 
115 // pragma(msg, mixin_string);
116 mixin(mixin_string);
117 ///
118 unittest
119 {
120     import dmd.location;
121     Expression e = new TypeidExp(Loc.initial, null);
122     Tuple t = new Tuple();
123     TemplateTypeParameter tp = new TemplateTypeParameter(Loc.initial, null, null, null);
124     assert(e.astTypeName == "TypeidExp");
125     assert(t.astTypeName == "Tuple");
126     assert(tp.astTypeName == "TemplateTypeParameter");
127 }