peon/src/util/debugger.nim

175 lines
6.4 KiB
Nim
Raw Normal View History

# Copyright 2022 Mattia Giambirtone & All Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ../frontend/meta/bytecode
import multibyte
import strformat
import strutils
import terminal
proc nl = stdout.write("\n")
proc printDebug(s: string, newline: bool = false) =
stdout.styledWrite(fgMagenta, "DEBUG - Disassembler -> ")
stdout.styledWrite(fgGreen, s)
if newline:
nl()
proc printName(opcode: OpCode, newline: bool = false) =
stdout.styledWrite(fgRed, $opcode, " (", fgYellow, $uint8(opcode), fgRed, ")")
if newline:
nl()
proc printInstruction(instruction: OpCode, newline: bool = false) =
printDebug("Instruction: ")
printName(instruction)
if newline:
nl()
proc simpleInstruction(instruction: OpCode, offset: int): int =
printInstruction(instruction)
nl()
return offset + 1
proc stackTripleInstruction(instruction: OpCode, chunk: Chunk,
offset: int): int =
## Debugs instructions that operate on a single value on the stack using a 24-bit operand
var slot = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[
offset + 3]].fromTriple()
printInstruction(instruction)
stdout.styledWrite(fgGreen, &", points to index ")
stdout.styledWriteLine(fgYellow, &"{slot}")
return offset + 4
proc stackDoubleInstruction(instruction: OpCode, chunk: Chunk,
offset: int): int =
## Debugs instructions that operate on a single value on the stack using a 16-bit operand
var slot = [chunk.code[offset + 1], chunk.code[offset + 2]].fromDouble()
printInstruction(instruction)
stdout.write(&", points to index ")
stdout.styledWrite(fgGreen, &", points to index ")
stdout.styledWriteLine(fgYellow, &"{slot}")
return offset + 3
proc argumentDoubleInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
## Debugs instructions that operate on a hardcoded value on the stack using a 16-bit operand
var slot = [chunk.code[offset + 1], chunk.code[offset + 2]].fromDouble()
printInstruction(instruction)
stdout.styledWrite(fgGreen, &", has argument ")
stdout.styledWriteLine(fgYellow, $slot)
return offset + 3
proc argumentTripleInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
## Debugs instructions that operate on a hardcoded value on the stack using a 24-bit operand
var slot = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[offset + 3]].fromTriple()
printInstruction(instruction)
stdout.styledWrite(fgGreen, ", has argument ")
stdout.styledWriteLine(fgYellow, $slot)
return offset + 4
proc callInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
## Debugs function calls
var slot = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[offset + 3]].fromTriple()
var args = [chunk.code[offset + 4], chunk.code[offset + 5], chunk.code[offset + 6]].fromTriple()
printInstruction(instruction)
stdout.styledWrite(fgGreen, &", jumps to address ", fgYellow, $slot, fgGreen, " with ", fgYellow, $args, fgGreen, " argument")
if args > 1:
stdout.styledWrite(fgYellow, "s")
nl()
return offset + 7
proc constantInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
## Debugs instructions that operate on the constant table
var constant = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[
offset + 3]].fromTriple()
printInstruction(instruction)
stdout.styledWrite(fgGreen, &", points to constant at position ", fgYellow, $constant)
nl()
printDebug("Operand: ")
stdout.styledWriteLine(fgYellow, &"{chunk.consts[constant]}")
return offset + 4
proc jumpInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
## Debugs jumps
var jump: int
case instruction:
2022-05-16 19:40:13 +02:00
of Jump, JumpIfFalse, JumpIfTrue, JumpIfFalsePop, JumpForwards, JumpBackwards:
jump = [chunk.code[offset + 1], chunk.code[offset + 2]].fromDouble().int()
of LongJump, LongJumpIfFalse, LongJumpIfTrue, LongJumpIfFalsePop,
LongJumpForwards, LongJumpBackwards:
jump = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[
offset + 3]].fromTriple().int()
else:
discard # Unreachable
printInstruction(instruction, true)
printDebug("Jump size: ")
stdout.styledWrite(fgYellow, $jump)
nl()
return offset + 3
proc disassembleInstruction*(chunk: Chunk, offset: int): int =
## Takes one bytecode instruction and prints it
printDebug("Offset: ")
stdout.styledWriteLine(fgYellow, $offset)
printDebug("Line: ")
stdout.styledWriteLine(fgYellow, &"{chunk.getLine(offset)}")
var opcode = OpCode(chunk.code[offset])
case opcode:
of simpleInstructions:
result = simpleInstruction(opcode, offset)
of constantInstructions:
result = constantInstruction(opcode, chunk, offset)
of stackDoubleInstructions:
result = stackDoubleInstruction(opcode, chunk, offset)
of stackTripleInstructions:
result = stackTripleInstruction(opcode, chunk, offset)
of argumentDoubleInstructions:
result = argumentDoubleInstruction(opcode, chunk, offset)
of argumentTripleInstructions:
result = argumentTripleInstruction(opcode, chunk, offset)
of callInstructions:
result = callInstruction(opcode, chunk, offset)
of jumpInstructions:
result = jumpInstruction(opcode, chunk, offset)
else:
echo &"DEBUG - Unknown opcode {opcode} at index {offset}"
result = offset + 1
proc disassembleChunk*(chunk: Chunk, name: string) =
## Takes a chunk of bytecode, and prints it
2022-04-21 15:58:33 +02:00
echo &"==== Peon Bytecode Debugger - Chunk '{name}' ====\n"
var index = 0
while index < chunk.code.len:
index = disassembleInstruction(chunk, index)
echo ""
echo &"==== Debug session ended - Chunk '{name}' ===="