-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Exceptions refactoring and try-finally transform #171
Conversation
Nim has a "exception stack" system where inner except branches will push a new exception to the stack then pop it after it's done. To replicate this accurately in CPS, we use one local per cps `try` instead of a single field like how it is done currently. This is because we set the global exception to whatever the stored exception was in our continuation leg, so to prevent inner cps `try`s from overriding what is perceived to be the "current" exception of the outer branch, we simply give them different locals. Ideally we can tap right into Nim's exception `up` field, but it's not exported.
Not sure what I thought of when I wrote that code, but we can just run filter on the outer node and don't have to think about the bugs this `for` would cause us.
Fixes disruptek/cps#164
Instead of creating a continuation leg for each except branch, we merge all except branches into one, then turn that into a continuation. That way we only have one continuation for all handlers, allow for a better implementation of cps exceptions in the future.
Implements try-finally transformation for CPS by generating finally as a continuation leg with a static generic for where it will continues after. Untested because the compiler broke. Known issues: - Early returns are not handled, which can be fixed by improving isScopeExit and making early termination an annotation. Fixes #80.
Instead of waiting for nim-lang/Nim#18254 and any other templates bug to be fix. We take the initiative and write our own continuation templater. It appears to work well enough to use as an alternative until a better alternative become available. I've also added an extra test that verify the exception re-raise property.
We ended up not needing it for finally
We implement early returns as `cpsTerminate` then tie them up at the end via `cpsResolver`. This way try-finally can capture early termination and specialize to those. Need @disruptek to review this stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really great advancement. I also think this stuff should go into its own file; it can be imported into transform
, right?
cps/transform.nim
Outdated
# The key is the symbol need updating and the value is what to update | ||
# it to | ||
var replacements: Table[NimNode, NimNode] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than a comment, I'd just use a type declaration. 😁
cps/transform.nim
Outdated
result = copyNimTree(replacements[n]) | ||
|
||
replacements[replace] = replacement | ||
templ.filter(generator) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eh do we ever use it like this? I think we prefer result = filter(templ, generator)
right?
As usual, the compiler blocks our transform:
nim-lang/Nim#18254Worked around that bugBlocked by: nim-lang/Nim#18247
So main changes:
try-except
is now implemented by merging allexcept
branches into one then turn that into a continuation. This should help with implementing an unwinding system for cps.try-finally
is implemented by turning thefinally
leg into a continuationtaking a generic parameter pointing to where to go next.then specialize it to each exit legs.Known issues:
try-except
doesn't work with except branches matching multiple exception types:except ValueError, IOError
.try-finally
doesn't handle early returns, but this is fixable by improvingisScopeExit
and making early return an annotation.