1 /**
2    From clang's cursors to dpp's nodes.
3  */
4 module dpp2.transform;
5 
6 
7 import dpp.from;
8 
9 
10 /**
11    Transforms a clang `Cursor` (or a mock) into a dpp `Node`
12  */
13 from!"dpp2.sea.node".Node[] toNode(C)(in C cursor) @trusted {
14 
15     import std.traits: isPointer;
16     import std.conv: text;
17 
18     static if(isPointer!C)
19         const cursorText = text(*cursor, " def? ", cursor.isDefinition);
20     else
21         const cursorText = text( cursor, " def? ", cursor.isDefinition);
22 
23     version(unittest) {
24         import unit_threaded;
25         () @trusted { writelnUt("toNode cursor: ", cursorText); }();
26     }
27 
28     auto transform = cursor.kind in transformations!C;
29 
30     if(transform is null)
31         throw new Exception("Unknown cursor kind: " ~ cursorText);
32 
33     return (*transform)(cursor);
34 }
35 
36 auto transformations(C)() {
37     import clang: Cursor;
38     with(Cursor.Kind) {
39         return [
40             TranslationUnit: &fromTranslationUnit!C,
41             StructDecl: &fromStruct!C,
42             FieldDecl: &fromField!C,
43             TypedefDecl: &fromTypedef!C,
44         ];
45     }
46 }
47 
48 from!"dpp2.sea.node".Node[] fromTranslationUnit(C)(in C cursor) @trusted
49     in(cursor.kind == from!"clang".Cursor.Kind.TranslationUnit)
50 do
51 {
52     import std.algorithm: filter, map;
53     import std.array: join;
54 
55     auto cursors = cursor.children
56         .filter!(a => a.isDefinition)
57         ;
58 
59     return cursors.map!(c => toNode(c)).join;
60 }
61 
62 
63 from!"dpp2.sea.node".Node[] fromStruct(C)(in C cursor) @trusted
64     in(cursor.kind == from!"clang".Cursor.Kind.StructDecl)
65 do
66 {
67     import dpp2.sea.node: Node, Struct;
68     import std.algorithm: map;
69     import std.array: join;
70 
71     return [
72         Node(
73             Struct(cursor.spelling,
74                    cursor.children.map!(c => toNode(c)).join,
75                    cursor.type.spelling),
76         )
77     ];
78 }
79 
80 
81 
82 from!"dpp2.sea.node".Node[] fromField(C)(in C cursor) @trusted
83     in(cursor.kind == from!"clang".Cursor.Kind.FieldDecl)
84 do
85 {
86     import dpp2.sea.node: Node, Field;
87     return [Node(Field(toType(cursor.type), cursor.spelling))];
88 }
89 
90 
91 from!"dpp2.sea.node".Node[] fromTypedef(C)(in C cursor) @trusted
92     in(cursor.kind == from!"clang".Cursor.Kind.TypedefDecl)
93 do
94 {
95     import dpp2.sea.node: Node, Typedef;
96     return [Node(Typedef(cursor.spelling, cursor.underlyingType.toType))];
97 }
98 
99 
100 from!"dpp2.sea.type".Type toType(T)(in T clangType) @safe {
101     import dpp2.sea.type;
102     import std.conv: text;
103 
104     alias Kind = clangType.Kind;
105 
106     switch(clangType.kind) {
107 
108         default:
109             throw new Exception(text("Unknown type kind: ", clangType));
110 
111         case Kind.Void: return Type(Void());
112         case Kind.NullPtr: return Type(NullPointerT());
113         case Kind.Bool: return Type(Bool());
114 
115         case Kind.WChar: return Type(Wchar());
116         case Kind.SChar: return Type(SignedChar());
117         case Kind.Char16: return Type(Char16());
118         case Kind.Char32: return Type(Char32());
119         case Kind.UChar: return Type(UnsignedChar());
120         case Kind.Char_U: return Type(UnsignedChar());
121         case Kind.Char_S: return Type(SignedChar());
122 
123         case Kind.UShort: return Type(UnsignedShort());
124         case Kind.Short: return Type(Short());
125         case Kind.Int: return Type(Int());
126         case Kind.UInt: return Type(UnsignedInt());
127         case Kind.Long: return Type(Long());
128         case Kind.ULong: return Type(UnsignedLong());
129         case Kind.LongLong: return Type(LongLong());
130         case Kind.ULongLong: return Type(UnsignedLongLong());
131         case Kind.Int128: return Type(Int128());
132         case Kind.UInt128: return Type(UnsignedInt128());
133 
134         case Kind.Half: return Type(Half());
135         case Kind.Float: return Type(Float());
136         case Kind.Double: return Type(Double());
137         case Kind.LongDouble: return Type(LongDouble());
138         case Kind.Float128: return Type(LongDouble());
139 
140         case Kind.Record:
141         case Kind.Elaborated:  // FIXME (could be enum or union)
142             return Type(UserDefinedType(clangType.spelling.unelaborate));
143     }
144 }
145 
146 
147 private string unelaborate(in string spelling) @safe pure {
148     import std.array: replace;
149     return spelling
150         .replace("struct ", "")
151         .replace("union ", "")
152         .replace("enum ", "")
153         ;
154 }