From 47a6f16664e655edabd8d01caa0326794865ede1 Mon Sep 17 00:00:00 2001 From: Mattia Giambirtone Date: Wed, 17 Aug 2022 20:40:34 +0200 Subject: [PATCH] =?UTF-8?q?Even=20more=20cleanup.=20Added=20=E2=9C=A8prett?= =?UTF-8?q?y=20colors=E2=9C=A8=20to=20the=20VM's=20debugger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/backend/vm.nim | 100 ++++++++++++++++++++++++++++----------------- src/main.nim | 4 -- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/src/backend/vm.nim b/src/backend/vm.nim index dc3a29a..ae21d45 100644 --- a/src/backend/vm.nim +++ b/src/backend/vm.nim @@ -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: diff --git a/src/main.nim b/src/main.nim index 5e448d3..d69baa2 100644 --- a/src/main.nim +++ b/src/main.nim @@ -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())