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 rewriteIdToObject = 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 = rewriteIdToObject ? "Object" : "id";
41 
42 		else
43 			switch (type.kind)
44 			{
45 				case CXType_Pointer: return translatePointer(type, rewriteIdToObject, 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, rewriteIdToObject); break;
60 				case CXType_Unexposed: result = translateUnexposed(type, rewriteIdToObject); break;
61 
62 				default: result = translateType(type.kind, rewriteIdToObject);
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 rewriteIdToObject)
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, rewriteIdToObject);
154 		
155 	else
156 		return translateType(type.kind, rewriteIdToObject);
157 }
158 
159 string translateConstantArray (Type type, bool rewriteIdToObject)
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, rewriteIdToObject);
168 	
169 	return elementType ~ '[' ~ array.size.toString ~ ']';
170 }
171 
172 string translatePointer (Type type, bool rewriteIdToObject, 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, rewriteIdToObject, 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 rewriteIdToObject = 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 "<unimplemented>";
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 rewriteIdToObject ? "Object" : "id";
289 			case CXType_ObjCClass: return "Class";
290 			case CXType_ObjCSel: return "SEL";
291 			case CXType_Complex: return "<unimplemented>";
292 			case CXType_Pointer: return "<unimplemented>";
293 			case CXType_BlockPointer: return "<unimplemented>";
294 			case CXType_LValueReference: return "<unimplemented>";
295 			case CXType_RValueReference: return "<unimplemented>";
296 			case CXType_Record: return "<unimplemented>";
297 			case CXType_Enum: return "<unimplemented>";
298 			case CXType_Typedef: return "<unimplemented>";
299 			case CXType_FunctionNoProto: return "<unimplemented>";
300 			case CXType_FunctionProto: return "<unimplemented>";
301 			case CXType_Vector: return "<unimplemented>";
302 			default: assert(0, "Unhandled type kind " ~ kind.toString);
303 		}
304 }