April 04, 2019 Re: I give up! I tried to create a reflection library but D's traits are just too screwed up! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | I went ahead and decided to tidy up the code a bit and fix what could be fixed. For the most part everything is working pretty nice. By being careful of what was returned and dealing with any problems correctly I was able to get most of the code to be as I intend. So far, assuming everything is right, the only problem is that overloads are not returning parameter information correctly which I demonstrate at the bottom(Since the method code is now using the function code and the function code works it suggests a subtle issue). import std.stdio; import mExModel; import mModel; import mReflect; import mExTraits; struct attr(T) { T name; int value; } @attr!string("test", 432) @(4) void foo(int x, ref double y, float z = 43234.34) { } int main() { pragma(msg, printModelHierarchy(Reflect!(cDerived!int))); pragma(msg, printModelHierarchy(Reflect!(foo))); pragma(msg, printModelHierarchy(Reflect!(eEnum))); return 0; } module mModel; struct sStruct { int Y; int opIndex(int i) { return i; } } @(4) enum eEnum : long { X, Y = 43, @("sdfdsa") @(3) Z = 4 } @("fdsa", 4) interface iBase { iBase fooBase(iBase); } union uUnion { int X; long Y; } class cBase : iBase { string testField; cBase fooBase(iBase c) { return cast(cBase)c; } //cType barBase(cDerived c) { return c.type; } } interface iX { }; interface iY { }; @("fdsa",8) class cDerived(Q) : cBase, iX, iY { alias type this; cType type; @("XXXRRERES") int testField1; @("XXXRRERES4") private double testField2; @("A") int foo() { return 2; } private @("B") int foo(int x, int y) { return x; } @("VP att") @property int ValueProp() { return 3; } } class cType { } module mReflect; import mExTraits; import std.meta, std.conv, std.typecons, std.typetuple, std.string, std.algorithm, std.range, std.variant; /* A basic type */ struct sTypeReflection { string Name; string Type; this(string n, string t) { Name = n; Type = t; } } /* A Basic attribute */ struct sAttributeReflection { string Value; string Type; this(string v, string t) { Value = v; Type = t; } } /* Encapsulation of basic reflection */ abstract class cBaseReflection { // Declared in reverse order for proper output sAttributeReflection[] Attributes; // Attributes on the type cBaseReflection[] Uses; // Known types that use this type as a field, parameter, return type, etc string Body; // D does not allow getting a body but this is included if it ever does string Protection; string MangledName; string ModuleName; // The module name string FullName; // The fully qualified name string TypeName; // The type name string Id; // The id = __traits(identifier,T) string DType() { return "Unknown"; } auto Reflect(Ts...)() { alias T = Ts[0]; static if (__traits(compiles, __traits(identifier, T))) Id = __traits(identifier, T); static if (__traits(compiles, T.stringof)) TypeName = T.stringof; static if (__traits(compiles, moduleName!T)) ModuleName = moduleName!(T); static if (__traits(compiles, fullyQualifiedName!T)) FullName = fullyQualifiedName!(T); static if (__traits(compiles, mangledName!T)) MangledName = mangledName!T; static if (__traits(compiles, __traits(getProtection, T))) Protection = __traits(getProtection, T); // Get the attributes for the type static if (__traits(compiles, __traits(getAttributes, T))) static foreach(a; __traits(getAttributes, T)) Attributes ~= sAttributeReflection(to!string(a), typeof(a).stringof); return this; } } /* Encapsulates an Enumeration Reflection */ class cEnumReflection : cBaseReflection { static struct sValueReflection { string Name; string Value; sAttributeReflection[] Attributes; this(string n, string v) { Name = n; Value = v; } } sValueReflection[] Values; string BaseType; override string DType() { return "enum"; } auto Reflect(alias T)() { super.Reflect!T; BaseType = OriginalType!(T).stringof; static foreach(e; EnumMembers!T) {{ Values ~= sValueReflection(to!string(e), e.stringof); mixin("alias E = __traits(getAttributes, T."~to!string(e)~");"); static foreach(a; E) Values[$-1].Attributes ~= sAttributeReflection(to!string(a), typeof(a).stringof); }} return this; } } /* Encapsulates an Aggregate Type */ abstract class cAggregateReflection : cBaseReflection { cMethodReflection[] Methods; // The methods cFieldReflection[] Fields; // The fields cClassReflection[] DerivedClasses; // Known immedate derived class that derive this type cAggregateReflection[] NestedAggregates; // Any nested aggregates sTypeReflection[] AliasThis; // The Alias This sTypeReflection[] TypeParameters; // Any type parameters used. bool HasAliasing; bool HasElaborateAssign; bool HasElaborateCopyConstructor; bool HasElaborateDestructor; bool HasIndirections; bool HasNested; bool HasUnsharedAliasing; bool IsInnerClass; bool IsNested; override string DType() { return "Unknown"; } auto Reflect(alias T)() { super.Reflect!T; // Get the Alias This static foreach(a; __traits(getAliasThis, T)) {{ mixin("import "~moduleName!T~";"); mixin("AliasThis ~= sTypeReflection(to!string(a), typeof("~moduleName!T~"."~T.stringof~"."~to!string(a)~").stringof);"); }} HasAliasing = hasAliasing!T; HasElaborateAssign = hasElaborateAssign!T; HasElaborateCopyConstructor = hasElaborateCopyConstructor!T; HasElaborateDestructor = hasElaborateDestructor!T; HasIndirections = hasIndirections!T; HasNested = hasNested!T; HasUnsharedAliasing = hasUnsharedAliasing!T; static if (__traits(compiles, isInnerClass!T)) IsInnerClass = isInnerClass!T; static if (__traits(compiles, isNested!T)) IsNested = isNested!T; // Get the fields alias n = FieldNameTuple!T; static foreach(k, f; std.traits.Fields!T) {{ Fields ~= (new cFieldReflection()).Reflect!(Alias!T, n[k]); }} // Get the methods static foreach(k, m; __traits(derivedMembers, T)) {{ static if (__traits(compiles, __traits(getVirtualMethods, T, m))) static foreach(j, v; typeof(__traits(getVirtualMethods, T, m))) {{ //Methods ~= (new cMethodReflection()).Reflect!(T, m, v); // If we could pass the appropriate type, like we can a function, then everythign would work great. mixin(`import `~moduleName!T~`;`); static foreach (f; typeof(__traits(getOverloads, T, m))) { mixin(`Methods ~= (new cMethodReflection()).Reflect!(`~T.stringof~`.`~m~`, f);`); } }} }} return this; } } /* Encapsulates a Field Reflection */ class cFieldReflection : cBaseReflection { override string DType() { return "field"; } auto Reflect(alias T, string name)() { //pragma(msg, "Field: ", T, " -- ", name); static if (name != "") { // There is no field type so must manually construct and duplicate code, else we could reflect directly mixin(`import `~moduleName!T~`;`); // super.Reflect!T // -------- Cannod delegate work to base class, copy, paste, fix instead Id = name; static if (__traits(compiles, TypeName = T.stringof)) TypeName = T.stringof~"."~name; ModuleName = moduleName!(T); FullName = fullyQualifiedName!(T)~"."~name; MangledName = mangledName!T; // Get the attributes for the field mixin(`Protection = __traits(getProtection, (`~T.stringof~`).`~name~`);`); mixin(`static if (__traits(compiles, __traits(getProtection, `~T.stringof~`.`~name~`))) static foreach(a; __traits(getAttributes, `~T.stringof~`.`~name~`)) Attributes ~= sAttributeReflection(to!string(a), typeof(a).stringof);`); } return this; } } /* Encapsulates a Method Reflection */ class cMethodReflection : cFunctionReflection { cFunctionReflection[] Overloads; override string DType() { return "delegate"; } auto Reflect(Ts...)() { alias T = Ts[0]; alias V = Ts[1]; //pragma(msg, "Method: ", T, " -- ", V.stringof); super.Reflect!V; (cast(cBaseReflection)this).Reflect!T; // Fill in base information to get correct information return this; } } /* Encapsulates a Union Reflection */ class cUnionReflection : cAggregateReflection { override string DType() { return "union"; } auto Reflect(alias T)() { super.Reflect!T; return this; } } /* Encapsulates a Struct Reflection */ class cStructReflection : cAggregateReflection { override string DType() { return "struct"; } auto Reflect(alias T)() { super.Reflect!T; return this; } } /* Encapsulates a Interface Reflection */ class cInterfaceReflection : cAggregateReflection { cInterfaceReflection[] InheritedInterfaces; // The inherited interfaces override string DType() { return "interface"; } auto Reflect(alias T)() { super.Reflect!T; // Reflect on inherited interfaces static foreach(t; BaseTypeTuple!T) static if (isInterface!t) InheritedInterfaces ~= (new cInterfaceReflection()).Reflect!(t); return this; } } /* Encapsulates a Class Reflection */ class cClassReflection : cInterfaceReflection { cClassReflection[] InheritedClasses; // Any Inherited class(D only allows single class inheritance, but we allow for possibly more for uniformity) int Alignment; bool IsAbstract = false; override string DType() { return "class"; } auto Reflect(alias T)() { super.Reflect!T; IsAbstract = isAbstractClass!T; Alignment = classInstanceAlignment!T; // Reflect on inherited class static foreach(t; BaseTypeTuple!T) static if (isClass!t) InheritedClasses ~= (new cClassReflection()).Reflect!(t); return this; } } /* Encapsulates a Function Reflection */ class cFunctionReflection : cBaseReflection { static struct sParameterReflection { string Name; string Type; string DefaultValue = "none"; string DefaultValueType = "void"; struct sStorageClass { static foreach(a; EnumMembers!ParameterStorageClass) mixin(`bool Is`~strip(capitalize(to!string(a)),"_")~";"); } sStorageClass StorageClass; this(string n, string t, string dv, string dt) { Name = n; Type = t; DefaultValue = dv; DefaultValueType = dt; } } static struct sFunctionAttributes { static foreach(a; EnumMembers!FunctionAttribute) mixin(`bool Is`~strip(capitalize(to!string(a)),"_")~";"); } sFunctionAttributes FunctionAttributes; sParameterReflection[] Parameters; string ReturnType; string Linkage; Variadic VariadicFunctionStyle; int NumArgs; string Signature; override string DType() { return "function"; } auto Reflect(Ts...)() if (Ts.length == 1 && isCallable!Ts) { alias T = Ts[0]; super.Reflect!T; // Note that we can delegate to the function to a base class, but not the a method Signature = FunctionTypeOf!T.stringof; NumArgs = arity!T; Linkage = functionLinkage!T; VariadicFunctionStyle = variadicFunctionStyle!T; ReturnType = std.traits.ReturnType!T.stringof; static foreach(a; EnumMembers!FunctionAttribute) mixin(`FunctionAttributes.Is`~strip(capitalize(to!string(a)),"_")~" = (functionAttributes!T & FunctionAttribute."~to!string(a)~") != 0;"); static foreach(k, a; std.traits.Parameters!T) {{ static if (__traits(compiles, typeof(ParameterDefaults!T[k]).stringof)) enum dt = typeof(ParameterDefaults!T[k]).stringof; else enum dt = "void"; Parameters ~= sParameterReflection(ParameterIdentifierTuple!T[k], a.stringof, ParameterDefaults!T[k].stringof, dt); static foreach(j, a; EnumMembers!ParameterStorageClass) mixin(`Parameters[k].StorageClass.Is`~strip(capitalize(to!string(a)),"_")~" = (ParameterStorageClassTuple!T[k] & ParameterStorageClass."~to!string(a)~") != 0;"); }} } } /* Encapsulates a Delegate Reflection */ class cDelegateReflection : cFunctionReflection { override string DType() { return "delegate"; } auto Reflect(alias T)() { super.Reflect!T; return this; } } /* Takes a type and builds it's inheritance and uses hierarchy. */ auto Reflect(T...)() { static foreach(t; ["class", "interface", "struct", "union", "function", "delegate", "enum"]) mixin("static if (is"~capitalize(t)~"!(T)) { auto model = new c"~capitalize(t)~"Reflection(); model.Reflect!T(); } "); return model; } auto printModelHierarchy(T, int depth = 1)(T model) {static if (depth > 20) return "ERROR"; else { auto res = ""; auto tab = "\t".replicate(depth); if (model.TypeName == "Object") return "Object"; // Print out basic info, allMembers returns funky as it returns the most derived first from top to bottom. Generally we want to display the least derived from top to bottom. Reversing gets us bottom to top though so we must declare them in reverse order in the types. static foreach(k, m; [Reverse!(__traits(allMembers, T))]) {{ static if (!canFind(["factory", "Monitor", "opEquals", "opCmp", "toHash", "toString", "Reflect"], m)) // Ignore these { mixin(`alias Q = TypeOf!(T.`~m~`);`); static if (isPrimitive!Q || isString!Q) // Print primitives mixin(`res ~= tab~m~" = "~to!string(model.`~m.stringof[1..$-1]~`)~"\n";`); else static if (__traits(compiles, is(ReturnType!Q == string)) && is(ReturnType!Q == string)) // Print functions that return strings { mixin(`res ~= tab~m~" = "~model.`~m.stringof[1..$-1]~`()~"\n";`); } else // Print other types { static if (is(Q U : U[]) && !is(U == Object)) // Print Arrays, handling recursion {{ mixin("auto arr = model."~m~";"); if (arr.length > 0) { string[] r; foreach(a; arr) { static if (is(U : cBaseReflection)) r ~= printModelHierarchy!(U, depth + 1)(a).strip("\t\n ,"); else r ~= to!string(a).strip("\t\n ,"); } // Prepare results auto q = r.join(","); if (q.length > 60 || r.canFind("\n") || r.canFind(",")) static if (is(U : cBaseReflection)) q = "\n"~tab~"\t"~r.join("\n"~tab~"\t,\n"~tab~"\t")~"\n"~tab; else q = "\n"~tab~"\t"~r.join(",\n"~tab~"\t")~"\n"~tab; res ~= tab~m~" = ["~q~"]\n"; } else res ~= tab~m~" = []\n"; }} } } }} return res; }} mReflect.d-mixin-207(207): Deprecation: `mModel.cDerived!int.cDerived.testField2` is not visible from module `mReflect` mReflect.d-mixin-208(209): Deprecation: `mModel.cDerived!int.cDerived.testField2` is not visible from module `mReflect` Id = cDerived TypeName = cDerived!int FullName = mModel.cDerived!(int) ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("fdsa", "string"), sAttributeReflection("8", "int") ] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [sTypeReflection("type", "cType")] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = type TypeName = cDerived!int.type FullName = mModel.cDerived!(int).type ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = public Body = Uses = [] Attributes = [] DType = field , Id = testField1 TypeName = cDerived!int.testField1 FullName = mModel.cDerived!(int).testField1 ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = public Body = Uses = [] Attributes = [sAttributeReflection("XXXRRERES", "string")] DType = field , Id = testField2 TypeName = cDerived!int.testField2 FullName = mModel.cDerived!(int).testField2 ModuleName = mModel MangledName = C6mModel__T8cDerivedTiZQm Protection = private Body = Uses = [] Attributes = [sAttributeReflection("XXXRRERES4", "string")] DType = field ] Methods = [ Id = foo TypeName = int() FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = 6mModel__T8cDerivedTiZQm3foo Protection = public Body = Uses = [] Attributes = [sAttributeReflection("A", "string")] Signature = int() NumArgs = 0 Linkage = D ReturnType = int Parameters = [] DType = delegate Overloads = [] , Id = foo TypeName = pure nothrow @nogc @safe int(int, int) FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = 6mModel__T8cDerivedTiZQm3foo Protection = public Body = Uses = [] Attributes = [sAttributeReflection("A", "string")] Signature = pure nothrow @nogc @safe int(int, int) NumArgs = 2 Linkage = D ReturnType = int Parameters = [ sParameterReflection("", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("", "int", "void", "void", sStorageClass(false, false, false, false, false, false)) ] DType = delegate Overloads = [] , Id = ValueProp TypeName = @property int() FullName = mModel.cDerived!(int).ValueProp ModuleName = mModel MangledName = _D6mModel__T8cDerivedTiZQm9ValuePropMFNdZi Protection = public Body = Uses = [] Attributes = [sAttributeReflection("VP att", "string")] Signature = @property int() NumArgs = 0 Linkage = D ReturnType = int Parameters = [] DType = delegate Overloads = [] ] InheritedInterfaces = [ Id = iX TypeName = iX FullName = mModel.iX ModuleName = mModel MangledName = C6mModel2iX Protection = public Body = Uses = [] Attributes = [] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = TypeName = FullName = ModuleName = MangledName = Protection = Body = Uses = [] Attributes = [] DType = field ] Methods = [] DType = interface InheritedInterfaces = [] , Id = iY TypeName = iY FullName = mModel.iY ModuleName = mModel MangledName = C6mModel2iY Protection = public Body = Uses = [] Attributes = [] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = TypeName = FullName = ModuleName = MangledName = Protection = Body = Uses = [] Attributes = [] DType = field ] Methods = [] DType = interface InheritedInterfaces = [] ] DType = class IsAbstract = false Alignment = 8 InheritedClasses = [ Id = cBase TypeName = cBase FullName = mModel.cBase ModuleName = mModel MangledName = C6mModel5cBase Protection = public Body = Uses = [] Attributes = [] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = testField TypeName = cBase.testField FullName = mModel.cBase.testField ModuleName = mModel MangledName = C6mModel5cBase Protection = public Body = Uses = [] Attributes = [] DType = field ] Methods = [ Id = fooBase TypeName = cBase(iBase) FullName = mModel.cBase.fooBase ModuleName = mModel MangledName = _D6mModel5cBase7fooBaseMFCQy5iBaseZCQBiQBe Protection = public Body = Uses = [] Attributes = [] Signature = cBase(iBase) NumArgs = 1 Linkage = D ReturnType = cBase Parameters = [ sParameterReflection("", "iBase", "void", "void", sStorageClass(false, false, false, false, false, false)) ] DType = delegate Overloads = [] ] InheritedInterfaces = [ Id = iBase TypeName = iBase FullName = mModel.iBase ModuleName = mModel MangledName = C6mModel5iBase Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("fdsa", "string"), sAttributeReflection("4", "int") ] IsNested = false IsInnerClass = false HasUnsharedAliasing = true HasNested = false HasIndirections = true HasElaborateDestructor = false HasElaborateCopyConstructor = false HasElaborateAssign = false HasAliasing = true TypeParameters = [] AliasThis = [] NestedAggregates = [] DerivedClasses = [] Fields = [ Id = TypeName = FullName = ModuleName = MangledName = Protection = Body = Uses = [] Attributes = [] DType = field ] Methods = [ Id = fooBase TypeName = iBase(iBase) FullName = mModel.iBase.fooBase ModuleName = mModel MangledName = _D6mModel5iBase7fooBaseMFCQyQtZQg Protection = public Body = Uses = [] Attributes = [] Signature = iBase(iBase) NumArgs = 1 Linkage = D ReturnType = iBase Parameters = [ sParameterReflection("", "iBase", "void", "void", sStorageClass(false, false, false, false, false, false)) ] DType = delegate Overloads = [] ] DType = interface InheritedInterfaces = [] ] DType = class IsAbstract = false Alignment = 4 InheritedClasses = [Object] ] Id = foo TypeName = FullName = main.foo ModuleName = main MangledName = _D4main3fooFiKdfZv Protection = public Body = Uses = [] Attributes = [ sAttributeReflection("attr!string(\"test\", 432)", "attr!string"), sAttributeReflection("4", "int") ] DType = function Signature = void(int x, ref double y, float z = 43234.3F) NumArgs = 3 Linkage = D ReturnType = void Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "double", "void", "void", sStorageClass(false, false, false, true, false, false)), sParameterReflection("z", "float", "43234.3F", "float", sStorageClass(false, false, false, false, false, false)) ] Id = eEnum TypeName = eEnum FullName = mModel.eEnum ModuleName = mModel MangledName = E6mModel5eEnum Protection = public Body = Uses = [] Attributes = [sAttributeReflection("4", "int")] DType = enum BaseType = long Values = [ sValueReflection("X", "cast(eEnum)0L", []), sValueReflection("Y", "cast(eEnum)43L", []), sValueReflection("Z", "cast(eEnum)4L", [sAttributeReflection("sdfdsa", "string"), sAttributeReflection("3", "int")]) ] If one looks at the overloads issue, we have: Methods = [ Id = foo TypeName = int() FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = 6mModel__T8cDerivedTiZQm3foo Protection = public Attributes = [sAttributeReflection("A", "string")] Signature = int() NumArgs = 0 Linkage = D ReturnType = int Parameters = [] DType = delegate Overloads = [] , Id = foo TypeName = pure nothrow @nogc @safe int(int, int) FullName = mModel.cDerived!(int).foo ModuleName = mModel MangledName = 6mModel__T8cDerivedTiZQm3foo Protection = public Attributes = [sAttributeReflection("A", "string")] Signature = pure nothrow @nogc @safe int(int, int) NumArgs = 2 Linkage = D ReturnType = int Parameters = [ sParameterReflection("", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("", "int", "void", "void", sStorageClass(false, false, false, false, false, false)) ] DType = delegate Overloads = [] , and Id = foo TypeName = FullName = main.foo ModuleName = main MangledName = _D4main3fooFiKdfZv Protection = public Attributes = [ sAttributeReflection("attr!string(\"test\", 432)", "attr!string"), sAttributeReflection("4", "int") ] DType = function Signature = void(int x, ref double y, float z = 43234.3F) NumArgs = 3 Linkage = D ReturnType = void Parameters = [ sParameterReflection("x", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), sParameterReflection("y", "double", "void", "void", sStorageClass(false, false, false, true, false, false)), sParameterReflection("z", "float", "43234.3F", "float", sStorageClass(false, false, false, false, false, false)) ] I'm having to do a trick to make things work here by using the method to fill in some information and the overload to fill in the rest... But regardless the overloads are not returning Parameter names while the function does(yet it is the exact same code. This might be a bug in the compiler. sParameterReflection("", "int", "void", "void", sStorageClass(false, false, false, false, false, false)), The first element should be x but is empty. For the local function it gives "x" which is valid. Same code but fails for methods. Another issue is that the protection is wrong for the overload... mainly because getting the protection of an overload fails. I will mess with it some more later, it is at least not as bad as I thought but requires a bit of work to get everything to fall in place. Would be nice to know though what is going on with the overloads and why the protection is failing to return the correct value. There might be other subtle issues but something is amiss. I have tried to generalize the code as much as possible and it is much closer than it as before. Many of the same problems still exist(protection warnings, field typing, etc). |
April 04, 2019 Re: I give up! I tried to create a reflection library but D's traits are just too screwed up! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | I've created a project page so it will be easier than pasting: https://github.com/IncipientDesigns/Dlang_Reflect |
April 05, 2019 Re: I give up! I tried to create a reflection library but D's traits are just too screwed up! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Alex | On Thursday, 4 April 2019 at 02:19:48 UTC, Alex wrote: > But because there is no `T` for fields we can't do it so easy, so we have to construct the name and use string mixins. You should pass fields as an alias more often than not. It is a little tricky when you want to read/write it (the alias is not a value, so you need to pass a pointer or something separately), but for reflection you want to use the alias. UDAs do not exist on types per se, since they are tied to symbols. > mixin(`static foreach(a; __traits(getAttributes, `~T.stringof~`.`~name~`)) This shouldn't use mixin at all, and even if you do use mixin, it shouldn't be using stringof; .stringof is a code smell and should almost never be used. This bypasses the local symbol. That is actually the reason why you get a visibility error. Just use T. more info: https://stackoverflow.com/questions/32615733/struct-composition-with-mixin-and-templates/32621854#32621854 |
April 06, 2019 Re: I give up! I tried to create a reflection library but D's traits are just too screwed up! | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Friday, 5 April 2019 at 16:00:26 UTC, Adam D. Ruppe wrote: > On Thursday, 4 April 2019 at 02:19:48 UTC, Alex wrote: >> But because there is no `T` for fields we can't do it so easy, so we have to construct the name and use string mixins. > > You should pass fields as an alias more often than not. It is a little tricky when you want to read/write it (the alias is not a value, so you need to pass a pointer or something separately), but for reflection you want to use the alias. > > UDAs do not exist on types per se, since they are tied to symbols. > >> mixin(`static foreach(a; __traits(getAttributes, `~T.stringof~`.`~name~`)) > > This shouldn't use mixin at all, and even if you do use mixin, it shouldn't be using stringof; .stringof is a code smell and should almost never be used. This bypasses the local symbol. That is actually the reason why you get a visibility error. > > Just use T. more info: https://stackoverflow.com/questions/32615733/struct-composition-with-mixin-and-templates/32621854#32621854 Ok, I was able to remove all of them I believe. I got in the habit because I routinely switch the mixin to a pragma(msg and having the actual name their is far more informative than T, helps find out if the type if wrong). I don't know why it is code smell, since it should ultimately end up the same. Fixing this did not solve the `private` error. // Get the attributes for the field mixin(`Protection = __traits(getProtection, T.`~name~`);`); In any case, the code seems to be fundamentally working now, as I mentioned in a previous thread. I just have to finish dealing with all the other types, which shouldn't be a huge problem. ----------- As far as using an alias as fields, The code is this: // Get the fields alias n = FieldNameTuple!T; static foreach(k, f; std.traits.Fields!T) {{ Fields ~= (new cFieldReflection()).Reflect!(Alias!T, n[k]); }} I am passing the base type and the name then building it inside Reflect, I've tried passing various things so I could simplify the code, but I am unable to get anything to work. auto Reflect(alias T, string name)() { static if (name != "") { // There is no field type so must manually construct and duplicate code, else we could reflect directly mixin(`import `~moduleName!T~`;`); // mixin(`super.Reflect!(T.`~name~`);`); Id = name; static if (__traits(compiles, TypeName = T.stringof)) TypeName = T.stringof~"."~name; ModuleName = moduleName!(T); FullName = fullyQualifiedName!(T)~"."~name; MangledName = mangledName!T; // Get the attributes for the field mixin(`Protection = __traits(getProtection, T.`~name~`);`); mixin(`static if (__traits(compiles, __traits(getProtection, T.`~name~`))) static foreach(a; __traits(getAttributes, T.`~name~`)) Attributes ~= sAttributeReflection(to!string(a), typeof(a).stringof);`); } return this; } If I could call super.Reflect then it would fill in all the info and I could remove the Id = name ... MangledName lines and consolidate code. But I have not figure out how to get any of that code to work without constructing the symbols by hand. |
Copyright © 1999-2021 by the D Language Foundation