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;
+}
+*/
+