Added some docs, LoadVar to the VM and readInt32

This commit is contained in:
Mattia Giambirtone 2022-05-23 14:03:17 +02:00
parent 9c14bfae91
commit 396f40d3d6
1 changed files with 35 additions and 5 deletions

View File

@ -28,6 +28,7 @@ type
cache: array[6, PeonObject] # Singletons cache
chunk: Chunk # Piece of bytecode to execute
frames: seq[int] # Stores the initial index of stack frames
heapVars: seq[PeonObject] # Stores variables that do not have stack semantics (i.e. "static")
proc initCache*(self: PeonVM) =
@ -67,7 +68,10 @@ proc getInf*(self: PeonVM, positive: bool): PeonObject =
proc getNan*(self: PeonVM): PeonObject = self.cache[5]
## Stack primitives
## Stack primitives. Note: all stack accessing that goes
## through the get/set wrappers is frame-relative, meaning
## that the index is added to the current stack frame's
## bottom to obtain an absolute stack index.
proc push(self: PeonVM, obj: PeonObject) =
## Pushes a Peon object onto the
@ -83,7 +87,7 @@ proc pop(self: PeonVM): PeonObject =
proc peek(self: PeonVM): PeonObject =
## Returns the element at the top
## Returns the Peon object at the top
## of the stack without consuming
## it
return self.stack[^1]
@ -168,6 +172,17 @@ proc readUInt32(self: PeonVM, idx: int): PeonObject =
copyMem(result.uInt.addr, arr.addr, sizeof(arr))
proc readInt32(self: PeonVM, idx: int): PeonObject =
## Reads a constant from the
## chunk's constant table and
## returns a Peon object. Assumes
## the constant is an Int32
var arr = [self.chunk.consts[idx], self.chunk.consts[idx + 1],
self.chunk.consts[idx + 2], self.chunk.consts[idx + 3]]
result = PeonObject(kind: Int32)
copyMem(result.`int`.addr, arr.addr, sizeof(arr))
proc dispatch*(self: PeonVM) =
## Main bytecode dispatch loop
var instruction: OpCode
@ -180,6 +195,7 @@ proc dispatch*(self: PeonVM) =
echo &"Instruction: {instruction}"
discard readLine stdin
case instruction:
# Constant loading
of LoadTrue:
self.push(self.getBool(true))
of LoadFalse:
@ -197,14 +213,20 @@ proc dispatch*(self: PeonVM) =
of LoadUInt32:
self.push(self.readUInt32(int(self.readLong())))
of Call:
# Calls a function. The calling convention for peon
# functions is pretty simple: the return address sits
# at the bottom of the stack frame, then follow the
# arguments and all temporaries/local variables
let newIp = self.readLong()
# We do this because if we immediately changed
# the instruction pointer, we'd read the wrong
# value for the argument count. Storing it and
# changing it later fixes this issue
let newIp = self.readLong()
self.frames.add(int(self.readLong()))
self.ip = int(newIp)
of OpCode.Return:
# Returns from a void function or terminates the
# program entirely if we're at the topmost frame
if self.frames.len() > 1:
let frame = self.frames.pop()
for i in countdown(self.stack.high(), frame):
@ -213,15 +235,23 @@ proc dispatch*(self: PeonVM) =
else:
return
of ReturnValue:
# Returns from a function which has a return value,
# pushing it on the stack
let retVal = self.pop()
let frame = self.frames.pop()
for i in countdown(self.stack.high(), frame):
discard self.pop()
self.ip = int(self.pop().uInt)
self.push(retVal)
of OpCode.StoreVar:
of StoreVar:
# Stores the value at the top of the stack
# into the given stack index
self.set(int(self.readLong()), self.pop())
of OpCode.LoadVar:
of StoreHeap:
self.heapVars.add(self.pop())
of LoadHeap:
self.push(self.heapVars[self.readLong()])
of LoadVar:
self.push(self.get(int(self.readLong())))
of NoOp:
continue