www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Loop through all modules and module members?

reply %u <wfunction hotmail.com> writes:
Hi,

I would like to perform compile-time reflection on a module (such as
enumerating all the classes inside the module) and/or on all modules in the
code -- are either of these possible? And if so, how?

Thank you!
Dec 31 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
%u:

 I would like to perform compile-time reflection on a module (such as
 enumerating all the classes inside the module) and/or on all modules in the
 code -- are either of these possible? And if so, how?
You may add your enhancement requests here, explaining why you need them: http://d.puremagic.com/issues/show_bug.cgi?id=4476 At the moment the static reflection is not able to do everything. Listing all modules in the code looks like work for rmdm. Listing all classes in a module seems work for __traits/meta, plus a compile-time Filter. Bye, bearophile
Jan 01 2011
next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Jan 1, 2011 at 11:14, bearophile <bearophileHUGS lycos.com> wrote:
 %u:

 I would like to perform compile-time reflection on a module (such as
 enumerating all the classes inside the module) and/or on all modules in the
 code -- are either of these possible? And if so, how?
You may add your enhancement requests here, explaining why you need them: http://d.puremagic.com/issues/show_bug.cgi?id=4476 At the moment the static reflection is not able to do everything. Listing all modules in the code looks like work for rmdm. Listing all classes in a module seems work for __traits/meta, plus a compile-time Filter.
Yes, it's doable : template StaticFilter(alias Pred, T...) { static if (T.length == 0) alias TypeTuple!() StaticFilter; else static if (Pred!(T[0])) alias TypeTuple!(T[0], StaticFilter!(Pred, T[1 .. $])) StaticFilter; else alias StaticFilter!(Pred, T[1 .. $]) StaticFilter; } template isClass(string name) { mixin(" static if (is(" ~ name ~ " == class)) enum bool isClass = true; else enum bool isClass = false;"); } template extractClasses(string moduleName, members...) { alias StaticFilter!(isClass,members) extractClasses; } template classMembers(string moduleName) { mixin("alias extractClasses!(moduleName, __traits(allMembers, " ~ moduleName ~ ")) classMembers;"); } if in module dir.mod1.d you have class A {} class B : A {} struct S {} class C {} int foo() { return 0;} then classMembers!("dir.mod1") will become the tuple ("A", "B", "C") during compilation. It's buggy, though: the module needs to be in a directory. You cannot do classMembers!("mod1"). Too bad. Note that class templates are *not* classes. So most of std.* modules will return an empty tuple, because they're full of templates. Another detail I didn't have the time to correct: the names should be tested fully qualified, to avoid any name clash with locally-defined classes. As for listing all modules imported by a module, I have something, but it's not very elegant: it scans the text, looking for import declarations. It works, but at runtime. I'm not sure it's doable at compile-time right now: you need to have access to the module code, as text. Do imports work in CT-evaluable functions? Philippe
Jan 01 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/1/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 I'm not sure it's doable at
 compile-time right now: you need to have access to the module code, as
 text. Do imports work in CT-evaluable functions?

 Philippe
You're gonna love this: module mymodule; void main() { pragma(msg, import(.stringof[7..$] ~ ".d")); } Of course, you need to -J switch with the path of your module.
Jan 01 2011
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
*the* J switch.

On 1/1/11, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 1/1/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 I'm not sure it's doable at
 compile-time right now: you need to have access to the module code, as
 text. Do imports work in CT-evaluable functions?

 Philippe
You're gonna love this: module mymodule; void main() { pragma(msg, import(.stringof[7..$] ~ ".d")); } Of course, you need to -J switch with the path of your module.
Jan 01 2011
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Jan 1, 2011 at 18:56, Andrej Mitrovic
<andrej.mitrovich gmail.com> wrote:
 On 1/1/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 I'm not sure it's doable at
 compile-time right now: you need to have access to the module code, as
 text. Do imports work in CT-evaluable functions?

 Philippe
You're gonna love this: module mymodule; void main() { =C2=A0 =C2=A0pragma(msg, import(.stringof[7..$] ~ ".d")); }
I saw your .stringof trick a few days ago and it made my day :-) But I didn't know you could text-import at compile-time (with access for the programmer, I mean. Obviously the compiler can import at CT). Cool! OK, then it's doable to get a compile-time list of imported modules from a module name. Too bad modules are not first class in D: would they have type, we could return a list of them [std.algorithm, std.concurrency, ...]
 Of course, you need to -J switch with the path of your module.
I'm not much versed in DMD switches. I'll try and see. Philippe
Jan 02 2011
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/2/11, Philippe Sigaud <philippe.sigaud gmail.com> wrote:
 Of course, you need to -J switch with the path of your module.
I'm not much versed in DMD switches. I'll try and see. Philippe
Well it's a simple switch, really. If the module is in "C:\dev\project\", use: dmd -JC:\dev\project\ On *nix it's the same, I believe. http://www.digitalmars.com/d/2.0/dmd-windows.html#switches http://www.digitalmars.com/d/2.0/dmd-linux.html#switches
Jan 02 2011