comparison src/docgen/config/reflection.d @ 806:bcb74c9b895c

Moved out files in the trunk folder to the root.
author Aziz K?ksal <aziz.koeksal@gmail.com>
date Sun, 09 Mar 2008 00:12:19 +0100
parents trunk/src/docgen/config/reflection.d@cb8edb09108a
children
comparison
equal deleted inserted replaced
805:a3fab8b74a7d 806:bcb74c9b895c
1 /**
2 * Author: Jari-Matti Mäkelä
3 * License: GPL3
4 */
5 module docgen.config.reflection;
6
7 import docgen.misc.meta;
8 import docgen.misc.options;
9
10 ////
11 //
12 // Macros for reading input
13 //
14 ////
15
16 char[] _wrong(char[] key) {
17 return `if (val.length != 1) throw new Exception(
18 "Wrong number of arguments for `~key~`");`;
19 }
20
21 char[] _switch(char[] stuff) {
22 return "switch(key) {" ~ stuff ~ "}";
23 }
24
25 char[] _parseI(char[] key) {
26 return `case "` ~ key ~ `":` ~ _wrong(key) ~ key ~
27 `= Integer.parse(val[0]); continue;`;
28 }
29
30 char[] _parseS(char[] key) {
31 return `case "` ~ key ~ `":` ~ _wrong(key) ~ key ~
32 `= val[0]; continue;`;
33 }
34
35 char[] _parseB(char[] key) {
36 return `case "` ~ key ~ `":` ~ _wrong(key) ~ key ~
37 `= val[0] == "true" ? true : val[0] == "false" ? false : err(); continue;`;
38 }
39
40 char[] _parseList(char[] key) {
41 return `case "` ~ key ~ `":foreach(v; val) ` ~
42 key ~ `~= v; continue;`;
43 }
44
45 template _parseEnum_(bool list, char[] key, V...) {
46 static if (V.length>1)
47 const char[] _parseEnum_ =
48 `case "` ~ V[0] ~ `":` ~ key ~ (list ? "~" : "") ~ `=` ~ V[1] ~ `; continue;` \n ~
49 _parseEnum_!(list, key, V[2..$]);
50 else
51 const char[] _parseEnum_ = "";
52 }
53
54 template _parseEnum(char[] key, V...) {
55 const char[] _parseEnum = `case "` ~ key ~
56 `":` ~ _wrong(key) ~ `switch(val[0]) {` ~
57 _parseEnum_!(false, key, V) ~
58 `default: err(); } continue;`;
59 }
60
61 template _parseEnumList(char[] key, V...) {
62 const char[] _parseEnumList = `case "` ~ key ~
63 `":` ~ `foreach (item; val) switch(item) {` ~
64 _parseEnum_!(true, key, V) ~
65 `default: err(); } continue;`;
66 }
67
68 ////
69 //
70 // Reflection for properties. This code will hopefully get better when the dmdfe bugs get fixed.
71 //
72 ////
73
74 // dmdfe bug -- Seriously WTF?
75 char[] fixType(char[] type) {
76 return type[$-1] == ' ' ? type[0..$-1] : type;
77 }
78
79 // take the last part of field name
80 char[] getLastName(char[] field) {
81 if (field.length == 0) return "";
82 int t = 0;
83 // dmdfe bug: a while loop causes index out of bounds error
84 for (int i=field.length-1; i >= 0; i--)
85 if (field[i] == '.') { t = i+1; break; }
86 return field[t..$];
87 }
88
89 // dmdfe bug: cannot return evalType alias
90 template _evalType(char[] type) {
91 mixin("alias "~type~" value;");
92 }
93
94 // Note: stuple wrappers needed for tuples, otherwise:
95 // dmdfe bug: cc1d: ../.././gcc/d/dmd/expression.c:4865: virtual Expression* DotIdExp::semantic(Scope*): Assertion `0' failed.
96 template evalType(char[] type) {
97 alias _evalType!(type).value evalType;
98 }
99
100 // wraps the reflected struct and enum data inside struct because otherwise the handling becomes impossibly hard
101 template getType(T) {
102 static if(is(T == struct))
103 alias Struct!(T) getType;
104 else static if(is(T == enum))
105 alias Enum!(T) getType;
106 else static if(isEnumList!(T))
107 alias Enum!(enumListType!(T), true) getType;
108 else
109 alias T getType;
110 }
111
112 template getTypes(alias S, int idx = S.tupleof.length) {
113 static if(idx)
114 alias Tuple!(getTypes!(S, idx-1), getType!(typeof(S.tupleof[idx-1]))) getTypes;
115 else
116 alias Tuple!() getTypes;
117 }
118
119 /**
120 * Extracts the comma separated struct field names using .tupleof.stringof.
121 * This is needed since the struct.tupleof[n].stringof is broken for enums and tuples in dmdfe.
122 *
123 * Bugs: handling of tuples
124 */
125 char[] __getNames(char[] type) {
126 char[] tmp;
127 bool end = false;
128
129 foreach(c; type[5..$]) {
130 if (c != ' ' && c != '(' && c != ')' && end) tmp ~= c;
131 if (c == ',') end = false;
132 if (c == '.') end = true;
133 }
134
135 return tmp;
136 }
137
138 template _getNames(char[] str, T...) {
139 static if (str.length) {
140 static if (str[0] == ',')
141 alias _getNames!(str[1..$], T, "") _getNames;
142 else
143 alias _getNames!(str[1..$], T[0..$-1], T[$-1] ~ str[0]) _getNames;
144 } else
145 alias T _getNames;
146 }
147
148 template getNames(char[] str) {
149 alias _getNames!(__getNames(str), "") getNames;
150 }
151
152 struct Struct(alias T) {
153 const type = "struct"; // used for pattern matching... apparently there's no other way
154 const name = fixType(T.stringof); // dmdfe bug: trailing space
155 alias STuple!(getNames!(T.tupleof.stringof)) names;
156 alias STuple!(getTypes!(T)) types;
157 }
158
159 struct Enum(alias T, bool list = false) {
160 const type = list ? "enumlist" : "enum"; // used for pattern matching... apparently there's no other way
161 const name = T.stringof[1..$]; // dmdfe bug: returns enum base type instead enum type
162 alias evalType!("___"~name).tuple elements;
163 }
164
165 // determines the enumtype[] type
166 template isEnumList(T : T[]) {
167 const isEnumList = T.stringof[0] == '_';
168 }
169
170 template isEnumList(T) {
171 const isEnumList = false;
172 }
173
174 template enumListType(T : T[]) {
175 alias T enumListType;
176 }
177
178 template enumListType(T) {
179 static assert(false, "Not enum list type!");
180 }
181
182 char[] createIParser(char[] field) {
183 return `_parseI("` ~ field ~ `") ~` \n;
184 }
185
186 char[] createBParser(char[] field) {
187 return `_parseB("` ~ field ~ `") ~` \n;
188 }
189
190 char[] createSParser(char[] field) {
191 return `_parseS("` ~ field ~ `") ~` \n;
192 }
193
194 char[] createLParser(char[] field) {
195 return `_parseList("` ~ field ~ `") ~` \n;
196 }
197
198 char[] createEParser(char[] field, char[] contents) {
199 return `_parseEnum!("` ~ field ~ `",` ~ contents ~ `) ~` \n;
200 }
201
202 char[] createELParser(char[] field, char[] contents) {
203 return `_parseEnumList!("` ~ field ~ `",` ~ contents ~ `) ~` \n;
204 }
205
206 template _makeEnumString(char[] t, E...) {
207 static if (E.length)
208 const _makeEnumString = `"` ~ E[0] ~ `", "` ~ t ~ "." ~ E[0] ~ `",` ~
209 _makeEnumString!(t, E[1..$]);
210 else
211 const _makeEnumString = "";
212 }
213
214 // avoids the following dmdfe bugs:
215 // - Error: elements is not a type (typeof(T).elements)
216 // - Error: tuple is not a valid template value argument (T.elements where T is the complex type def)
217 template makeEnumString(char[] t, T) {
218 const makeEnumString = _makeEnumString!(t, T.elements);
219 }
220
221 /**
222 * Generates code for parsing data from the configuration data structure.
223 */
224 template makeTypeString(int i, N, T, char[] prefix) {
225 static assert(N.tuple.length == T.tuple.length);
226 static if (i < N.tuple.length) {
227 static if (is(T.tuple[i] == bool))
228 const makeTypeString = createBParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix);
229 else static if (is(T.tuple[i] : int))
230 const makeTypeString = createIParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix);
231 else static if (is(T.tuple[i] == char[]))
232 const makeTypeString = createSParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix);
233 else static if (is(T.tuple[i] == char[][]))
234 const makeTypeString = createLParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix);
235 else static if (is(T.tuple[i] == struct)) {
236 static if (T.tuple[i].type == "struct")
237 const makeTypeString = makeTypeString!(0, typeof(T.tuple[i].names),
238 typeof(T.tuple[i].types), prefix~N.tuple[i]~".") ~
239 makeTypeString!(i+1, N, T, prefix);
240 else static if (T.tuple[i].type == "enum")
241 const makeTypeString = createEParser(prefix ~ N.tuple[i],
242 makeEnumString!(T.tuple[i].name, T.tuple[i])[0..$-1]) ~
243 makeTypeString!(i+1, N, T, prefix);
244 else static if (T.tuple[i].type == "enumlist")
245 const makeTypeString = createELParser(prefix ~ N.tuple[i],
246 makeEnumString!(T.tuple[i].name, T.tuple[i])[0..$-1]) ~
247 makeTypeString!(i+1, N, T, prefix);
248 else {
249 const makeTypeString = "?" ~ makeTypeString!(i+1, N, T, prefix);
250 static assert(false, "Unknown type");
251 }
252 } else {
253 const makeTypeString = "?" ~ makeTypeString!(i+1, N, T, prefix);
254 static assert(false, "Unknown type");
255 }
256 } else
257 const makeTypeString = "";
258 }
259
260 template makeTypeStringForStruct(alias opt) {
261 const makeTypeStringForStruct = makeTypeString!(0, opt.names, opt.types, opt.name~".")[0..$-2];
262 }
263
264 /* some leftovers
265 template handleType(T, char[] prefix="") {
266 static if(is(typeof(T) == struct)) {
267 static if(T.type == "enum")
268 // another dmdfe weirdness: T.stringof == "Enum!(Type)" here, but if do
269 // alias T handleType;, the result.stringof is "struct Enum".
270 alias T handleType;
271 } else
272 alias T handleType;
273 }
274 */
275