The main point of interest is the use of CpsExprBuilder as an accumulator and explicit looping over sub-expressions instead of using meta-continuations, as is popular in most papers on CPS transformations. This is not the only possible way to implement such CpsExprBuilder: another option would be to have a mutable CPS expression with a pointer into it, and gradually grow it. But since you can't just take a pointer to a list's element in Python, you would probably have to keep a whole path (as, say, an array of indexes), and re-traverse the tree every time you append to it, like this:
result = {
'expr': ['let', [['#t0', 2], ['@k0', ['cont', ['#t1'], None]]], ['f', '#t0', '@k0']],
'path': [1, 1, 1, 2],
}
cursor = result['expr']
for index in result['path'][:-1]:
cursor = cursor[index]
cursor[result['path'][-1]] = ['g', '@halt', '#t1']
I've tried this approach, and even when it's encapsulated in a class, it's way too easy to accidentally end up with a random None somewhere deep inside your resulting expression. So instead, the expression's tree is turned inside out, so to speak. It's similar to using an explicit stack instead of using recursion.[0] https://gist.github.com/Joker-vD/7cddcfada042ed486dd74690ae9...
[1] https://www.microsoft.com/en-us/research/wp-content/uploads/...