# HG changeset patch # User Jacob Carlborg # Date 1270546688 -7200 # Node ID 6825fcc47e39d67c974dfa6b49f41a0aad8460c3 # Parent b9de51448c6bfb7d6d43bd20f63bd9216a9c1e7c Added dstep.internal.Reflection diff -r b9de51448c6b -r 6825fcc47e39 dstep/internal/Reflection.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dstep/internal/Reflection.d Tue Apr 06 11:38:08 2010 +0200 @@ -0,0 +1,345 @@ +/** + * Copyright: Copyright (c) 2010 Jacob Carlborg. + * Authors: Jacob Carlborg + * Version: Initial created: Mar 8, 2010 + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) + */ +module dstep.internal.Reflection; + +import dstep.objc.bridge.Bridge; +import dstep.internal.String; + +/** + * Returns the name of the given function + * + * Params: + * func = the function alias to get the name of + * + * Returns: the name of the function + */ +template functionNameOf (alias func) +{ + version(LDC) + const functionNameOf = (&func).stringof[1 .. $]; + + else + const functionNameOf = (&func).stringof[2 .. $]; +} + +/** + * Returns the parameter names of the given function + * + * Params: + * func = the function alias to get the parameter names of + * + * Returns: an array of strings containing the parameter names + */ +template parameterNamesOf (alias func) +{ + const parameterNamesOf = parameterNamesOfImpl!(func); +} + +private string[] parameterNamesOfImpl (alias func) () +{ + string funcStr = typeof(&func).stringof; + + auto start = funcStr.indexOf('('); + auto end = funcStr.indexOf(')'); + + const firstPattern = ' '; + const secondPattern = ','; + + funcStr = funcStr[start + 1 .. end]; + + if (funcStr == "") + return null; + + funcStr ~= secondPattern; + + string token; + string[] arr; + + foreach (c ; funcStr) + { + if (c != firstPattern && c != secondPattern) + token ~= c; + + else + { + if (token) + arr ~= token; + + token = null; + } + } + + if (arr.length == 1) + return arr; + + string[] result; + bool skip = false; + + foreach (str ; arr) + { + skip = !skip; + + if (skip) + continue; + + result ~= str; + } + + return result; +} + +/** + * Compile-time function to get the index of the give element. + * + * Performs a linear scan, returning the index of the first occurrence + * of the specified element in the array, or U.max if the array does + * not contain the element. + * + * Params: + * arr = the array to get the index of the element from + * element = the element to find + * + * Returns: the index of the element or size_t.max if the element was not found. + */ +private size_t indexOf (T) (T[] arr, T element) +{ + foreach (i, e ; arr) + if (e == element) + return i; + + return size_t.max; +} + +//FIXME fix this when http://d.puremagic.com/issues/show_bug.cgi?id=3512 is fixed +version (none) +{ + +/** + * Compile-time function to get the index of the give element. + * + * Performs a linear scan, returning the index of the first occurrence + * of the specified element in the array, or U.max if the array does + * not contain the element. + * + * Params: + * arr = the array to get the index of the element from + * element = the element to find + * + * Returns: the index of the element or size_t.max if the element was not found. + */ +private size_t indexOf (T) (T[] arr, dchar element) +{ + static assert(is(T == char) || is(T == wchar) || is(T == dchar), `dstep.internal.Traits.indexOf: The given type "` ~ T.stringof ~ `" is not valid, it has to be char, wchar or dchar`); + + foreach (i, dchar e ; arr) + if (e == element) + return i; + + return size_t.max; +} +} + +/** + * Evaluates to true if $(D_PARAM T) has a instance method with the given name + * + * Params: + * T = the type of the class/struct + * method = the name of the method + */ +template hasInstanceMethod (T, string method) +{ + const hasInstanceMethod = is(typeof({ + T t; + mixin("auto f = &t." ~ method ~ ";"); + })); +} + +/** + * Evaluates to true if $(D_PARAM T) has a class method with the given name + * + * Params: + * T = the type of the class/struct + * method = the name of the method + */ +template hasClassMethod (T, string method) +{ + const hasClassMethod = is(typeof({ + mixin("auto f = &T." ~ method ~ ";"); + })); +} + +/** + * Evaluates to true if $(D_PARAM T) has a either a class method or a instance method + * with the given name. + * + * Params: + * T = the type of the class/struct + * method = the name of the method + */ +template hasMethod (T, string method) +{ + const hasMethod = hasClassMethod!(T, method) || hasInstanceMethod!(T, method); +} + +/** + * Evaluates to true if T has a field with the given name + * + * Params: + * T = the type of the class/struct + * field = the name of the field + */ +template hasField (T, string field) +{ + const hasField = hasFieldImpl!(T, field, 0); +} + +private template hasFieldImpl (T, string field, size_t i) +{ + static if (T.tupleof.length == i) + const hasFieldImpl = false; + + else static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field) + const hasFieldImpl = true; + + else + const hasFieldImpl = hasFieldImpl!(T, field, i + 1); +} + +/// Evaluates to true if $(D_PARAM T) has binded methods +template hasBindedMethods (T) +{ + const bool hasBindedMethods = hasField!(T, Bridge.objcClassMethodDeclarationVar) || hasField!(T, Bridge.objcMethodDeclarationVar); +} + + + +/** + * Sets the given value to the filed with the given name + * + * Params: + * t = an instance of the type that has the field + * value = the value to set + */ +void setValueOfField (string field, T, U) (ref T t, U value) +in +{ + static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\""); +} +body +{ + const len = T.stringof.length; + + foreach (i, dummy ; typeof(T.tupleof)) + { + const f = T.tupleof[i].stringof[1 + len + 2 .. $]; + + static if (f == field) + { + t.tupleof[i] = value; + break; + } + } +} + +/** + * Evaluates to the type of the field with the given name + * + * Params: + * T = the type of the class/struct + * field = the name of the field + */ +template TypeOfField (T, string field) +{ + static assert(hasField!(T, field), "The given field \"" ~ field ~ "\" doesn't exist in the type \"" ~ T.stringof ~ "\""); + + alias TypeOfFieldImpl!(T, field, 0) TypeOfField; +} + +private template TypeOfFieldImpl (T, string field, size_t i) +{ + static if (T.tupleof[i].stringof[1 + T.stringof.length + 2 .. $] == field) + alias typeof(T.tupleof[i]) TypeOfFieldImpl; + + else + alias TypeOfFieldImpl!(T, field, i + 1) TypeOfFieldImpl; +} + +/** + * Creates a new instance of class with the given name + * + * Params: + * name = the fully qualified name of the class + * args = the arguments to the constructor + * + * Returns: the newly created instance or null + */ +T factory (T : Object, ARGS...) (string name, ARGS args) +{ + auto classInfo = ClassInfo.find(name); + + if (!classInfo) + return null; + + auto object = newInstance(classInfo); + + if (classInfo.flags & 8 && classInfo.defaultConstructor is null) + { + auto o = cast(T) object; + + static if (is(typeof(o._ctor(args)))) + return o._ctor(args); + + else + return null; + } + + else + { + if (classInfo.flags & 8 && classInfo.defaultConstructor !is null) + { + Object delegate () ctor; + ctor.ptr = cast(void*) object; + ctor.funcptr = cast(Object function()) classInfo.defaultConstructor; + + return cast(T) ctor(); + } + + else + return cast(T) object; + } +} + +private +{ + version (LDC) + extern (C) Object _d_allocclass(ClassInfo); + + else + extern (C) Object _d_newclass(ClassInfo); +} + +/** + * Creates a new instance of the given ClassInfo + * + * Params: + * classInfo = the class to create a new instance of + * + * Returns: the new instance + */ +Object newInstance (ClassInfo classInfo) +{ + version (LDC) + { + Object object = _d_allocclass(classInfo); + (cast(byte*) object)[0 .. classInfo.init.length] = classInfo.init[]; + + return object; + } + + else + return _d_newclass(classInfo); +} \ No newline at end of file