f(int v){ select(v) { 1: out "one",end; 2:{ out "three"; out end; } 3: out "three",end; }}f(int v){ select(v) { 1: out "one",end; 2:{ out "three"; out end; } 3: out "three",end; } else out "some other value",end;}f(int v){ select(v) { 1: out "one",end; 2:{ out "three"; out end; } 3: out "three",end; } else { int x=v*2; out "whatever it is, it is half of ",x,end; }}
It is unlike C++ switch in that any expression can form the equivalent of the case section and you don't need break statements. By default a single statement follows the case colon and you need to use braces to have multiple statements execute under a single case. You can't fall through like with a C++ switch - if you match a case, only those instructions following the case are executed.
The optional else section is roughly equivalent to C++ default and is executed if none of the cases in the select body are matched.
It wasn't too bad to implement. A minor problem is that in order for it to work, it has to duplicate the top of the math stack before evaluating the case expression and performing a comparision (comparisions are performed on the top two items on the math stack in the vm, like every other binary operation). This means that at the end of the select statement, an additional mpop instruction is needed.
Unfortunately, since it is possible to nest select statements indefinately and to have return statements executed in the case sections, it was necessary to have an external counter track the depth of select-nesting at any point and then issue that number of mpop instructions in the event of a return statement.
Feels like a bit of a hack but wasn't particularly hard to code and I've tested it fairly thoroughly, including creating local variables inside select statements and returning from deeply nested positions and the vm is not complaining that the math stack is either underflown or still has data at the termination of the program.
From a text adventure point of view, this feature will be most useful for switching on verbs e.g.
void response(word vb,word nn){ select(vb) { #get: on_get(nn); #drop: on_drop(nn); #quit: exit(); } else { out "I don't understand.",end; clear_commands(); }}
sort of thing.
So on it goes. Next I need to implement some kind of system for recording connections between locations. I want this to be built in rather than expressed via the language because I want to provide route-finding features in the vm rather than have to implement them in the language directly.
Anyway, I've rambled enough for one night.
rather than hardcoding such a thing (in C++), it would be more awesome to do something like -
std::map< std::string, boost::function< void( word ) > > what_to_do_with_verbs
to translate between a verb and a function which is associated with the verb. I'm not sure how far you're planning on developing your language (or if its even an issue for you!), but I enjoy over-engineering everything, and this method allows for more robust dynamic content. I guess.
:D