comparison orange/util/Reflection.d @ 1:11a31bd929f9

Removed dependency on private library
author Jacob Carlborg <doob@me.com>
date Mon, 31 May 2010 16:06:36 +0200
parents f7b078e85f7f
children 32152d5fad4b
comparison
equal deleted inserted replaced
0:f7b078e85f7f 1:11a31bd929f9
1 /** 1 /**
2 * Copyright: Copyright (c) 2010 Jacob Carlborg. 2 * Copyright: Copyright (c) 2009 Jacob Carlborg.
3 * Authors: Jacob Carlborg 3 * Authors: Jacob Carlborg
4 * Version: Initial created: Jan 26, 2010 4 * Version: Initial created: Oct 5, 2009
5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6 */ 6 */
7 module orange.util.Reflection; 7 module orange.util.Reflection;
8 8
9 public import mambo.util.Reflection; 9 import orange.util.CTFE;
10 import orange.util.string;
11
12 /**
13 * Returns the name of the given function
14 *
15 * Params:
16 * func = the function alias to get the name of
17 *
18 * Returns: the name of the function
19 */
20 template functionNameOf (alias func)
21 {
22 version(LDC)
23 const functionNameOf = (&func).stringof[1 .. $];
24
25 else
26 const functionNameOf = (&func).stringof[2 .. $];
27 }
28
29 /**
30 * Returns the parameter names of the given function
31 *
32 * Params:
33 * func = the function alias to get the parameter names of
34 *
35 * Returns: an array of strings containing the parameter names
36 */
37 template parameterNamesOf (alias func)
38 {
39 const parameterNamesOf = parameterNamesOfImpl!(func);
40 }
41
42 /**
43 * Returns the parameter names of the given function
44 *
45 * Params:
46 * func = the function alias to get the parameter names of
47 *
48 * Returns: an array of strings containing the parameter names
49 */
50 private string[] parameterNamesOfImpl (alias func) ()
51 {
52 string funcStr = typeof(&func).stringof;
53
54 auto start = funcStr.indexOf('(');
55 auto end = funcStr.indexOf(')');
56
57 const firstPattern = ' ';
58 const secondPattern = ',';
59
60 funcStr = funcStr[start + 1 .. end];
61
62 if (funcStr == "")
63 return null;
64
65 funcStr ~= secondPattern;
66
67 string token;
68 string[] arr;
69
70 foreach (c ; funcStr)
71 {
72 if (c != firstPattern && c != secondPattern)
73 token ~= c;
74
75 else
76 {
77 if (token)
78 arr ~= token;
79
80 token = null;
81 }
82 }
83
84 if (arr.length == 1)
85 return arr;
86
87 string[] result;
88 bool skip = false;
89
90 foreach (str ; arr)
91 {
92 skip = !skip;
93
94 if (skip)
95 continue;
96
97 result ~= str;
98 }
99
100 return result;
101 }
102
103 /**
104 * Helper function for callWithNamedArguments
105 *
106 * Returns:
107 */
108 private string buildFunction (alias func, string args) ()
109 {
110 const str = split(args);
111 string[] params;
112 string[] values;
113 auto mixinString = functionNameOf!(func) ~ "(";
114
115 foreach (s ; str)
116 {
117 auto index = s.indexOf('=');
118 params ~= s[0 .. index];
119 values ~= s[index + 1 .. $];
120 }
121
122 const parameterNames = parameterNamesOf!(func);
123
124 foreach (i, s ; parameterNames)
125 {
126 auto index = params.indexOf(s);
127
128 if (index != params.length)
129 mixinString ~= values[index] ~ ",";
130 }
131
132 return mixinString[0 .. $ - 1] ~ ");";
133 }
134
135 /**
136 * Calls the given function with named arguments
137 *
138 * Params:
139 * func = an alias to the function to call
140 * args = a string containing the arguments to call using this syntax: `arg2=value,arg1="value"`
141 */
142 void callWithNamedArguments (alias func, string args) ()
143 {
144 mixin(buildFunction!(func, args));
145 }
146
147 /**
148 * Evaluates to true if T has a instance method with the given name
149 *
150 * Params:
151 * T = the type of the class/struct
152 * method = the name of the method
153 */
154 template hasInstanceMethod (T, string method)
155 {
156 const hasInstanceMethod = is(typeof({
157 T t;
158 mixin("auto f = &t." ~ method ~ ";");
159 }));
160 }
161
162 /**
163 * Evaluates to true if T has a class method with the given name
164 *
165 * Params:
166 * T = the type of the class/struct
167 * method = the name of the method
168 */
169 template hasClassMethod (T, string method)
170 {
171 const hasClassMethod = is(typeof({
172 mixin("auto f = &T." ~ method ~ ";");
173 }));
174 }
175
176 /**
177 * Evaluates to true if T has a either a class method or a instance method with the given name
178 *
179 * Params:
180 * T = the type of the class/struct
181 * method = the name of the method
182 */
183 template hasMethod (T, string method)
184 {
185 const hasMethod = hasClassMethod!(T, method) || hasInstanceMethod!(T, method);
186 }
187
188 /**
189 * Evaluates to true if T has a field with the given name
190 *
191 * Params:
192 * T = the type of the class/struct
193 * field = the name of the field
194 */
195 template hasField (T, string field)
196 {
197 const hasField = hasFieldImpl!(T, field, 0);
198 }
199
200 private template hasFieldImpl (T, string field, size_t i)
201 {
202 static if (T.tupleof.length == i)
203 const hasFieldImpl = false;
204
205 else static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
206 const hasFieldImpl = true;
207
208 else
209 const hasFieldImpl = hasFieldImpl!(T, field, i + 1);
210 }
211
212 /**
213 * Evaluates to an array of strings containing the names of the fields in the given type
214 */
215 template fieldsOf (T)
216 {
217 const fieldsOf = fieldsOfImpl!(T, 0);
218 }
219
220 /**
221 * Implementation for fieldsOf
222 *
223 * Returns: an array of strings containing the names of the fields in the given type
224 */
225 template fieldsOfImpl (T, size_t i)
226 {
227 static if (T.tupleof.length == 0)
228 const fieldsOfImpl = [""];
229
230 else static if (T.tupleof.length - 1 == i)
231 const fieldsOfImpl = [T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $]];
232
233 else
234 const fieldsOfImpl = T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] ~ fieldsOfImpl!(T, i + 1);
235 }
236
237 /**
238 * Evaluates to the type of the field with the given name
239 *
240 * Params:
241 * T = the type of the class/struct
242 * field = the name of the field
243 */
244 template TypeOfField (T, string field)
245 {
246 static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
247
248 alias TypeOfFieldImpl!(T, field, 0) TypeOfField;
249 }
250
251 private template TypeOfFieldImpl (T, string field, size_t i)
252 {
253 static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field)
254 alias typeof(T.tupleof[i]) TypeOfFieldImpl;
255
256 else
257 alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl;
258 }
259
260 /**
261 * Evaluates to a string containing the name of the field at given position in the type given type.
262 *
263 * Params:
264 * T = the type of the class/struct
265 * position = the position of the field in the tupleof array
266 */
267 template nameOfFieldAt (T, size_t position)
268 {
269 static if (T.tupleof[position].stringof.length > T.stringof.length + 3)
270 const nameOfFieldAt = T.tupleof[position].stringof[1 + T.stringof.length + 2 .. $];
271
272 else
273 const nameOfFieldAt = "";
274 }
275
276 /**
277 * Sets the given value to the filed with the given name
278 *
279 * Params:
280 * t = an instance of the type that has the field
281 * value = the value to set
282 */
283 void setValueOfField (T, U, string field) (ref T t, U value)
284 in
285 {
286 static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
287 }
288 body
289 {
290 const len = T.stringof.length;
291
292 foreach (i, dummy ; typeof(T.tupleof))
293 {
294 const f = T.tupleof[i].stringof[1 + len + 2 .. $];
295
296 static if (f == field)
297 {
298 t.tupleof[i] = value;
299 break;
300 }
301 }
302 }
303
304 /**
305 * Gets the value of the field with the given name
306 *
307 * Params:
308 * t = an instance of the type that has the field
309 *
310 * Returns: the value of the field
311 */
312 U getValueOfField (T, U, string field) (T t)
313 in
314 {
315 static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\"");
316 }
317 body
318 {
319 const len = T.stringof.length;
320
321 foreach (i, dummy ; typeof(T.tupleof))
322 {
323 const f = T.tupleof[i].stringof[1 + len + 2 .. $];
324
325 static if (f == field)
326 return t.tupleof[i];
327 }
328 }
329
330 /**
331 * Gets all the class names in the given string of D code
332 *
333 * Params:
334 * code = a string containg the code to get the class names from
335 *
336 * Returns: the class names
337 */
338 string[] getClassNames (string code) ()
339 {
340 const fileContent = code;
341 const classString = "class";
342 bool foundPossibleClass;
343 bool foundClass;
344 string[] classNames;
345 string className;
346
347 for (size_t i = 0; i < fileContent.length; i++)
348 {
349 final c = fileContent[i];
350
351 if (foundPossibleClass)
352 {
353 if (c == ' ' || c == '\n')
354 foundClass = true;
355
356 foundPossibleClass = false;
357 }
358
359 else if (foundClass)
360 {
361 if (c == '{')
362 {
363 classNames ~= className;
364 foundClass = false;
365 className = "";
366 }
367
368 else if (c != ' ' && c != '\n')
369 className ~= c;
370 }
371
372 else
373 {
374 if (i + classString.length < fileContent.length)
375 {
376 if (fileContent[i .. i + classString.length] == classString)
377 {
378 if (i > 0)
379 {
380 if (fileContent[i - 1] == ' ' || fileContent[i - 1] == '\n' || fileContent[i - 1] == ';' || fileContent[i - 1] == '}')
381 {
382 foundPossibleClass = true;
383 i += classString.length - 1;
384 continue;
385 }
386 }
387
388 else
389 {
390 foundPossibleClass = true;
391 i += classString.length - 1;
392 continue;
393 }
394 }
395 }
396 }
397 }
398
399 return classNames;
400 }
401
402 /**
403 * Creates a new instance of class with the given name
404 *
405 * Params:
406 * name = the fully qualified name of the class
407 * args = the arguments to the constructor
408 *
409 * Returns: the newly created instance or null
410 */
411 T factory (T, ARGS...) (string name, ARGS args)
412 {
413 auto classInfo = ClassInfo.find(name);
414
415 if (!classInfo)
416 return null;
417
418 auto object = newInstance(classInfo);
419
420 if (classInfo.flags & 8 && classInfo.defaultConstructor is null)
421 {
422 auto o = cast(T) object;
423
424 static if (is(typeof(o._ctor(args))))
425 return o._ctor(args);
426
427 else
428 return null;
429 }
430
431 else
432 {
433 if (classInfo.flags & 8 && classInfo.defaultConstructor !is null)
434 {
435 Object delegate () ctor;
436 ctor.ptr = cast(void*) object;
437 ctor.funcptr = cast(Object function()) classInfo.defaultConstructor;
438
439 return cast(T) ctor();
440 }
441
442 else
443 return cast(T) object;
444 }
445 }
446
447 private
448 {
449 version (LDC)
450 extern (C) Object _d_allocclass(ClassInfo);
451
452 else
453 extern (C) Object _d_newclass(ClassInfo);
454 }
455
456 Object newInstance (ClassInfo classInfo)
457 {
458 version (LDC)
459 {
460 Object object = _d_allocclass(classInfo);
461 (cast(byte*) object)[0 .. classInfo.init.length] = classInfo.init[];
462
463 return object;
464 }
465
466 else
467 return _d_newclass(classInfo);
468 }