-
Notifications
You must be signed in to change notification settings - Fork 0
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
spec/bytecode.md #2
Comments
Jump position is based on current bytecode file? |
Yes. Otherwise it's a call you want. |
Bikesheds, almost exactly 2 years later:
|
I forgot:
|
The WIP absolutely doesn't do this, it does
Seems annoying: I need to make sure a label can't be a valid AST element later on (see below), and I need to ensure a label doesn't count in the bytecode pos.
...Sounds annoying... |
The above comment ^ is completely outdated, and now our VM isn't recursive anymore, and we also have a well-typed and well-behaved AST. |
Instructions:
Push(valueType: int | str, value: this.type)
Pushes a value onto the stack, with the type given by
valueType
.Dup
Duplicates the element at the top of the stack.
Error: it is an error to use this instruction if the stack is empty.
Jump(mode: "stack" | "fixed", pos: usize)
Jumps to a position.
Right now, the VM doesn't have flags, so the
stack
mode will pop the stack and use the popped value as a boolean.Error: it is an error to do a stack-based jump if the stack is empty.
Call(name: str)
Generates a callframe and enters it. It is unspecified whether this is implemented recursively in the VM.
The name must be fully-qualified. Each module JSON will contain offsets for functions.
To allow for overloading, it is important that function names are mangled. See [mangling.md (TODO)](todo as i said).
The
std
module is reserved for the VM's own functions.Functions with a
void
return type do not push anything to the stack – *if a function's result is discarded, it is the frontend's responsability to generate apop
.When entering a function, the stack is empty. It is up to the frontend to generate
ArgumentLoad
instructions when necessary.Note: arity isn't necessary for now, so it's not present. However, if/when optional arguments are implemented, it might be necessary. Another option would be to create a more complex call where you give a
arguments
array (splat-like).Error: It is an error to call a function if the stack's size is smaller than the function arity.
Return(returns: bool)
Returns from the current callframe.
If
returns
is true, pops the stack and pushes it in the parent's callframe.The rest of the stack is discarded.
Error: it is an error to return with a return value if the stack is empty.
LocalLoad(name: str)
Loads a local for the current subroutine and pushes it to the stack. Each subroutine has its own dictionary of locals, which starts off empty.
Note: "locals" somewhat act like registers, but per-fn. They might turn unnecessary, but they're helpful for simpler compilation of local variables, and in the future, maybe for SSAF as well (?).
Note: how to implement nested functions is currently an open question.
Error: it is an error to load a unexisting local.
LocalStore(name: str)
Pops the stack and stores it in the current subroutine's locals dictionary at
name
.Error: it is an error to use this instruction when the stack is empty.
Removed instructions, compared to smallstack:
carry {set|invert}
: those only existed to demonstrateJump
, they're vastly unnecessary.math
: those can simply beCall
s.cmp
: those can simply beCall
s.NOTE about
Jump
:The VM doesn't (currently) have flags, like
ZF
/zero,CF
/carry,SF
/sign. If we want to implement x86-like jumps (see this). I'm not sure we want to do that, however. Bikeshedding welcome!The text was updated successfully, but these errors were encountered: