Mercurial > projects > orange
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 } |