1 
2 module witchcraft.classes;
3 
4 import witchcraft;
5 
6 import std.algorithm;
7 import std.array;
8 import std.range;
9 import std.traits;
10 
11 
12 interface ClassAccessor {
13     Class getMetaType();
14 }
15 
16 
17 /++
18  + Represents and grants access to a class's attributes, fields, methods,
19  + and constructors.
20  ++/
21 abstract class Class : Aggregate
22 {
23     /++
24      + Creates a new instance of the class, provided it has a default or
25      + zero-argument constructor.
26      +
27      + Returns:
28      +   A new instance of the class.
29      ++/
30     @property
31     abstract Object create() const;
32 
33     /++
34      + Ditto, but also casts the result to a type given by template parameter.
35      +
36      + Params:
37      +   T = An Object type to which the result is cast.
38      +
39      + Returns:
40      +   A new instance of the class.
41      ++/
42     @property
43     T create(T : Object)() const
44     {
45         return cast(T) this.create;
46     }
47 
48     /++
49      + Returns an array of all constructors defined by this class.
50      + This does not include any constructors inherited from a base class,
51      + nor the default constructor.
52      +
53      + If a class declares no constructors, this method will return an empty
54      + array. To construct an Object of such a type, the `create()` method
55      + defined by `Class` should be used.
56      +
57      + Returns:
58      +   And array of all constructors on the class.
59      +
60      + See_Also:
61      +   create
62      ++/
63     abstract override const(Constructor)[] getConstructors() const;
64 
65     /++
66      + Looks up a field by name, searching this class, and each of its super
67      + classes in turn.
68      +
69      + Params:
70      +   name = The name of the field.
71      +
72      + Returns:
73      +   The field object, or null if no such field exists.
74      ++/
75     override const(Field) getField(string name) const
76     {
77         auto field = getLocalField(name);
78 
79         if(field !is null)
80         {
81             return field;
82         }
83         else if(getSuperClass !is null)
84         {
85             return getSuperClass.getField(name);
86         }
87         else
88         {
89             return null;
90         }
91     }
92 
93     /++
94      + Returns an array of all fields defined by this class and classes that
95      + it inherits from. This only extends to super classes that also use
96      + `Witchcraft`.
97      +
98      + Returns:
99      +   An array of all known field objects belonging to this class.
100      ++/
101     override const(Field)[] getFields() const
102     {
103         if(getSuperClass !is null)
104         {
105             return getSuperClass.getFields ~ getLocalFields;
106         }
107         else
108         {
109             return getLocalFields;
110         }
111     }
112 
113     /++
114      + Returns an array of all interfaces that are declared directly on this
115      + class. Interfaces that appear multiple times on the class are only
116      + present once in the array.
117      +
118      + Returns:
119      +   An array of interfaces on this class.
120      ++/
121     abstract const(InterfaceType)[] getInterfaces() const;
122 
123     const(Field) getLocalField(string name) const
124     {
125         return super.getField(name);
126     }
127 
128     string[] getLocalFieldNames() const
129     {
130         return getLocalFields
131             .map!"a.getName"
132             .array;
133     }
134 
135     const(Field)[] getLocalFields() const
136     {
137         return super.getFields;
138     }
139 
140     const(Method) getLocalMethod(string name, TypeInfo[] parameterTypes...) const
141     {
142         return getLocalMethods(name)
143             .filter!(m => m.getParameterTypes == parameterTypes)
144             .takeOne
145             .chain(null.only)
146             .front;
147     }
148 
149     const(Method) getLocalMethod(TList...)(string name) const
150     {
151         auto types = new TypeInfo[TList.length];
152 
153         foreach(index, type; TList)
154         {
155             types[index] = typeid(type);
156         }
157 
158         return this.getLocalMethod(name, types);
159     }
160 
161     string[] getLocalMethodNames() const
162     {
163         return getLocalMethods
164             .map!"a.getName"
165             .array;
166     }
167 
168     const(Method)[] getLocalMethods() const
169     {
170         return super.getMethods;
171     }
172 
173     const(Method)[] getLocalMethods(string name) const
174     {
175         return super.getMethods(name);
176     }
177 
178     /++
179      + Returns all methods declared on this class, and non-private methods in
180      + classes that it inherits from. This is restricted to classes for which
181      + reflective information is present.
182      +
183      + Methods that are declared by a base class and are overriden by another
184      + class appear in the array for every class that delcares them.
185      +
186      + Returns:
187      +   All methods that are available to this class.
188      +
189      + See_Also:
190      +   getDeclaringType
191      ++/
192     override const(Method)[] getMethods() const
193     {
194         const(Class) superClassMeta = getSuperClass();
195         if(superClassMeta !is null)
196         {
197             return superClassMeta.getMethods
198                 .filter!`a.getProtection != "private"`
199                 .chain(getLocalMethods)
200                 .array;
201         }
202         else
203         {
204             return getLocalMethods;
205         }
206     }
207 
208     /++
209      + Ditto, but returns only methods that match the given name.
210      +
211      + Params:
212      +   name = The name of the method to look for.
213      +
214      + Returns:
215      +   All methods that match the given name.
216      ++/
217     override const(Method)[] getMethods(string name) const
218     {
219         const(Class) superClassMeta = getSuperClass();
220         if(superClassMeta !is null)
221         {
222             return superClassMeta.getMethods(name)
223                 .filter!`a.getProtection != "private"`
224                 .chain(getLocalMethods(name))
225                 .array;
226         }
227         else
228         {
229             return getLocalMethods(name);
230         }
231     }
232 
233     /++
234      + Returns the parent of this class. If the class doesn't declare a super
235      + class, the super class is `Object`, unless the class itself is `Object`.
236      + For `Object`, this method always returns `null`.
237      +
238      + Returns:
239      +   This class's super class.
240      ++/
241     abstract const(Class) getSuperClass() const;
242 
243     /++
244      + Ditto, but a `TypeInfo` object is returned instead.
245      +
246      + Returns:
247      +   This class's super class.
248      ++/
249     abstract const(TypeInfo) getSuperTypeInfo() const;
250 
251     /++
252      + Checks if this class is abstract.
253      +
254      + Returns:
255      +   `true` if the class is abstract.
256      ++/
257     @property
258     abstract bool isAbstract() const;
259 
260     /++
261      + Checks if this type is a class. For children of `Class`, this always
262      + returns `true`.
263      +
264      + Returns:
265      +   `true` if the type is a class.
266      ++/
267     @property
268     final override bool isClass() const
269     {
270         return true;
271     }
272 
273     /++
274      + Checks if this class is final.
275      +
276      + Returns:
277      +   `true` if the type is final.
278      ++/
279     @property
280     abstract bool isFinal() const;
281 
282     abstract bool isSubClassOf(const Class other) const;
283 
284     abstract bool isSuperClassOf(const Class other) const;
285 }