Even more cleanup. Added pretty colors to the VM's debugger

This commit is contained in:
Mattia Giambirtone 2022-08-17 20:40:34 +02:00
parent 77fd5931fa
commit 47a6f16664
2 changed files with 62 additions and 42 deletions

View File

@ -77,21 +77,22 @@ proc newPeonVM*: PeonVM =
result.initCache()
# Getters for singleton types (they are cached!)
# Getters for singleton types
{.push inline.}
proc getNil*(self: PeonVM): uint64 {.inline.} = self.cache[2]
proc getNil*(self: PeonVM): uint64 = self.cache[2]
proc getBool*(self: PeonVM, value: bool): uint64 {.inline.} =
proc getBool*(self: PeonVM, value: bool): uint64 =
if value:
return self.cache[1]
return self.cache[0]
proc getInf*(self: PeonVM, positive: bool): uint64 {.inline.} =
proc getInf*(self: PeonVM, positive: bool): uint64 =
if positive:
return self.cache[3]
return self.cache[4]
proc getNan*(self: PeonVM): uint64 {.inline.} = self.cache[5]
proc getNan*(self: PeonVM): uint64 = self.cache[5]
# Thanks to nim's *genius* idea of making x !> y a template
@ -113,7 +114,6 @@ proc `!>=`[T](a, b: T): auto {.inline, used.} =
# that go through the getc/setc wrappers is frame-relative,
# meaning that the index is added to the current stack frame's
# bottom to obtain an absolute stack index
{.push inline.}
proc push(self: PeonVM, obj: uint64) =
## Pushes a value object onto the
## operand stack
@ -288,8 +288,6 @@ proc constReadUInt8(self: PeonVM, idx: int): uint8 =
result = self.chunk.consts[idx]
proc constReadFloat32(self: PeonVM, idx: int): float32 =
## Reads a constant from the
## chunk's constant table and
@ -308,30 +306,66 @@ proc constReadFloat64(self: PeonVM, idx: int): float =
self.chunk.consts[idx + 4], self.chunk.consts[idx + 5],
self.chunk.consts[idx + 6], self.chunk.consts[idx + 7]]
copyMem(result.addr, arr.addr, sizeof(arr))
{.pop.}
when debugVM: # So nim shuts up
proc debug(self: PeonVM) =
## Implements the VM's runtime
## debugger
styledEcho fgMagenta, "IP: ", fgYellow, &"{self.ip}"
styledEcho fgBlue, "Instruction: ", fgRed, &"{OpCode(self.chunk.code[self.ip])} (", fgYellow, $self.chunk.code[self.ip], fgRed, ")"
if self.calls.len() !> 0:
stdout.styledWrite(fgGreen, "Call Stack: ", fgMagenta, "[")
for i, e in self.calls:
stdout.styledWrite(fgYellow, $e)
if i < self.calls.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
if self.operands.len() !> 0:
stdout.styledWrite(fgBlue, "Operand Stack: ", fgMagenta, "[")
for i, e in self.operands:
stdout.styledWrite(fgYellow, $e)
if i < self.operands.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
if self.frames.len() !> 0:
stdout.styledWrite(fgCyan, "Current Frame: ", fgMagenta, "[")
for i, e in self.calls[self.frames[^1]..^1]:
stdout.styledWrite(fgYellow, $e)
if i < self.calls.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
stdout.styledWrite(fgRed, "Live stack frames: ", fgMagenta, "[")
for i, e in self.frames:
stdout.styledWrite(fgYellow, $e)
if i < self.frames.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
if self.closedOver.len() !> 0:
stdout.styledWrite(fgGreen, "Closure Array: ", fgMagenta, "[")
for i, e in self.closedOver:
stdout.styledWrite(fgYellow, $e)
if i < self.closedOver.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
if self.results.len() !> 0:
stdout.styledWrite(fgYellow, "Function Results: ", fgMagenta, "[")
for i, e in self.results:
stdout.styledWrite(fgYellow, $e)
if i < self.results.high():
stdout.styledWrite(fgYellow, ", ")
styledEcho fgMagenta, "]"
discard readLine stdin
proc dispatch*(self: PeonVM) =
## Main bytecode dispatch loop
var instruction {.register.}: OpCode
while true:
{.computedgoto.} # https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
when debugVM:
echo &"IP: {self.ip}"
echo &"Instruction: {OpCode(self.chunk.code[self.ip])}"
if self.calls.len() !> 0:
echo &"Call Stack: {self.calls}"
if self.operands.len() !> 0:
echo &"Operand Stack: {self.operands}"
if self.frames.len() !> 0:
echo &"Current Frame: {self.calls[self.frames[^1]..^1]}"
echo &"Frames: {self.frames}"
if self.closedOver.len() !> 0:
echo &"Closure Array: {self.closedOver}"
if self.results.len() !> 0:
echo &"Results: {self.results}"
discard readLine stdin
self.debug()
instruction = OpCode(self.readByte())
case instruction:
# Constant loading instructions
@ -391,9 +425,9 @@ proc dispatch*(self: PeonVM) =
# how the stack works, all arguments before the call
# are in the reverse order in which they are passed
# to the function
var argc {.used.} = self.readLong().int
let retAddr = self.peek(-argc - 1) # Return address
let jmpAddr = self.peek(-argc - 2) # Function address
let argc = self.readLong().int
let retAddr = self.peek(-argc - 1) # Return address
let jmpAddr = self.peek(-argc - 2) # Function address
self.ip = jmpAddr
self.pushc(jmpAddr)
self.pushc(retAddr)
@ -410,13 +444,6 @@ proc dispatch*(self: PeonVM) =
# not needed there anymore
discard self.pop()
discard self.pop()
# TODO: Use the frame's initial size once
# we have more control over the
# memory
#[while argc !> 0:
dec(argc)
self.pushc(self.getNil())
]#
of Return:
# Returns from a function.
# Every peon program is wrapped
@ -595,6 +622,7 @@ proc dispatch*(self: PeonVM) =
self.push(not self.pop())
of And:
self.push(self.pop() and self.pop())
# Comparison opcodes
of Equal:
self.push(self.getBool(self.pop() == self.pop()))
of NotEqual:
@ -607,12 +635,10 @@ proc dispatch*(self: PeonVM) =
self.push(self.getBool(self.pop() !>= self.pop()))
of LessOrEqual:
self.push(self.getBool(self.pop() <= self.pop()))
# Print opcodes
of PrintInt64:
# Prints the value at the top of the stack
# as an int64
echo int64(self.pop())
of PrintUInt64:
# Prints the value at the top of the stack
echo self.pop()
of PrintInt32:
echo int32(self.pop())
@ -631,8 +657,6 @@ proc dispatch*(self: PeonVM) =
of PrintFloat64:
echo cast[float](self.pop())
of PrintHex:
# Prints the value at the top of the stack
# as a hexadecimal integer
echo "0x" & self.pop().toHex().strip(chars={'0'})
of PrintBool:
if self.pop().bool:

View File

@ -123,8 +123,6 @@ proc repl =
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
when debugVM:
styledEcho fgCyan, "\n\nExecution step: "
vm.run(serialized.chunk)
except LexingError:
input = ""
@ -258,8 +256,6 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
when debugVM:
styledEcho fgCyan, "\n\nExecution step: "
vm.run(serialized.chunk)
except LexingError:
var exc = LexingError(getCurrentException())