Design of reflective enums
renoX
renosky at free.fr
Mon Feb 19 09:02:30 PST 2007
Michiel Wrote:
> renoX wrote:
>
> > Hello,
> > Kevin Bealer has started an implementation (two implementations in fact!) of reflective enums, and I wanted to discuss the use case and the design of this feature to make it as useful as possible.
> > Reflective enums have two useful properties that don't have normal enums:
> > - their label is printable
> > - it's possible to do a foreach on all the possible values.
>
> By the way, should this not be in the core language?
Well I think that Ada does it in the core language (but I think that they are not printable), it is able to define enum as an index array as you suggest in your second email.
As the more I look at D, the more I find it similar to Ada, it is perhaps a good idea to make them those enhanced enum in the core language, and as an improvement to Ada those enum should be printable (maybe as an option to save memory) .
In the meantime, my trial is below, but it doesn't work when there are two enums: the two toString conflicts, even though they should not because their parameter is a different enum type.
Should I report this as a bug?
renoX
import std.stdio;
import std.metastrings;
template Find(char[] A, char[] B) {
static if (A.length < B.length)
{
const int Find = -1;
} else static if (A[0..B.length] == B) {
const int Find = 0;
} else static if (-1 == Find!(A[1..$], B)) {
const int Find = -1;
} else {
const int Find = 1 + Find!(A[1..$], B);
}
}
template SplitFirst(char[] A, char[] B) {
const int Location = Find!(A, B);
static if (Location == -1) {
const char[] First = A;
const char[] Rest = "";
} else {
const char[] First = A[0..Location];
const char[] Rest = A[Location+B.length..$];
}
}
template ChompSpaces(char[] A) {
static if (A.length) {
static if (A[0] == ' ') {
alias ChompSpaces!(A[1..$]) ChompSpaces;
} else static if (A[$-1] == ' ') {
alias ChompSpaces!(A[0..$-1]) ChompSpaces;
} else {
alias A ChompSpaces;
}
} else {
const char[] ChompSpaces = "";
}
}
template SplitChomp(char[] A, char[] B) {
alias ChompSpaces!(SplitFirst!(A, B).First) First;
alias ChompSpaces!(SplitFirst!(A, B).Rest) Rest;
}
template EnumName(char[] A) {
alias SplitChomp!(SplitFirst!(A, ",").First, "=").First EnumName;
}
template EnumAssign(char[] A) {
alias SplitChomp!(SplitFirst!(A, ",").First, "=").Rest EnumAssign;
}
template EnumValue(char[] A, int i) {
static if (EnumAssign!(A) == "") {
const int EnumValue = i;
} else {
const int EnumValue =
mixin(ParseInteger!(EnumAssign!(A)).value);
}
}
template EnumListName(char[] A) {
alias SplitChomp!(A, "{").First EnumListName;
}
template EnumBody(char[] A) {
alias SplitChomp!(SplitFirst!(A, "}").First, "{").Rest EnumBody;
}
template BuildOneEnum(char[] A, int i) {
const char[] BuildOneEnum =
"const int "~EnumName!(A)~" = "~
ToString!(EnumValue!(A, i))~";\n";
}
template BuildEnums(char[] A, int i) {
static if (SplitChomp!(A, ",").Rest.length == 0) {
const char[] BuildEnums = BuildOneEnum!(A, EnumValue!(A, i));
} else {
const char[] BuildEnums =
BuildOneEnum!(SplitChomp!(A, ",").First, EnumValue!(A, i)) ~
BuildEnums!(SplitChomp!(A, ",").Rest, EnumValue!(A, i)+1);
}
}
template BuildOneCase(char[] A, int i, bool full) {
static if (!full) {
const char[] BuildOneCase =
"case "~ToString!(EnumValue!(A, i))~
": return \""~EnumName!(A)~"\";\n";
} else {
const char[] BuildOneCase =
"case "~ToString!(EnumValue!(A, i))~
": return \""~EnumName!(A)~"("~ToString!(EnumValue!(A, i))~")\";\n";
}
}
template BuildEnumCases(char[] A, int i, bool full) {
static if (SplitChomp!(A, ",").Rest.length == 0) {
const char[] BuildEnumCases =
BuildOneCase!(A, EnumValue!(A, i), full);
} else {
const char[] BuildEnumCases =
BuildOneCase!(SplitChomp!(A, ",").First,
EnumValue!(A, i), full) ~
BuildEnumCases!(SplitChomp!(A, ",").Rest,
EnumValue!(A, i)+1,full);
}
}
template BuildEnumSwitch(char[] A, int i, bool full) {
const char[] BuildEnumSwitch =
"switch(x) {"~
BuildEnumCases!(A, i, full) ~
"default: "~
" throw new Exception(\"enumeration out of range\");"
"}";
}
template BuildEnumElem(char[] A, char[]enumListName, int i, int ekv) {
static if (ekv == 0) {
const char[] BuildEnumElem =
enumListName~"."~EnumName!(A)~", ";
} ;
static if (ekv == 1) {
const char[] BuildEnumElem =
"\""~EnumName!(A)~"\", ";
};
static if (ekv == 2) {
const char[] BuildEnumElem =
ToString!(EnumValue!(A, i))~", ";
}
}
// build the list of key if key is true, the list of values if key is false
template BuildEnumList(char[] A, char[]enumListName, int i, int ekv) {
static if (SplitChomp!(A, ",").Rest.length == 0) {
const char[] BuildEnumList =
BuildEnumElem!(A, enumListName, EnumValue!(A, i), ekv);
} else {
const char[] BuildEnumList =
BuildEnumElem!(SplitChomp!(A, ",").First, enumListName, EnumValue!(A, i), ekv)~
BuildEnumList!(SplitChomp!(A, ",").Rest, enumListName, EnumValue!(A, i)+1, ekv);
}
}
//to be mature it should parse also the EnumBaseType
template DefEnum(char[] enum_str) {
mixin("enum "~enum_str~";");
mixin(
"static char[] toString("~EnumListName!(enum_str)~" val)
{
int x = val; "~
BuildEnumSwitch!(EnumBody!(enum_str), 0, false)~
" }"
);
mixin(
"static char[] toFullString("~EnumListName!(enum_str)~" val)
{
int x = val; "~
BuildEnumSwitch!(EnumBody!(enum_str), 0, true)~
" }"
);
mixin(
"const "~EnumListName!(enum_str)~"[] "~EnumListName!(enum_str)~"_elem ="~
" [ "~
BuildEnumList!(EnumBody!(enum_str), EnumListName!(enum_str), 0, 0)~
" ];"
);
mixin(
"const char[][]"~EnumListName!(enum_str)~"_keys = [ "~
BuildEnumList!(EnumBody!(enum_str), EnumListName!(enum_str), 0, 1)~
" ];"
);
mixin(
"const int[]"~EnumListName!(enum_str)~"_values = [ "~
BuildEnumList!(EnumBody!(enum_str), EnumListName!(enum_str), 0, 2)~
" ];"
);
}
int main(char[][] args)
{
// mixin DefEnum!("LEnum2 {other=2, cont, end2=15, ps}");
mixin DefEnum!("LEnum {start, middle, end=10, ps, pps,}");
LEnum s = LEnum.start;
writefln("s is %s, with name %s full name '%s'\n", s, toString(s), toFullString(s));
foreach(i,v; LEnum_elem) {
writefln("Enum %d has name=%s value %d", i, toString(v), v);
}
// LEnum2 o = LEnum2.other;
// writefln("o is %s, with name %s full name '%s'\n", o, toString(o), toFullString(o));
foreach(i,v; LEnum_keys) {
writefln("Enum %d has name=%s and value %d", i, v, LEnum_values[i]);
}
foreach(i,v; LEnum_values) {
writefln("Enum %d has name=%s value %d", i, toString(cast(LEnum)v), v);
}
return 0;
}
More information about the Digitalmars-d
mailing list