Got rid of serializedRaw in main module and prettyfied the output
This commit is contained in:
parent
5b9206a580
commit
e4c2ba2ce2
79
src/main.nim
79
src/main.nim
|
@ -2,6 +2,8 @@
|
|||
import sequtils
|
||||
import strformat
|
||||
import strutils
|
||||
import terminal
|
||||
# Thanks art <3
|
||||
import jale/editor as ed
|
||||
import jale/templates
|
||||
import jale/plugin/defaults
|
||||
|
@ -45,7 +47,6 @@ when isMainModule:
|
|||
tree: seq[Declaration] = @[]
|
||||
compiled: Chunk
|
||||
serialized: Serialized
|
||||
serializedRaw: seq[byte]
|
||||
tokenizer = newLexer()
|
||||
parser = newParser()
|
||||
compiler = newCompiler()
|
||||
|
@ -55,6 +56,8 @@ when isMainModule:
|
|||
input: string
|
||||
tokenizer.fillSymbolTable()
|
||||
editor.bindEvent(jeQuit):
|
||||
stdout.styledWriteLine(fgGreen, "Goodbye!")
|
||||
editor.prompt = ""
|
||||
keep = false
|
||||
editor.bindKey("ctrl+a"):
|
||||
editor.content.home()
|
||||
|
@ -66,90 +69,84 @@ when isMainModule:
|
|||
if input.len() == 0:
|
||||
continue
|
||||
# Currently the parser doesn't handle these tokens well
|
||||
tokens = filter(tokenizer.lex(input, "stdin"), proc (
|
||||
x: Token): bool = x.kind notin {TokenType.Whitespace, Tab})
|
||||
tokens = tokenizer.lex(input, "stdin")
|
||||
if tokens.len() == 0:
|
||||
continue
|
||||
when debugLexer:
|
||||
echo "Tokenization step:"
|
||||
styledEcho fgCyan, "Tokenization step:"
|
||||
for i, token in tokens:
|
||||
if i == tokens.high():
|
||||
# Who cares about EOF?
|
||||
break
|
||||
echo "\t", token
|
||||
styledEcho fgGreen, "\t", $token
|
||||
echo ""
|
||||
tree = parser.parse(tokens, "stdin")
|
||||
if tree.len() == 0:
|
||||
continue
|
||||
when debugParser:
|
||||
echo "Parsing step:"
|
||||
styledEcho fgCyan, "Parsing step:"
|
||||
for node in tree:
|
||||
echo "\t", node
|
||||
styledEcho fgGreen, "\t", $node
|
||||
echo ""
|
||||
compiled = compiler.compile(tree, "stdin")
|
||||
when debugCompiler:
|
||||
echo "Compilation step:"
|
||||
stdout.write("\t")
|
||||
echo &"""Raw byte stream: [{compiled.code.join(", ")}]"""
|
||||
echo "\nBytecode disassembler output below:\n"
|
||||
styledEcho fgCyan, "Compilation step:"
|
||||
stdout.styledWrite(fgCyan, "\tRaw byte stream: ", fgGreen, "[", fgYellow, compiled.code.join(", "), fgGreen, "]")
|
||||
styledEcho fgCyan, "\n\nBytecode disassembler output below:\n"
|
||||
disassembleChunk(compiled, "stdin")
|
||||
echo ""
|
||||
|
||||
serializer.dumpToFile(compiled, input, "stdin", "stdin.pbc")
|
||||
serializedRaw = serializer.dumpBytes(compiled, input, "stdin")
|
||||
serializer.dumpFile(compiled, input, "stdin", "stdin.pbc")
|
||||
serialized = serializer.loadFile("stdin.pbc")
|
||||
when debugSerializer:
|
||||
echo "Serialization step: "
|
||||
stdout.write("\t")
|
||||
echo &"""Raw hex output: {serializedRaw.mapIt(toHex(it)).join("").toLowerAscii()}"""
|
||||
echo ""
|
||||
|
||||
echo &"\t- File hash: {serialized.fileHash} (matches: {computeSHA256(input).toHex().toLowerAscii() == serialized.fileHash})"
|
||||
echo &"\t- Peon version: {serialized.peonVer.major}.{serialized.peonVer.minor}.{serialized.peonVer.patch} (commit {serialized.commitHash[0..8]} on branch {serialized.peonBranch})"
|
||||
stdout.write("\t")
|
||||
echo &"""- Compilation date & time: {fromUnix(serialized.compileDate).format("d/M/yyyy HH:mm:ss")}"""
|
||||
stdout.write(&"\t- Reconstructed constants table: [")
|
||||
for i, e in serialized.chunk.consts:
|
||||
stdout.write(e)
|
||||
if i < len(serialized.chunk.consts) - 1:
|
||||
stdout.write(", ")
|
||||
stdout.write(&"] (matches: {serialized.chunk.consts == compiled.consts})\n")
|
||||
stdout.write(&"\t- Reconstructed bytecode: [")
|
||||
for i, e in serialized.chunk.code:
|
||||
stdout.write($e)
|
||||
if i < len(serialized.chunk.code) - 1:
|
||||
stdout.write(", ")
|
||||
stdout.write(&"] (matches: {serialized.chunk.code == compiled.code})\n")
|
||||
var hashMatches = computeSHA256(input).toHex().toLowerAscii() == serialized.fileHash
|
||||
styledEcho fgCyan, "Serialization step: "
|
||||
styledEcho fgBlue, &"\t- File hash: ", fgYellow, serialized.fileHash, fgBlue, " (", if hashMatches: fgGreen else: fgRed, if hashMatches: "OK" else: "Fail", fgBlue, ")"
|
||||
styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.peonVer.major}.{serialized.peonVer.minor}.{serialized.peonVer.patch}", fgBlue, " (commit ", fgYellow, serialized.commitHash[0..8], fgBlue, ") on branch ", fgYellow, serialized.peonBranch
|
||||
stdout.styledWriteLine(fgBlue, "\t- Compilation date & time: ", fgYellow, fromUnix(serialized.compileDate).format("d/M/yyyy HH:mm:ss"))
|
||||
stdout.styledWrite(fgBlue, &"\t- Constants segment: ")
|
||||
if serialized.chunk.consts == compiled.consts:
|
||||
styledEcho fgGreen, "OK"
|
||||
else:
|
||||
styledEcho fgRed, "Corrupted"
|
||||
stdout.styledWrite(fgBlue, &"\t- Code segment: ")
|
||||
if serialized.chunk.code == compiled.code:
|
||||
styledEcho fgGreen, "OK"
|
||||
else:
|
||||
styledEcho fgRed, "Corrupted"
|
||||
stdout.styledWrite(fgBlue, "\t- Line info segment: ")
|
||||
if serialized.chunk.lines == compiled.lines:
|
||||
styledEcho fgGreen, "OK"
|
||||
else:
|
||||
styledEcho fgRed, "Corrupted"
|
||||
when debugRuntime:
|
||||
echo "Execution step: "
|
||||
styledEcho fgCyan, "\n\nExecution step: "
|
||||
vm.run(serialized.chunk)
|
||||
except IOError:
|
||||
break
|
||||
# TODO: The code for error reporting completely
|
||||
# breaks down with multiline input, fix it
|
||||
except LexingError:
|
||||
# let lineNo = tokenizer.getLine()
|
||||
# let relPos = tokenizer.getRelPos(lineNo)
|
||||
# let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
echo getCurrentExceptionMsg()
|
||||
stderr.styledWriteLine(fgRed, getCurrentExceptionMsg())
|
||||
# echo &"Source line: {line}"
|
||||
# echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - relPos.start)
|
||||
except ParseError:
|
||||
# let lineNo = parser.getCurrentToken().line
|
||||
# let relPos = tokenizer.getRelPos(lineNo)
|
||||
# let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
echo getCurrentExceptionMsg()
|
||||
stderr.styledWriteLine(fgRed, getCurrentExceptionMsg())
|
||||
# echo &"Source line: {line}"
|
||||
# echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - parser.getCurrentToken().lexeme.len())
|
||||
except CompileError:
|
||||
# let lineNo = compiler.getCurrentNode().token.line
|
||||
# let relPos = tokenizer.getRelPos(lineNo)
|
||||
# let line = tokenizer.getSource().splitLines()[lineNo - 1].strip()
|
||||
echo getCurrentExceptionMsg()
|
||||
stderr.styledWriteLine(fgRed, getCurrentExceptionMsg())
|
||||
# echo &"Source line: {line}"
|
||||
# echo " ".repeat(relPos.start + len("Source line: ")) & "^".repeat(relPos.stop - compiler.getCurrentNode().token.lexeme.len())
|
||||
except SerializationError:
|
||||
echo getCurrentExceptionMsg()
|
||||
stderr.styledWriteLine(fgRed, getCurrentExceptionMsg())
|
||||
quit(0)
|
||||
|
||||
|
||||
|
|
|
@ -25,15 +25,14 @@ proc nl = stdout.write("\n")
|
|||
|
||||
|
||||
proc printDebug(s: string, newline: bool = false) =
|
||||
stdout.write(&"DEBUG - Disassembler -> {s}")
|
||||
stdout.styledWrite(fgMagenta, "DEBUG - Disassembler -> ")
|
||||
stdout.styledWrite(fgGreen, s)
|
||||
if newline:
|
||||
nl()
|
||||
|
||||
|
||||
proc printName(name: string, newline: bool = false) =
|
||||
setForegroundColor(fgRed)
|
||||
stdout.write(name)
|
||||
setForegroundColor(fgGreen)
|
||||
stdout.styledWrite(fgRed, name)
|
||||
if newline:
|
||||
nl()
|
||||
|
||||
|
@ -57,9 +56,8 @@ proc stackTripleInstruction(instruction: OpCode, chunk: Chunk,
|
|||
var slot = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[
|
||||
offset + 3]].fromTriple()
|
||||
printInstruction(instruction)
|
||||
stdout.write(&", points to index ")
|
||||
setForegroundColor(fgYellow)
|
||||
stdout.write(&"{slot}")
|
||||
stdout.styledWrite(fgGreen, &", points to index ")
|
||||
stdout.styledWrite(fgYellow, &"{slot}")
|
||||
nl()
|
||||
return offset + 4
|
||||
|
||||
|
@ -70,14 +68,13 @@ proc stackDoubleInstruction(instruction: OpCode, chunk: Chunk,
|
|||
var slot = [chunk.code[offset + 1], chunk.code[offset + 2]].fromDouble()
|
||||
printInstruction(instruction)
|
||||
stdout.write(&", points to index ")
|
||||
setForegroundColor(fgYellow)
|
||||
stdout.write(&"{slot}")
|
||||
stdout.styledWrite(fgGreen, &", points to index ")
|
||||
stdout.styledWrite(fgYellow, &"{slot}")
|
||||
nl()
|
||||
return offset + 3
|
||||
|
||||
|
||||
proc argumentDoubleInstruction(instruction: OpCode, chunk: Chunk,
|
||||
offset: int): int =
|
||||
proc argumentDoubleInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
|
||||
## Debugs instructions that operate on a hardcoded value on the stack using a 16-bit operand
|
||||
var slot = [chunk.code[offset + 1], chunk.code[offset + 2]].fromDouble()
|
||||
printInstruction(instruction)
|
||||
|
@ -93,16 +90,13 @@ proc constantInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
|
|||
var constant = [chunk.code[offset + 1], chunk.code[offset + 2], chunk.code[
|
||||
offset + 3]].fromTriple()
|
||||
printInstruction(instruction)
|
||||
stdout.write(&", points to constant at position ")
|
||||
stdout.styledWrite(fgGreen, &", points to constant at position ")
|
||||
setForegroundColor(fgYellow)
|
||||
stdout.write(&"{constant}")
|
||||
nl()
|
||||
let obj = chunk.consts[constant]
|
||||
setForegroundColor(fgGreen)
|
||||
printDebug("Operand: ")
|
||||
setForegroundColor(fgYellow)
|
||||
stdout.write(&"{obj}\n")
|
||||
setForegroundColor(fgGreen)
|
||||
stdout.styledWrite(fgYellow, &"{obj}\n")
|
||||
return offset + 4
|
||||
|
||||
|
||||
|
@ -120,23 +114,18 @@ proc jumpInstruction(instruction: OpCode, chunk: Chunk, offset: int): int =
|
|||
discard # Unreachable
|
||||
printInstruction(instruction, true)
|
||||
printDebug("Jump size: ")
|
||||
setForegroundColor(fgYellow)
|
||||
stdout.write($jump)
|
||||
stdout.styledWrite(fgYellow, $jump)
|
||||
nl()
|
||||
return offset + 3
|
||||
|
||||
|
||||
proc disassembleInstruction*(chunk: Chunk, offset: int): int =
|
||||
## Takes one bytecode instruction and prints it
|
||||
setForegroundColor(fgGreen)
|
||||
printDebug("Offset: ")
|
||||
setForegroundColor(fgYellow)
|
||||
echo offset
|
||||
setForegroundColor(fgGreen)
|
||||
stdout.styledWriteLine(fgYellow, $offset)
|
||||
printDebug("Line: ")
|
||||
setForegroundColor(fgYellow)
|
||||
stdout.write(&"{chunk.getLine(offset)}\n")
|
||||
setForegroundColor(fgGreen)
|
||||
stdout.styledWriteLine(fgYellow, &"{chunk.getLine(offset)}")
|
||||
var opcode = OpCode(chunk.code[offset])
|
||||
case opcode:
|
||||
of simpleInstructions:
|
||||
|
@ -163,7 +152,6 @@ proc disassembleChunk*(chunk: Chunk, name: string) =
|
|||
while index < chunk.code.len:
|
||||
index = disassembleInstruction(chunk, index)
|
||||
echo ""
|
||||
setForegroundColor(fgDefault)
|
||||
echo &"==== Debug session ended - Chunk '{name}' ===="
|
||||
|
||||
|
||||
|
|
|
@ -102,6 +102,14 @@ proc writeHeaders(self: Serializer, stream: var seq[byte], file: string) =
|
|||
stream.extend(self.toBytes(computeSHA256(file)))
|
||||
|
||||
|
||||
proc writeLineData(self: Serializer, stream: var seq[byte]) =
|
||||
## Writes line information for debugging
|
||||
## bytecode instructions
|
||||
stream.extend(len(self.chunk.lines).toQuad())
|
||||
for b in self.chunk.lines:
|
||||
stream.extend(b.toTriple())
|
||||
|
||||
|
||||
proc writeConstants(self: Serializer, stream: var seq[byte]) =
|
||||
## Writes the constants table in-place into the
|
||||
## given stream
|
||||
|
@ -145,6 +153,18 @@ proc readHeaders(self: Serializer, stream: seq[byte], serialized: Serialized): i
|
|||
result += 32
|
||||
|
||||
|
||||
proc readLineData(self: Serializer, stream: seq[byte]): int =
|
||||
## Reads line information from a stream
|
||||
## of bytes
|
||||
let size = [stream[0], stream[1], stream[2], stream[3]].fromQuad()
|
||||
result += 4
|
||||
var stream = stream[4..^1]
|
||||
for i in countup(0, int(size) - 1):
|
||||
self.chunk.lines.add(int([stream[0], stream[1], stream[2]].fromTriple()))
|
||||
result += 3
|
||||
stream = stream[3..^1]
|
||||
|
||||
|
||||
proc readConstants(self: Serializer, stream: seq[byte]): int =
|
||||
## Reads the constant table from the given stream
|
||||
## of bytes
|
||||
|
@ -169,16 +189,18 @@ proc readCode(self: Serializer, stream: seq[byte]): int =
|
|||
|
||||
proc dumpBytes*(self: Serializer, chunk: Chunk, file, filename: string): seq[byte] =
|
||||
## Dumps the given bytecode and file to a sequence of bytes and returns it.
|
||||
## The file argument must be the actual file's content and is needed to compute its SHA256 hash.
|
||||
## The file argument must be the actual file's content and is needed to
|
||||
## compute its SHA256 hash.
|
||||
self.file = file
|
||||
self.filename = filename
|
||||
self.chunk = chunk
|
||||
self.writeHeaders(result, self.file)
|
||||
self.writeLineData(result)
|
||||
self.writeConstants(result)
|
||||
self.writeCode(result)
|
||||
|
||||
|
||||
proc dumpToFile*(self: Serializer, chunk: Chunk, file, filename, dest: string) =
|
||||
proc dumpFile*(self: Serializer, chunk: Chunk, file, filename, dest: string) =
|
||||
## Dumps the result of dumpBytes to a file at dest
|
||||
var fp = open(dest, fmWrite)
|
||||
defer: fp.close()
|
||||
|
@ -196,6 +218,7 @@ proc loadBytes*(self: Serializer, stream: seq[byte]): Serialized =
|
|||
var stream = stream
|
||||
try:
|
||||
stream = stream[self.readHeaders(stream, result)..^1]
|
||||
stream = stream[self.readLineData(stream)..^1]
|
||||
stream = stream[self.readConstants(stream)..^1]
|
||||
stream = stream[self.readCode(stream)..^1]
|
||||
except IndexDefect:
|
||||
|
|
Loading…
Reference in New Issue