import strformat import strutils import value type OpCode* = enum opReturn, opCall, # functions opPop, # pop opPrint, # print opNegate, opNot # unary opAdd, opSubtract, opMultiply, opDivide, # math opEqual, opGreater, opLess, # comparison opTrue, opFalse, opNil, # literal opConstant, # constant opDefineGlobal, opGetGlobal, opSetGlobal, # globals (uses constants) opGetLocal, opSetLocal, # locals opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, # jumps Chunk* = object code*: seq[uint8] constants*: seq[KonValue] lines*: seq[int] name*: string # name of the module/chunk/files DoubleUint8* = array[2, uint8] const argSize* = 2 const argMax*: int = 256*256 proc initChunk*(name: string): Chunk = Chunk(code: @[], name: name, lines: @[], constants: @[]) proc writeChunk*(ch: var Chunk, code: uint8, line: int) = ch.code.add(code) ch.lines.add(line) proc writeChunk*(ch: var Chunk, code: OpCode, line: int) = ch.code.add(code.uint8) ch.lines.add(line) proc writeChunk*(ch: var Chunk, code: DoubleUint8, line: int) = for c in code: ch.code.add(c) ch.lines.add(line) proc len*(ch: Chunk): int = ch.code.len proc toDU8*(integ: int): DoubleUint8 = cast[ptr array[2, uint8]](integ.unsafeAddr)[] proc toInt*(du8: DoubleUint8): int = cast[uint16](du8).int proc DU8ptrToInt*(du8: ptr uint8): int = cast[ptr uint16](du8)[].int proc addConstant*(ch: var Chunk, constant: KonValue): int = ch.constants.add(constant) ch.constants.high proc writeConstant*(ch: var Chunk, constant: KonValue, line: int): int = result = ch.addConstant(constant) ch.writeChunk(opConstant, line) ch.writeChunk(result.toDU8, line) const simpleInstructions = { opReturn, opPop, opPrint, opNegate, opNot, opAdd, opSubtract, opMultiply, opDivide, opEqual, opGreater, opLess, opTrue, opFalse, opNil } const constantInstructions = { opConstant, opDefineGlobal, opGetGlobal, opSetGlobal, } const argInstructions = { opCall, opGetLocal, opSetLocal, opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, } proc disassembleChunk*(ch: Chunk) = echo &"== Chunk {ch.name} begin ==" echo "index line instruction" var c: int = 0 var lastLine = -1 while c < ch.code.len: template instruction: uint8 = ch.code[c] template line: int = ch.lines[c] template double: DoubleUint8 = [ch.code[c+1], ch.code[c+2]] let cFmt = &"{c:04}" let lineFmt = if lastLine == line: " | " else: &"{line:04}" try: write stdout, &"[{cFmt}] {lineFmt} {instruction.OpCode} ({instruction.toHex(2)}" case instruction.OpCode: of simpleInstructions: write stdout, ")\n" of argInstructions: write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n" c += 2 of constantInstructions: let i = double.toInt write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n" echo &" points to constant {ch.constants[i]} (i: {i})" c += 2 except: echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}" c.inc echo &"== Chunk {ch.name} end =="