Mercurial > projects > dil
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 |