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.
In any of these two modes, you can use debugger in your code to debug it at that point. This is similar tu Ruby's pry. There you can use these commands (similar to pry too):
By the way, before this PR you could also use debugger and lldb or gdb would stop at that point, if compiled with -d (otherwise it seems the program just crashes, maybe we should just ignore debugger in that case: something to improve outside of this PR)
When running in interpreted mode, semantic analysis is done as usual, but instead of then using LLVM to generate code, we compile code to bytecode (custom bytecode defined in this PR, totally unrelated to LLVM). Then there's an interpreter that understands this bytecode. All of this for a stack-based machine. If you know nothing about interpreters and you want to learn more, I recommend reading the excellent https://www.craftinginterpreters.com/a-bytecode-virtual-machine.html
The memory layout of things in interpreted mode matches the memory layout of compiled mode: a union of Int32 | String occupies 16 bytes in both modes, and there's an 8 bytes tag for the type ID. That said, the values for type IDs might not match between the two versions, and this makes the two worlds kind of incompatible (they can't interact with each other.)