mirror of https://github.com/japl-lang/japl.git
Minor improvements to debugger experience
This commit is contained in:
parent
4a1fc8df6d
commit
21ab45ecc4
|
@ -51,3 +51,7 @@ type
|
|||
|
||||
proc initParser*(tokens: seq[Token]): Parser =
|
||||
result = Parser(current: 0, tokens: tokens, hadError: false, panicMode: false)
|
||||
|
||||
|
||||
const FRAMES_MAX* = 256
|
||||
const STACK_MAX* = FRAMES_MAX * int uint8.high
|
||||
|
|
|
@ -716,6 +716,7 @@ proc compile*(self: var Compiler, source: string): ptr Function =
|
|||
else:
|
||||
return nil
|
||||
|
||||
|
||||
proc initCompiler*(vm: var VM, context: FunctionType): Compiler =
|
||||
result = Compiler(parser: initParser(@[]), function: nil, locals: @[], scopeDepth: 0, localCount: 0, loop: Loop(alive: false, loopEnd: -1), vm: vm, context: context)
|
||||
result.locals.add(Local(depth: 0, name: Token(kind: EOF, lexeme: "")))
|
||||
|
|
19
nim/main.nim
19
nim/main.nim
|
@ -2,13 +2,17 @@ import vm
|
|||
import strformat
|
||||
import parseopt
|
||||
import os
|
||||
import common
|
||||
|
||||
|
||||
proc repl(debug: bool = false) =
|
||||
var bytecodeVM = initVM()
|
||||
echo &"[JAPL 0.2.0 - Nim {NimVersion} - {CompileDate} {CompileTime}]"
|
||||
echo &"[JAPL 0.2.0 - on Nim {NimVersion} - {CompileDate} {CompileTime}]"
|
||||
if debug:
|
||||
echo "Debug mode is enabled, bytecode will be disassembled"
|
||||
echo "Debugger enabled, expect verbose output\n"
|
||||
echo "==== VM Constants ====\n"
|
||||
echo &"- FRAMES_MAX -> {FRAMES_MAX}\n- STACK_MAX -> {STACK_MAX}\n"
|
||||
echo "==== Code starts ====\n"
|
||||
var source: string = ""
|
||||
while true:
|
||||
try:
|
||||
|
@ -16,11 +20,11 @@ proc repl(debug: bool = false) =
|
|||
source = readLine(stdin)
|
||||
except IOError:
|
||||
echo ""
|
||||
bytecodeVM.freeVM()
|
||||
bytecodeVM.freeVM(debug)
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
echo ""
|
||||
bytecodeVM.freeVM()
|
||||
bytecodeVM.freeVM(debug)
|
||||
break
|
||||
if source == "":
|
||||
continue
|
||||
|
@ -47,11 +51,14 @@ proc main(file: string = "", debug: bool = false) =
|
|||
echo &"Error: '{file}' could not be read, probably you don't have the permission to read it"
|
||||
var bytecodeVM = initVM()
|
||||
if debug:
|
||||
echo "Debug mode is enabled, bytecode will be disassembled"
|
||||
echo "Debugger enabled, expect verbose output\n"
|
||||
echo "==== VM Constants ====\n"
|
||||
echo &"- FRAMES_MAX -> {FRAMES_MAX}\n- STACK_MAX -> {STACK_MAX}\n"
|
||||
echo "==== Code starts ====\n"
|
||||
var result = bytecodeVM.interpret(source, debug)
|
||||
if debug:
|
||||
echo &"Result: {result}"
|
||||
bytecodeVM.freeVM()
|
||||
bytecodeVM.freeVM(debug)
|
||||
|
||||
|
||||
when isMainModule:
|
||||
|
|
|
@ -5,13 +5,13 @@ import strformat
|
|||
|
||||
|
||||
proc simpleInstruction(name: string, index: int): int =
|
||||
echo &"\tOpCode at offset: {name}\n"
|
||||
echo &"\tInstruction at IP: {name}\n"
|
||||
return index + 1
|
||||
|
||||
|
||||
proc byteInstruction(name: string, chunk: Chunk, offset: int): int =
|
||||
var slot = chunk.code[offset + 1]
|
||||
echo &"\tOpCode at offset: {name}, points to slot {slot}\n"
|
||||
echo &"\tInstruction at IP: {name}, points to slot {slot}\n"
|
||||
return offset + 1
|
||||
|
||||
|
||||
|
@ -20,28 +20,29 @@ proc constantLongInstruction(name: string, chunk: Chunk, offset: int): int =
|
|||
var constantArray: array[3, uint8] = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[offset + 3]]
|
||||
var constant: int
|
||||
copyMem(constant.addr, unsafeAddr(constantArray), sizeof(constantArray))
|
||||
echo &"\tOpCode at offset: {name}, points to {constant}"
|
||||
echo &"\tInstruction at IP: {name}, points to slot {constant}"
|
||||
let obj = chunk.consts.values[constant]
|
||||
echo &"\tValue: {stringify(obj)}\n\tKind: {obj.kind}\n"
|
||||
echo &"\tOperand: {stringify(obj)}\n\tValue kind: {obj.kind}\n"
|
||||
return offset + 4
|
||||
|
||||
|
||||
proc constantInstruction(name: string, chunk: Chunk, offset: int): int =
|
||||
var constant = chunk.code[offset + 1]
|
||||
echo &"\tOpCode at offset: {name}, points to index {constant}"
|
||||
echo &"\tInstruction at IP: {name}, points to index {constant}"
|
||||
let obj = chunk.consts.values[constant]
|
||||
echo &"\tValue: {stringify(obj)}\n\tKind: {obj.kind}\n"
|
||||
echo &"\tOperand: {stringify(obj)}\n\tValue kind: {obj.kind}\n"
|
||||
return offset + 2
|
||||
|
||||
|
||||
proc jumpInstruction(name: string, chunk: Chunk, offset: int): int =
|
||||
var jump = uint16 (chunk.code[offset + 1] shr 8)
|
||||
jump = jump or chunk.code[offset + 2]
|
||||
echo &"\tOpCode at offset: {name}\n\tJump size: {jump}\n"
|
||||
echo &"\tInstruction at IP: {name}\n\tJump offset: {jump}\n"
|
||||
return offset + 3
|
||||
|
||||
|
||||
proc disassembleInstruction*(chunk: Chunk, offset: int): int =
|
||||
echo &"Current offset: {offset}\nCurrent line: {chunk.lines[offset]}"
|
||||
echo &"Current IP position: {offset}\nCurrent line: {chunk.lines[offset]}"
|
||||
var opcode = OpCode(chunk.code[offset])
|
||||
if opcode == OP_RETURN:
|
||||
result = simpleInstruction("OP_RETURN", offset)
|
||||
|
|
21
nim/vm.nim
21
nim/vm.nim
|
@ -382,33 +382,42 @@ proc run(self: var VM, debug, repl: bool): InterpretResult =
|
|||
return OK
|
||||
|
||||
|
||||
proc freeObject(obj: ptr Obj) =
|
||||
proc freeObject(obj: ptr Obj, debug: bool) =
|
||||
case obj.kind:
|
||||
of ObjectTypes.STRING:
|
||||
var str = cast[ptr String](obj)
|
||||
if debug:
|
||||
echo &"Freeing string object with value '{stringify(str[])}' of length {str.len}"
|
||||
discard freeArray(char, str.str, str.len)
|
||||
discard free(ObjectTypes.STRING, obj)
|
||||
of ObjectTypes.FUNCTION:
|
||||
var fun = cast[ptr Function](obj)
|
||||
echo "Freeing function object with value '{stringify(fun[])}'"
|
||||
fun.chunk.freeChunk()
|
||||
discard free(ObjectTypes.FUNCTION, fun)
|
||||
else:
|
||||
discard
|
||||
|
||||
|
||||
proc freeObjects(self: var VM) =
|
||||
proc freeObjects(self: var VM, debug: bool) =
|
||||
var obj = self.objects
|
||||
var next: ptr Obj
|
||||
var i = 0
|
||||
while obj != nil:
|
||||
next = obj[].next
|
||||
freeObject(obj)
|
||||
freeObject(obj, debug)
|
||||
i += 1
|
||||
obj = next
|
||||
if debug:
|
||||
echo &"Freed {i} objects"
|
||||
|
||||
|
||||
proc freeVM*(self: var VM) =
|
||||
proc freeVM*(self: var VM, debug: bool) =
|
||||
if debug:
|
||||
echo "\nFreeing all allocated memory before exiting"
|
||||
unsetControlCHook()
|
||||
try:
|
||||
self.freeObjects()
|
||||
self.freeObjects(debug)
|
||||
except NilAccessError:
|
||||
echo "MemoryError: could not manage memory, exiting"
|
||||
quit(71)
|
||||
|
@ -427,8 +436,6 @@ proc interpret*(self: var VM, source: string, debug: bool = false, repl: bool =
|
|||
except KeyboardInterrupt:
|
||||
self.error(newInterruptedError(""))
|
||||
return RUNTIME_ERROR
|
||||
self.chunk.freeChunk()
|
||||
self.freeVM()
|
||||
|
||||
|
||||
proc resetStack*(self: var VM) =
|
||||
|
|
Loading…
Reference in New Issue