Mercurial > projects > dil
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/docgen/config/reflection.d Sun Mar 09 00:12:19 2008 +0100 @@ -0,0 +1,275 @@ +/** + * Author: Jari-Matti Mäkelä + * License: GPL3 + */ +module docgen.config.reflection; + +import docgen.misc.meta; +import docgen.misc.options; + +//// +// +// Macros for reading input +// +//// + +char[] _wrong(char[] key) { + return `if (val.length != 1) throw new Exception( + "Wrong number of arguments for `~key~`");`; +} + +char[] _switch(char[] stuff) { + return "switch(key) {" ~ stuff ~ "}"; +} + +char[] _parseI(char[] key) { + return `case "` ~ key ~ `":` ~ _wrong(key) ~ key ~ + `= Integer.parse(val[0]); continue;`; +} + +char[] _parseS(char[] key) { + return `case "` ~ key ~ `":` ~ _wrong(key) ~ key ~ + `= val[0]; continue;`; +} + +char[] _parseB(char[] key) { + return `case "` ~ key ~ `":` ~ _wrong(key) ~ key ~ + `= val[0] == "true" ? true : val[0] == "false" ? false : err(); continue;`; +} + +char[] _parseList(char[] key) { + return `case "` ~ key ~ `":foreach(v; val) ` ~ + key ~ `~= v; continue;`; +} + +template _parseEnum_(bool list, char[] key, V...) { + static if (V.length>1) + const char[] _parseEnum_ = + `case "` ~ V[0] ~ `":` ~ key ~ (list ? "~" : "") ~ `=` ~ V[1] ~ `; continue;` \n ~ + _parseEnum_!(list, key, V[2..$]); + else + const char[] _parseEnum_ = ""; +} + +template _parseEnum(char[] key, V...) { + const char[] _parseEnum = `case "` ~ key ~ + `":` ~ _wrong(key) ~ `switch(val[0]) {` ~ + _parseEnum_!(false, key, V) ~ + `default: err(); } continue;`; +} + +template _parseEnumList(char[] key, V...) { + const char[] _parseEnumList = `case "` ~ key ~ + `":` ~ `foreach (item; val) switch(item) {` ~ + _parseEnum_!(true, key, V) ~ + `default: err(); } continue;`; +} + +//// +// +// Reflection for properties. This code will hopefully get better when the dmdfe bugs get fixed. +// +//// + +// dmdfe bug -- Seriously WTF? +char[] fixType(char[] type) { + return type[$-1] == ' ' ? type[0..$-1] : type; +} + +// take the last part of field name +char[] getLastName(char[] field) { + if (field.length == 0) return ""; + int t = 0; + // dmdfe bug: a while loop causes index out of bounds error + for (int i=field.length-1; i >= 0; i--) + if (field[i] == '.') { t = i+1; break; } + return field[t..$]; +} + +// dmdfe bug: cannot return evalType alias +template _evalType(char[] type) { + mixin("alias "~type~" value;"); +} + +// Note: stuple wrappers needed for tuples, otherwise: +// dmdfe bug: cc1d: ../.././gcc/d/dmd/expression.c:4865: virtual Expression* DotIdExp::semantic(Scope*): Assertion `0' failed. +template evalType(char[] type) { + alias _evalType!(type).value evalType; +} + +// wraps the reflected struct and enum data inside struct because otherwise the handling becomes impossibly hard +template getType(T) { + static if(is(T == struct)) + alias Struct!(T) getType; + else static if(is(T == enum)) + alias Enum!(T) getType; + else static if(isEnumList!(T)) + alias Enum!(enumListType!(T), true) getType; + else + alias T getType; +} + +template getTypes(alias S, int idx = S.tupleof.length) { + static if(idx) + alias Tuple!(getTypes!(S, idx-1), getType!(typeof(S.tupleof[idx-1]))) getTypes; + else + alias Tuple!() getTypes; +} + +/** + * Extracts the comma separated struct field names using .tupleof.stringof. + * This is needed since the struct.tupleof[n].stringof is broken for enums and tuples in dmdfe. + * + * Bugs: handling of tuples + */ +char[] __getNames(char[] type) { + char[] tmp; + bool end = false; + + foreach(c; type[5..$]) { + if (c != ' ' && c != '(' && c != ')' && end) tmp ~= c; + if (c == ',') end = false; + if (c == '.') end = true; + } + + return tmp; +} + +template _getNames(char[] str, T...) { + static if (str.length) { + static if (str[0] == ',') + alias _getNames!(str[1..$], T, "") _getNames; + else + alias _getNames!(str[1..$], T[0..$-1], T[$-1] ~ str[0]) _getNames; + } else + alias T _getNames; +} + +template getNames(char[] str) { + alias _getNames!(__getNames(str), "") getNames; +} + +struct Struct(alias T) { + const type = "struct"; // used for pattern matching... apparently there's no other way + const name = fixType(T.stringof); // dmdfe bug: trailing space + alias STuple!(getNames!(T.tupleof.stringof)) names; + alias STuple!(getTypes!(T)) types; +} + +struct Enum(alias T, bool list = false) { + const type = list ? "enumlist" : "enum"; // used for pattern matching... apparently there's no other way + const name = T.stringof[1..$]; // dmdfe bug: returns enum base type instead enum type + alias evalType!("___"~name).tuple elements; +} + +// determines the enumtype[] type +template isEnumList(T : T[]) { + const isEnumList = T.stringof[0] == '_'; +} + +template isEnumList(T) { + const isEnumList = false; +} + +template enumListType(T : T[]) { + alias T enumListType; +} + +template enumListType(T) { + static assert(false, "Not enum list type!"); +} + +char[] createIParser(char[] field) { + return `_parseI("` ~ field ~ `") ~` \n; +} + +char[] createBParser(char[] field) { + return `_parseB("` ~ field ~ `") ~` \n; +} + +char[] createSParser(char[] field) { + return `_parseS("` ~ field ~ `") ~` \n; +} + +char[] createLParser(char[] field) { + return `_parseList("` ~ field ~ `") ~` \n; +} + +char[] createEParser(char[] field, char[] contents) { + return `_parseEnum!("` ~ field ~ `",` ~ contents ~ `) ~` \n; +} + +char[] createELParser(char[] field, char[] contents) { + return `_parseEnumList!("` ~ field ~ `",` ~ contents ~ `) ~` \n; +} + +template _makeEnumString(char[] t, E...) { + static if (E.length) + const _makeEnumString = `"` ~ E[0] ~ `", "` ~ t ~ "." ~ E[0] ~ `",` ~ + _makeEnumString!(t, E[1..$]); + else + const _makeEnumString = ""; +} + +// avoids the following dmdfe bugs: +// - Error: elements is not a type (typeof(T).elements) +// - Error: tuple is not a valid template value argument (T.elements where T is the complex type def) +template makeEnumString(char[] t, T) { + const makeEnumString = _makeEnumString!(t, T.elements); +} + +/** + * Generates code for parsing data from the configuration data structure. + */ +template makeTypeString(int i, N, T, char[] prefix) { + static assert(N.tuple.length == T.tuple.length); + static if (i < N.tuple.length) { + static if (is(T.tuple[i] == bool)) + const makeTypeString = createBParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix); + else static if (is(T.tuple[i] : int)) + const makeTypeString = createIParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix); + else static if (is(T.tuple[i] == char[])) + const makeTypeString = createSParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix); + else static if (is(T.tuple[i] == char[][])) + const makeTypeString = createLParser(prefix ~ N.tuple[i]) ~ makeTypeString!(i+1, N, T, prefix); + else static if (is(T.tuple[i] == struct)) { + static if (T.tuple[i].type == "struct") + const makeTypeString = makeTypeString!(0, typeof(T.tuple[i].names), + typeof(T.tuple[i].types), prefix~N.tuple[i]~".") ~ + makeTypeString!(i+1, N, T, prefix); + else static if (T.tuple[i].type == "enum") + const makeTypeString = createEParser(prefix ~ N.tuple[i], + makeEnumString!(T.tuple[i].name, T.tuple[i])[0..$-1]) ~ + makeTypeString!(i+1, N, T, prefix); + else static if (T.tuple[i].type == "enumlist") + const makeTypeString = createELParser(prefix ~ N.tuple[i], + makeEnumString!(T.tuple[i].name, T.tuple[i])[0..$-1]) ~ + makeTypeString!(i+1, N, T, prefix); + else { + const makeTypeString = "?" ~ makeTypeString!(i+1, N, T, prefix); + static assert(false, "Unknown type"); + } + } else { + const makeTypeString = "?" ~ makeTypeString!(i+1, N, T, prefix); + static assert(false, "Unknown type"); + } + } else + const makeTypeString = ""; +} + +template makeTypeStringForStruct(alias opt) { + const makeTypeStringForStruct = makeTypeString!(0, opt.names, opt.types, opt.name~".")[0..$-2]; +} + +/* some leftovers +template handleType(T, char[] prefix="") { + static if(is(typeof(T) == struct)) { + static if(T.type == "enum") + // another dmdfe weirdness: T.stringof == "Enum!(Type)" here, but if do + // alias T handleType;, the result.stringof is "struct Enum". + alias T handleType; + } else + alias T handleType; +} +*/ +