WIP closures: unclosed upvalues work; improved vm debugging and changed $ for functions, closures

This commit is contained in:
prod2 2022-02-06 04:59:39 +01:00
parent f453de631d
commit 392955e290
4 changed files with 81 additions and 46 deletions

View File

@ -118,6 +118,43 @@ const argInstructions = {
opGetUpvalue, opSetUpvalue,
}
proc disassembleInstruction*(ch: Chunk, c: var int, lastLine: var int) =
template instruction: uint8 = ch.code[c]
template line: int = ch.lines[c]
template double: DoubleUint8 = [ch.code[c+1], ch.code[c+2]]
template shortArg: uint8 = ch.code[c+1]
let cFmt = &"{c:04}"
let lineFmt = if lastLine == line: " | " else: &"{line:04}"
lastLine = line
try:
write stdout, &"[{cFmt}] {lineFmt} {instruction.OpCode} ({instruction.toHex(2)}"
case instruction.OpCode:
of simpleInstructions:
write stdout, ")\n"
of shortArgInstructions:
write stdout, &" {shortArg.toHex(2)})\n"
c += 1
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
of opClosure:
let upvalCount = double.toInt
c += 2
write stdout, &" length: {upvalCount} [ "
for i in countup(1, upvalCount):
let index = double.toInt
c += 2
let local = shortArg.int
c += 1
write stdout, &"(i: {index} l: {local}) "
write stdout, &"])\n"
except:
echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}"
proc disassembleChunk*(ch: Chunk) =
echo &"== Chunk {ch.name} begin =="
@ -125,42 +162,7 @@ proc disassembleChunk*(ch: Chunk) =
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]]
template shortArg: uint8 = ch.code[c+1]
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 shortArgInstructions:
write stdout, &" {shortArg.toHex(2)})\n"
c += 1
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
of opClosure:
let upvalCount = double.toInt
c += 2
write stdout, &" length: {upvalCount} [ "
for i in countup(1, upvalCount):
let index = double.toInt
c += 2
let local = shortArg.int
c += 1
write stdout, &"(i: {index} l: {local}) "
write stdout, &"])\n"
except:
echo &"[{cFmt}] {lineFmt} Unknown opcode {instruction}"
disassembleInstruction(ch, c, lastLine)
c.inc
echo &"== Chunk {ch.name} end =="

View File

@ -17,4 +17,20 @@ proc newClosure*[T](start: ptr uint8, upvalueCount: int): Closure[T] =
result.upvalueCount = upvalueCount
proc getIp*[T](clos: Closure[T]): ptr uint8 {.inline.} =
clos.start
clos.start
proc set*[T](clos: Closure[T], index: int, val: Upvalue[T]) =
clos.upvalues[index] = val
proc get*[T](clos: Closure[T], index: int): Upvalue[T] =
clos.upvalues[index]
proc captureUpvalue*[T](location: ptr T): Upvalue[T] =
result = cast[Upvalue[T]](alloc0(sizeof(UpvalueObj[T])))
result.location = location
proc read*[T](upval: Upvalue[T]): T =
upval.location[]
proc write*[T](upval: Upvalue[T], val: T) =
upval.location[]= val

View File

@ -1,4 +1,5 @@
import strformat
import strutils
import bitops
import ndstring
@ -155,7 +156,9 @@ proc `$`*(val: NdValue): string =
elif val.isFloat():
return $val.asFloat()
elif val.isFunct():
return &"Function object {cast[uint](val.asFunct())}"
return &"Function object {(val).uint.toHex()}"
elif val.isClosure():
return &"Closure object {(val).uint.toHex()}"
elif val.isString():
return $val.asString()
elif val.isTable():

View File

@ -27,6 +27,7 @@ type
Frame = object
stackBottom: int # the absolute index of where 0 inside the frame is
returnIp: ptr uint8
closure: Closure[NdValue]
InterpretResult* = enum
irOK, irRuntimeError
@ -72,7 +73,7 @@ proc run*(chunk: Chunk): InterpretResult =
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip))
ip = funct.asFunct() # jump to the entry point
elif funct.isClosure():
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip))
frames.add(Frame(stackBottom: stack.high - argcount, returnIp: ip, closure: funct.asClosure()))
ip = funct.asClosure().getIp()
else:
error
@ -84,9 +85,10 @@ proc run*(chunk: Chunk): InterpretResult =
ip = ip.padd(1)
when debugVM:
let ii = ip.pdiff(chunk.code[0].unsafeAddr) - 1
let opname = ($ins)
var msg = &"[{ii:04}] {opname}"
var ii = ip.pdiff(chunk.code[0].unsafeAddr) - 1
var ll = -1
disassembleInstruction(chunk, ii, ll)
var msg = ""
msg &= " Stack: [ "
for i in 0 .. stack.high():
let e = stack[i]
@ -199,9 +201,11 @@ proc run*(chunk: Chunk): InterpretResult =
let slot = ip.readDU8()
stack[slot + frameBottom] = stack.peek()
of opGetUpvalue:
discard
let slot = ip.readDU8()
stack.push(frames.peek().closure.get(slot).read())
of opSetUpvalue:
discard
let slot = ip.readDU8()
frames.peek().closure.get(slot).write(stack.peek())
of opJumpIfFalse:
let offset = ip.readDU8()
if stack.peek().isFalsey():
@ -222,8 +226,18 @@ proc run*(chunk: Chunk): InterpretResult =
ip = ip.padd(offset)
stack.push(faddr.fromFunct())
of opClosure:
runtimeError("Closures are not implemented.")
break
let upvalCount = ip.readDU8()
let funct = stack.peek()
let closure = newClosure[NdValue](funct.asFunct(), upvalCount)
stack.settip(closure.fromClosure())
for i in countup(0, upvalCount - 1):
let slot = ip.readDU8()
let isLocal = ip.readUI8() == 0
if isLocal:
closure.set(i, stack[slot + frameBottom].addr.captureUpvalue())
else:
closure.set(i, frames.peek().closure.get(slot))
of opCheckArity:
let arity = ip.readUI8()
let argcount = stack.high() - frameBottom