I think it is somewhere in between the two. There is dynamic-ness, so
to desugar it to "raise %lastexception" is going to require some
global set!ing and non-trivial (but not particularly hard) desugaring
for exit points.
For example, in this first example, break should be desugared to
un-set the %lastexception, but in the second, it shouldn't.
while True:
try:
raise Exception
except:
# blah
break
raise # should error
==== desugars to =====>
try:
raise Exception
except:
%lastexception = $exn-id # or whatever we do in core
# blah
%lastexception = undefined
break
raise %lastexception # throws error, as %lastexception isn't defined
And:
try:
raise Exception
except:
while True:
break
raise
=== desugars to ===>
try:
raise Exception
except:
%lastexception = $exn-id
while True:
break
raise %lastexception
%lastexception = undefined
But none of this isn't stuff we can't do with a reasonably
straightforward desugaring-pass - we just need to figure out all the
exit points of except blocks (essentially break, continue, return, and
maybe yield?) and unset the global, and then we can just turn `raise`
into `raise %lastexception`. I originally thought it was more
complicated because I thought that the exceptions behaved more like a
stack, but they don't, (I did a bunch of testing and read some of the
specs).