Whew, lots of new features and fixes in this release! Highlights include:
- on-err, err, and details implemented
- ccc (call/cc) implemented (actually proved ridiculously simple, at least until protect was implemented anyway)
- protect implemented (it's astounding to see how much implementing this function complicated the implementation of ccc and exception handling)
- major bug fix: evaluation order is now left to right. Previous versions stupidly did right to left evaluation. We didn't do a lot of work with side effects before which is why it went unnoticed for so long.
I just have to wonder if there's a better way of implementing protect than the rather kludgy way that I wound up doing it.
I think a more natural way to do this might be to stop at the first protect handler, then enact instructions that accomplish "call this handler, pop the frame of (or otherwise exit) the protect body, then make the same continuation call again." In fact, I wonder why you and Conan Dalton didn't do this to begin with. :-p
Just to explore this a bit, to help both of us understand... if this approach were extended to dynamic-wind, if you encountered a dynamic-wind form on your way up the stack, you might stop there and enact instructions of the form "call this handler, push the frame of (or otherwise enter) the dynamic-wind body, then make the same continuation call again." Does this make sense? Part of my concern is to have clear semantics for what happens if a continuation call exits or enters a handler block.
Meanwhile, an alternate (but not necessarily better) way to do it is to define a core language without 'protect and then wrap that core in a standard library that hides the original version of 'ccc and exposes a version that consults a global stack of 'protect handlers. This Ruby library does that: https://github.com/mame/dynamicwind.