More Script Interpreting
Today I made some more progress on my script interpreter, such that the return, break, and continue keywords are now supported.
I'm not entirely happy about my implementation because it strikes me as a bit inelegant. Basically each return, break, or continue is turned into a ControlExpression object, which when evaluated returns a value of type CONTROL_TYPE. Every other type of Expression then watches the results of its sub expressions for CONTROL_TYPE values. Loop Expressions catch break and continue values and act to break or continue the loop. All other types of expressions just immediately abort and return the CONTROL_TYPE value as the result of their evaluation. I'm not terribly happy because every type of Expression now has ts evaluation code cluttered up with checks for CONTROL_TYPE values. However, it does work and preserves the possibility of writing great expressions like:
while(y>=1){
y++;
x = 2 + if(y < 6) 9; else 5-break;
}
Yes, the if/else block can be an arithmetic subexpression, as can the break itself. Frankly I don't think that allowing use of break this way is terribly useful, but preventing it would be far more work for little gain, and I do definitely want to allow lines like x = 2 + if(y < 6) 9; else 5;
Another thing that I tossed in was allowing the break keyword to accept a parameter which specifies the number of loops to break out of. It's not really a necessary feature; as long as I have used C and C++ I've gotten along fine without it, but it's convenient and user-friendly to allow it, I think.
One possibility that I had to stop and think about a bit was the expression return(return(5));. What this will do is to return a value which will itself trigger an immediate return. Here's a complete example:
int foo(){
int temp = bar() * bar();
temp += 2;
return(temp);
}
int bar(){
return(return(5));
}
One might expect the result of calling foo() would be 27 (=(5*5)+2), but the result would actually be 5. Why? The nested returns mean that the result of bar() is not an integer object with value 5, it's a control object with value return, which carries as data an integer object with a value of 5. Within foo the multiplication expression will discover that it has received a control object, and return that immediately. Likewise so will the assignment expression. The crazed return object will continue upward until it causes the interpreter to return out of the foo function with a value of 5.
Fascinating though this is, it looks to me like it can only lead to disaster, since bar has no idea what kind of havoc it's wreaking inside of foo by doing this. Thus, I will be putting in measures to prevent this, namely disallowing expressions of type CONTROL_TYPE from being the parameter of the return keyword. Still, it was a fun possibility to consider.