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 Triple* = array[3, uint8] 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: Triple, line: int) = for c in code: ch.code.add(c) ch.lines.add(line) proc len*(ch: Chunk): int = ch.code.len proc toTriple*(integer: int): Triple = var integer = integer result[0] = integer.uint8 integer = integer div 256 result[1] = integer.uint8 integer = integer div 256 result[2] = integer.uint8 proc toInt*(triple: Triple): int = triple[0].int + triple[1].int * 256 + triple[2].int * 256 * 256 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.toTriple, 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, } const tripleMax*: int = 16777215 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 triple: Triple = [ch.code[c+1], ch.code[c+2], ch.code[c+3]] 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, &" {triple[0].toHex(2)} {triple[1].toHex(2)} {triple[2].toHex(2)})\n" c += 3 of constantInstructions: let i = triple.toInt write stdout, &" {triple[0].toHex(2)} {triple[1].toHex(2)} {triple[2].toHex(2)})\n" echo &" points to constant {ch.constants[i]} (i: {i})" c += 3 except: echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}" c.inc echo &"== Chunk {ch.name} end =="