Even more cleanup. Added ✨pretty colors✨ to the VM's debugger
This commit is contained in:
parent
77fd5931fa
commit
47a6f16664
|
@ -77,21 +77,22 @@ proc newPeonVM*: PeonVM =
|
||||||
result.initCache()
|
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:
|
if value:
|
||||||
return self.cache[1]
|
return self.cache[1]
|
||||||
return self.cache[0]
|
return self.cache[0]
|
||||||
|
|
||||||
proc getInf*(self: PeonVM, positive: bool): uint64 {.inline.} =
|
proc getInf*(self: PeonVM, positive: bool): uint64 =
|
||||||
if positive:
|
if positive:
|
||||||
return self.cache[3]
|
return self.cache[3]
|
||||||
return self.cache[4]
|
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
|
# 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,
|
# that go through the getc/setc wrappers is frame-relative,
|
||||||
# meaning that the index is added to the current stack frame's
|
# meaning that the index is added to the current stack frame's
|
||||||
# bottom to obtain an absolute stack index
|
# bottom to obtain an absolute stack index
|
||||||
{.push inline.}
|
|
||||||
proc push(self: PeonVM, obj: uint64) =
|
proc push(self: PeonVM, obj: uint64) =
|
||||||
## Pushes a value object onto the
|
## Pushes a value object onto the
|
||||||
## operand stack
|
## operand stack
|
||||||
|
@ -288,8 +288,6 @@ proc constReadUInt8(self: PeonVM, idx: int): uint8 =
|
||||||
result = self.chunk.consts[idx]
|
result = self.chunk.consts[idx]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc constReadFloat32(self: PeonVM, idx: int): float32 =
|
proc constReadFloat32(self: PeonVM, idx: int): float32 =
|
||||||
## Reads a constant from the
|
## Reads a constant from the
|
||||||
## chunk's constant table and
|
## 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 + 4], self.chunk.consts[idx + 5],
|
||||||
self.chunk.consts[idx + 6], self.chunk.consts[idx + 7]]
|
self.chunk.consts[idx + 6], self.chunk.consts[idx + 7]]
|
||||||
copyMem(result.addr, arr.addr, sizeof(arr))
|
copyMem(result.addr, arr.addr, sizeof(arr))
|
||||||
|
|
||||||
{.pop.}
|
{.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) =
|
proc dispatch*(self: PeonVM) =
|
||||||
## Main bytecode dispatch loop
|
## Main bytecode dispatch loop
|
||||||
var instruction {.register.}: OpCode
|
var instruction {.register.}: OpCode
|
||||||
while true:
|
while true:
|
||||||
{.computedgoto.} # https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
{.computedgoto.} # https://nim-lang.org/docs/manual.html#pragmas-computedgoto-pragma
|
||||||
when debugVM:
|
when debugVM:
|
||||||
echo &"IP: {self.ip}"
|
self.debug()
|
||||||
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
|
|
||||||
instruction = OpCode(self.readByte())
|
instruction = OpCode(self.readByte())
|
||||||
case instruction:
|
case instruction:
|
||||||
# Constant loading instructions
|
# Constant loading instructions
|
||||||
|
@ -391,9 +425,9 @@ proc dispatch*(self: PeonVM) =
|
||||||
# how the stack works, all arguments before the call
|
# how the stack works, all arguments before the call
|
||||||
# are in the reverse order in which they are passed
|
# are in the reverse order in which they are passed
|
||||||
# to the function
|
# to the function
|
||||||
var argc {.used.} = self.readLong().int
|
let argc = self.readLong().int
|
||||||
let retAddr = self.peek(-argc - 1) # Return address
|
let retAddr = self.peek(-argc - 1) # Return address
|
||||||
let jmpAddr = self.peek(-argc - 2) # Function address
|
let jmpAddr = self.peek(-argc - 2) # Function address
|
||||||
self.ip = jmpAddr
|
self.ip = jmpAddr
|
||||||
self.pushc(jmpAddr)
|
self.pushc(jmpAddr)
|
||||||
self.pushc(retAddr)
|
self.pushc(retAddr)
|
||||||
|
@ -410,13 +444,6 @@ proc dispatch*(self: PeonVM) =
|
||||||
# not needed there anymore
|
# not needed there anymore
|
||||||
discard self.pop()
|
discard self.pop()
|
||||||
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:
|
of Return:
|
||||||
# Returns from a function.
|
# Returns from a function.
|
||||||
# Every peon program is wrapped
|
# Every peon program is wrapped
|
||||||
|
@ -595,6 +622,7 @@ proc dispatch*(self: PeonVM) =
|
||||||
self.push(not self.pop())
|
self.push(not self.pop())
|
||||||
of And:
|
of And:
|
||||||
self.push(self.pop() and self.pop())
|
self.push(self.pop() and self.pop())
|
||||||
|
# Comparison opcodes
|
||||||
of Equal:
|
of Equal:
|
||||||
self.push(self.getBool(self.pop() == self.pop()))
|
self.push(self.getBool(self.pop() == self.pop()))
|
||||||
of NotEqual:
|
of NotEqual:
|
||||||
|
@ -607,12 +635,10 @@ proc dispatch*(self: PeonVM) =
|
||||||
self.push(self.getBool(self.pop() !>= self.pop()))
|
self.push(self.getBool(self.pop() !>= self.pop()))
|
||||||
of LessOrEqual:
|
of LessOrEqual:
|
||||||
self.push(self.getBool(self.pop() <= self.pop()))
|
self.push(self.getBool(self.pop() <= self.pop()))
|
||||||
|
# Print opcodes
|
||||||
of PrintInt64:
|
of PrintInt64:
|
||||||
# Prints the value at the top of the stack
|
|
||||||
# as an int64
|
|
||||||
echo int64(self.pop())
|
echo int64(self.pop())
|
||||||
of PrintUInt64:
|
of PrintUInt64:
|
||||||
# Prints the value at the top of the stack
|
|
||||||
echo self.pop()
|
echo self.pop()
|
||||||
of PrintInt32:
|
of PrintInt32:
|
||||||
echo int32(self.pop())
|
echo int32(self.pop())
|
||||||
|
@ -631,8 +657,6 @@ proc dispatch*(self: PeonVM) =
|
||||||
of PrintFloat64:
|
of PrintFloat64:
|
||||||
echo cast[float](self.pop())
|
echo cast[float](self.pop())
|
||||||
of PrintHex:
|
of PrintHex:
|
||||||
# Prints the value at the top of the stack
|
|
||||||
# as a hexadecimal integer
|
|
||||||
echo "0x" & self.pop().toHex().strip(chars={'0'})
|
echo "0x" & self.pop().toHex().strip(chars={'0'})
|
||||||
of PrintBool:
|
of PrintBool:
|
||||||
if self.pop().bool:
|
if self.pop().bool:
|
||||||
|
|
|
@ -123,8 +123,6 @@ proc repl =
|
||||||
styledEcho fgGreen, "OK"
|
styledEcho fgGreen, "OK"
|
||||||
else:
|
else:
|
||||||
styledEcho fgRed, "Corrupted"
|
styledEcho fgRed, "Corrupted"
|
||||||
when debugVM:
|
|
||||||
styledEcho fgCyan, "\n\nExecution step: "
|
|
||||||
vm.run(serialized.chunk)
|
vm.run(serialized.chunk)
|
||||||
except LexingError:
|
except LexingError:
|
||||||
input = ""
|
input = ""
|
||||||
|
@ -258,8 +256,6 @@ proc runFile(f: string, interactive: bool = false, fromString: bool = false) =
|
||||||
styledEcho fgGreen, "OK"
|
styledEcho fgGreen, "OK"
|
||||||
else:
|
else:
|
||||||
styledEcho fgRed, "Corrupted"
|
styledEcho fgRed, "Corrupted"
|
||||||
when debugVM:
|
|
||||||
styledEcho fgCyan, "\n\nExecution step: "
|
|
||||||
vm.run(serialized.chunk)
|
vm.run(serialized.chunk)
|
||||||
except LexingError:
|
except LexingError:
|
||||||
var exc = LexingError(getCurrentException())
|
var exc = LexingError(getCurrentException())
|
||||||
|
|
Loading…
Reference in New Issue