nondescript/src/ndspkg/chunk.nim

155 lines
4.5 KiB
Nim
Raw Normal View History

2022-01-20 21:54:11 +01:00
import strformat
import strutils
import types/value
2022-01-20 21:54:11 +01:00
type
OpCode* = enum
2022-01-29 20:43:13 +01:00
opReturn, opCall, opCheckArity, opFunctionDef, # functions
2022-02-05 12:30:07 +01:00
opClosure, # closures
2022-01-27 03:32:42 +01:00
opPop, opPopSA, opPopA # pop
2022-01-20 21:54:11 +01:00
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
2022-02-05 12:37:54 +01:00
opGetUpvalue, opSetUpvalue, # upvalues
2022-01-20 21:54:11 +01:00
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop, # jumps
2022-02-03 03:18:11 +01:00
opCreateList, opCreateTable, # collection creation
opLen, opSetIndex, opGetIndex, # collection operators
2022-02-05 02:45:29 +01:00
opPrint, opChr, opInt, opPutchar, # temporary opcodes for the brainfuck interpreter TODO move to native funcs
2022-01-20 21:54:11 +01:00
Chunk* = object
code*: seq[uint8]
2022-01-27 05:37:10 +01:00
constants*: seq[NdValue]
2022-01-20 21:54:11 +01:00
lines*: seq[int]
2022-01-21 00:18:58 +01:00
name*: string # name of the module/chunk/files
2022-01-20 21:54:11 +01:00
DoubleUint8* = array[2, uint8]
2022-01-27 03:32:42 +01:00
# WARNING! short args can safely assumed to be 1 byte long outside of chunk.nim
const shortArgSize* = 1
2022-01-27 04:41:32 +01:00
const shortArgMax* = 256 - 1
2022-01-27 03:32:42 +01:00
# modules outside chunk.nim should not assume any length of argSize, however code inside chunk.nim can make such assumptions
const argSize* = 2
2022-01-27 04:41:32 +01:00
const argMax*: int = 256*256 - 1
2022-01-20 21:54:11 +01:00
2022-01-21 00:18:58 +01:00
proc initChunk*(name: string): Chunk =
Chunk(code: @[], name: name, lines: @[], constants: @[])
2022-01-20 21:54:11 +01:00
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) =
2022-01-20 21:54:11 +01:00
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)[]
2022-01-20 21:54:11 +01:00
proc toInt*(du8: DoubleUint8): int =
cast[uint16](du8).int
2022-01-20 21:54:11 +01:00
proc DU8ptrToInt*(du8: ptr uint8): int =
cast[ptr uint16](du8)[].int
proc findConstant(ch: var Chunk, constant: NdValue): int =
2022-02-05 06:10:37 +01:00
# TODO, if there are a lot of constants that are different, this could be possibly slow, so either use a table lookup or only check for the last x constants
if ch.constants.len() == 0:
return -1
for i in countup(0, ch.constants.high()):
let current = ch.constants[i]
if current == constant:
return i
return -1
2022-01-27 05:37:10 +01:00
proc addConstant*(ch: var Chunk, constant: NdValue): int =
let found = ch.findConstant(constant)
if found == -1:
ch.constants.add(constant)
ch.constants.high
else:
found
2022-01-20 21:54:11 +01:00
2022-01-27 05:37:10 +01:00
proc writeConstant*(ch: var Chunk, constant: NdValue, line: int): int =
2022-01-20 21:54:11 +01:00
result = ch.addConstant(constant)
ch.writeChunk(opConstant, line)
ch.writeChunk(result.toDU8, line)
2022-01-20 21:54:11 +01:00
const simpleInstructions = {
2022-01-21 01:51:55 +01:00
opReturn,
2022-01-20 21:54:11 +01:00
opPop,
opPrint,
opNegate, opNot,
opAdd, opSubtract, opMultiply, opDivide,
opEqual, opGreater, opLess,
2022-02-03 03:18:11 +01:00
opTrue, opFalse, opNil,
opLen, opSetIndex, opGetIndex,
2022-02-05 02:45:29 +01:00
opChr, opInt, opPutchar,
2022-01-20 21:54:11 +01:00
}
const constantInstructions = {
opConstant,
opDefineGlobal, opGetGlobal, opSetGlobal,
}
2022-01-27 03:32:42 +01:00
const shortArgInstructions = {
opPopSA,
2022-01-27 04:41:32 +01:00
opCall,
2022-01-27 05:56:09 +01:00
opCheckArity,
2022-01-27 03:32:42 +01:00
}
2022-01-20 21:54:11 +01:00
const argInstructions = {
2022-01-27 03:32:42 +01:00
opPopA,
2022-01-20 21:54:11 +01:00
opGetLocal, opSetLocal,
opJumpIfFalse, opJump, opLoop, opJumpIfFalsePop,
2022-02-05 12:30:07 +01:00
opFunctionDef, opClosure,
2022-02-03 03:18:11 +01:00
opCreateList, opCreateTable,
2022-02-05 12:37:54 +01:00
opGetUpvalue, opSetUpvalue,
2022-01-20 21:54:11 +01:00
}
proc disassembleChunk*(ch: Chunk) =
2022-01-21 00:18:58 +01:00
echo &"== Chunk {ch.name} begin =="
2022-01-20 21:54:11 +01:00
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]]
2022-01-27 03:32:42 +01:00
template shortArg: uint8 = ch.code[c+1]
2022-01-20 21:54:11 +01:00
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"
2022-01-27 03:32:42 +01:00
of shortArgInstructions:
write stdout, &" {shortArg.toHex(2)}"
c += 1
2022-01-20 21:54:11 +01:00
of argInstructions:
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
c += 2
2022-01-20 21:54:11 +01:00
of constantInstructions:
let i = double.toInt
write stdout, &" {double[0].toHex(2)} {double[1].toHex(2)})\n"
2022-01-20 21:54:11 +01:00
echo &" points to constant {ch.constants[i]} (i: {i})"
c += 2
2022-01-20 21:54:11 +01:00
except:
echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}"
c.inc
2022-01-21 00:18:58 +01:00
echo &"== Chunk {ch.name} end =="
2022-01-20 21:54:11 +01:00