Add a global interpreter state that can be managed via with statements.

This allows for interacting with the interpreter in a somewhat normal way,
without all of the code having to deal with it being transactional. It
does mean some non-obvious twiddling of some globals that make the
interpreter non-thread-safe, but we can make this use thread-local storage
later if that becomes a problem.