1 
2 module witchcraft.types;
3 
4 import witchcraft;
5 
6 import std.algorithm;
7 import std.array;
8 import std.range;
9 
10 abstract class Type : Member
11 {
12 protected:
13     Field[string] _fields;
14     Method[][string] _methods;
15 
16 public:
17     /++
18      + Looks up a field by name.
19      +
20      + Params:
21      +   name = The name of the field.
22      +
23      + Returns:
24      +   The field object, or null if no such field exists.
25      ++/
26     const(Field) getField(string name) const
27     {
28         auto ptr = name in _fields;
29         return ptr ? *ptr : null;
30     }
31 
32     final string[] getFieldNames() const
33     {
34         return getFields
35             .map!"a.getName"
36             .array;
37     }
38 
39     /++
40      + Returns an array of all fields defined by this type.
41      +
42      + Returns:
43      +   All fields objects on this type.
44      ++/
45     const(Field)[] getFields() const
46     {
47         return _fields.values;
48     }
49 
50     final const(Method) getMethod(string name, Type[] parameterTypes...) const
51     {
52         // Iterate up the inheritance tree.
53         return this.getMethods(name).retro
54             .filter!(m => m.getParameterTypes == parameterTypes)
55             .takeOne
56             .chain(null.only)
57             .front;
58     }
59 
60     final const(Method) getMethod(string name, TypeInfo[] parameterTypeInfos) const
61     {
62         // Iterate up the inheritance tree.
63         return this.getMethods(name).retro
64             .filter!(m => m.getParameterTypeInfos == parameterTypeInfos)
65             .takeOne
66             .chain(null.only)
67             .front;
68     }
69 
70     final const(Method) getMethod(TList...)(string name) const
71     {
72         auto parameterTypeInfos = new TypeInfo[TList.length];
73 
74         foreach(index, Type; TList)
75         {
76             parameterTypeInfos[index] = typeid(Type);
77         }
78 
79         return this.getMethod(name, parameterTypeInfos);
80     }
81 
82     const(Method)[] getMethods() const
83     {
84         const(Method)[] methods;
85 
86         // Flatten the overloads array.
87         foreach(overloads; _methods.values)
88         {
89             methods ~= overloads;
90         }
91 
92         return methods;
93     }
94 
95     final string[] getMethodNames() const
96     {
97         return getMethods
98             .map!"a.getName"
99             .array;
100     }
101 
102     const(Method)[] getMethods(string name) const
103     {
104         auto ptr = name in _methods;
105         return ptr ? *ptr : [ ];
106     }
107 
108     abstract const(TypeInfo) getTypeInfo() const;
109 
110     @property
111     bool isAggregate() const
112     {
113         return false;
114     }
115 
116     @property
117     bool isArray() const
118     {
119         return false;
120     }
121 
122     @property
123     bool isAssocArray() const
124     {
125         return false;
126     }
127 
128     @property
129     bool isBuiltIn() const
130     {
131         return false;
132     }
133 
134     @property
135     bool isClass() const
136     {
137         return false;
138     }
139 
140     @property
141     bool isInterface() const
142     {
143         return false;
144     }
145 
146     @property
147     bool isModule() const
148     {
149         return false;
150     }
151 
152     @property
153     bool isPointer() const
154     {
155         return false;
156     }
157 
158     @property
159     bool isPrimitive() const
160     {
161         return false;
162     }
163 
164     @property
165     bool isStaticArray() const
166     {
167         return false;
168     }
169 
170     @property
171     bool isString() const
172     {
173         return false;
174     }
175 
176     @property
177     bool isStruct() const
178     {
179         return false;
180     }
181 
182     override string toString() const
183     {
184         return getFullName;
185     }
186 }