1 /**
2  * Copyright: Copyright (c) 2012 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Jan 30, 2012
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module dstep.translator.Type;
8 
9 import mambo.core..string;
10 import mambo.core.io;
11 
12 import clang.c.Index;
13 import clang.Type;
14 
15 import dstep.translator.IncludeHandler;
16 import dstep.translator.Translator;
17 import dstep.translator.Output;
18 
19 string translateType (Type type, bool rewriteIdToObjcObject = true, bool applyConst = true)
20 in
21 {
22     assert(type.isValid);
23 }
24 body
25 {
26     string result;
27 
28     with (CXTypeKind)
29     {
30         if (type.kind == CXType_BlockPointer || type.isFunctionPointerType)
31             result = translateFunctionPointerType(type);
32 
33         else if (type.kind == CXType_ObjCObjectPointer && !type.isObjCBuiltinType)
34             result = translateObjCObjectPointerType(type);
35 
36         else if (type.isWideCharType)
37             result = "wchar";
38 
39         else if (type.isObjCIdType)
40             result = rewriteIdToObjcObject ? "ObjcObject" : "id";
41 
42         else
43             switch (type.kind)
44             {
45                 case CXType_Pointer: return translatePointer(type, rewriteIdToObjcObject, applyConst);
46                 case CXType_Typedef: result = translateTypedef(type); break;
47 
48                 case CXType_Record:
49                 case CXType_Enum:
50                 case CXType_ObjCInterface:
51                     result = type.spelling;
52 
53                     if (result.isEmpty)
54                         result = getAnonymousName(type.declaration);
55 
56                     handleInclude(type);
57                 break;
58 
59                 case CXType_ConstantArray: result = translateConstantArray(type, rewriteIdToObjcObject); break;
60                 case CXType_Unexposed: result = translateUnexposed(type, rewriteIdToObjcObject); break;
61 
62                 default: result = translateType(type.kind, rewriteIdToObjcObject);
63             }
64     }
65 
66     version (D1)
67     {
68         // ignore const
69     }
70     else
71     {
72         if (applyConst && type.isConst)
73             result = "const " ~ result;
74     }
75 
76     return result;
77 }
78 
79 string translateSelector (string str, bool fullName = false, bool translateIdentifier = true)
80 {
81     if (fullName)
82         str = str.replace(":", "_");
83 
84     else
85     {
86         auto i = str.indexOf(":");
87 
88         if (i > -1)
89             str = str[0 .. i];
90     }
91 
92     return translateIdentifier ? .translateIdentifier(str) : str;
93 }
94 
95 private:
96 
97 string translateTypedef (Type type)
98 in
99 {
100     assert(type.kind == CXTypeKind.CXType_Typedef);
101 }
102 body
103 {
104     auto spelling = type.spelling;
105 
106     with (CXTypeKind)
107         switch (spelling)
108         {
109             case "BOOL": return translateType(CXType_Bool);
110 
111             case "int64_t": return translateType(CXType_LongLong);
112             case "int32_t": return translateType(CXType_Int);
113             case "int16_t": return translateType(CXType_Short);
114             case "int8_t": return "byte";
115 
116             case "uint64_t": return translateType(CXType_ULongLong);
117             case "uint32_t": return translateType(CXType_UInt);
118             case "uint16_t": return translateType(CXType_UShort);
119             case "uint8_t": return translateType(CXType_UChar);
120 
121             case "size_t":
122             case "ptrdiff_t":
123             case "sizediff_t":
124                 return spelling;
125 
126             case "wchar_t":
127                 auto kind = type.canonicalType.kind;
128 
129                 if (kind == CXType_Int)
130                     return "dchar";
131 
132                 else if (kind == CXType_Short)
133                     return "wchar";
134 
135             default: break;
136         }
137 
138     handleInclude(type);
139 
140     return spelling;
141 }
142 
143 string translateUnexposed (Type type, bool rewriteIdToObjcObject)
144 in
145 {
146     assert(type.kind == CXTypeKind.CXType_Unexposed);
147 }
148 body
149 {
150     auto declaration = type.declaration;
151 
152     if (declaration.isValid)
153         return translateType(declaration.type, rewriteIdToObjcObject);
154 
155     else
156         return translateType(type.kind, rewriteIdToObjcObject);
157 }
158 
159 string translateConstantArray (Type type, bool rewriteIdToObjcObject)
160 in
161 {
162     assert(type.kind == CXTypeKind.CXType_ConstantArray);
163 }
164 body
165 {
166     auto array = type.array;
167     auto elementType = translateType(array.elementType, rewriteIdToObjcObject);
168 
169     return elementType ~ '[' ~ array.size.toString ~ ']';
170 }
171 
172 string translatePointer (Type type, bool rewriteIdToObjcObject, bool applyConst)
173 in
174 {
175     assert(type.kind == CXTypeKind.CXType_Pointer);
176 }
177 body
178 {
179     static bool valueTypeIsConst (Type type)
180     {
181         auto pointee = type.pointeeType;
182 
183         while (pointee.kind == CXTypeKind.CXType_Pointer)
184             pointee = pointee.pointeeType;
185 
186         return pointee.isConst;
187     }
188 
189     auto result = translateType(type.pointeeType, rewriteIdToObjcObject, false);
190 
191     version (D1)
192     {
193         result = result ~ '*';
194     }
195     else
196     {
197         if (applyConst && valueTypeIsConst(type))
198         {
199             if (type.isConst)
200                 result = "const " ~ result ~ '*';
201 
202             else
203                 result = "const(" ~ result ~ ")*";
204         }
205         else
206             result = result ~ '*';
207     }
208 
209     return result;
210 }
211 
212 string translateFunctionPointerType (Type type)
213 in
214 {
215     assert(type.kind == CXTypeKind.CXType_BlockPointer || type.isFunctionPointerType);
216 }
217 body
218 {
219     auto func = type.pointeeType.func;
220 
221     Parameter[] params;
222     params.reserve(func.arguments.length);
223 
224     foreach (type ; func.arguments)
225         params ~= Parameter(translateType(type));
226 
227     auto resultType = translateType(func.resultType);
228 
229     return translateFunction(resultType, "function", params, func.isVariadic, new String);
230 }
231 
232 string translateObjCObjectPointerType (Type type)
233 in
234 {
235     assert(type.kind == CXTypeKind.CXType_ObjCObjectPointer && !type.isObjCBuiltinType);
236 }
237 body
238 {
239     auto pointee = type.pointeeType;
240 
241     if (pointee.spelling == "Protocol")
242         return "Protocol*";
243 
244     else
245         return translateType(pointee);
246 }
247 
248 string translateType (CXTypeKind kind, bool rewriteIdToObjcObject = true)
249 {
250     with (CXTypeKind)
251         switch (kind)
252         {
253             case CXType_Invalid: return "<unimplemented>";
254             case CXType_Unexposed: return "<unimplemented>";
255             case CXType_Void: return "void";
256             case CXType_Bool: return "bool";
257             case CXType_Char_U: return "<unimplemented>";
258             case CXType_UChar: return "ubyte";
259             case CXType_Char16: return "wchar";
260             case CXType_Char32: return "dchar";
261             case CXType_UShort: return "ushort";
262             case CXType_UInt: return "uint";
263 
264             case CXType_ULong:
265                 includeHandler.addCompatible();
266                 return "c_ulong";
267 
268             case CXType_ULongLong: return "ulong";
269             case CXType_UInt128: return "<unimplemented>";
270             case CXType_Char_S: return "char";
271             case CXType_SChar: return "byte";
272             case CXType_WChar: return "wchar";
273             case CXType_Short: return "short";
274             case CXType_Int: return "int";
275 
276             case CXType_Long:
277                 includeHandler.addCompatible();
278                 return "c_long";
279 
280             case CXType_LongLong: return "long";
281             case CXType_Int128: return "<unimplemented>";
282             case CXType_Float: return "float";
283             case CXType_Double: return "double";
284             case CXType_LongDouble: return "real";
285             case CXType_NullPtr: return "null";
286             case CXType_Overload: return "<unimplemented>";
287             case CXType_Dependent: return "<unimplemented>";
288             case CXType_ObjCId: return rewriteIdToObjcObject ? "ObjcObject" : "id";
289             case CXType_ObjCClass: return "Class";
290             case CXType_ObjCSel: return "SEL";
291 
292             case CXType_Complex:
293             case CXType_Pointer:
294             case CXType_BlockPointer:
295             case CXType_LValueReference:
296             case CXType_RValueReference:
297             case CXType_Record:
298             case CXType_Enum:
299             case CXType_Typedef:
300             case CXType_FunctionNoProto:
301             case CXType_FunctionProto:
302             case CXType_Vector:
303             case CXType_IncompleteArray:
304             case CXType_VariableArray:
305             case CXType_DependentSizedArray:
306             case CXType_MemberPointer:
307                 return "<unimplemented>";
308 
309             default: assert(0, "Unhandled type kind " ~ kind.toString);
310         }
311 }