Various components are now debuggable without recompiling

This commit is contained in:
Mattia Giambirtone 2023-05-22 13:10:15 +02:00
parent 40d0f23135
commit 879fec20fe
Signed by: nocturn9x
GPG Key ID: 8270F9F467971E59
3 changed files with 55 additions and 52 deletions

View File

@ -15,14 +15,14 @@
import strformat
# These variables can be tweaked to debug and test various components of the toolchain
const debugLexer* {.booldefine.} = false # Print the tokenizer's output
const debugParser* {.booldefine.} = false # Print the AST generated by the parser
const debugCompiler* {.booldefine.} = false # Disassemble and/or print the code generated by the compiler
var debugLexer* = false # Print the tokenizer's output
var debugParser* = false # Print the AST generated by the parser
var debugCompiler* = false # Disassemble and/or print the code generated by the compiler
const debugVM* {.booldefine.} = false # Enable the runtime debugger in the bytecode VM
const debugGC* {.booldefine.} = false # Debug the Garbage Collector (extremely verbose)
const debugAlloc* {.booldefine.} = false # Trace object allocation (extremely verbose)
const debugMem* {.booldefine.} = false # Debug the memory allocator (extremely verbose)
const debugSerializer* {.booldefine.} = false # Validate the bytecode serializer's output
var debugSerializer* = false # Validate the bytecode serializer's output
const debugStressGC* {.booldefine.} = false # Make the GC run a collection at every allocation (VERY SLOW!)
const debugMarkGC* {.booldefine.} = false # Trace the marking phase object by object (extremely verbose)
const PeonBytecodeMarker* = "PEON_BYTECODE" # Magic value at the beginning of bytecode files
@ -70,8 +70,11 @@ Options
yes/on and no/off
--noWarn Disable a specific warning (for example, --noWarn:unusedVariable)
--showMismatches Show all mismatches when function dispatching fails (output is really verbose)
--backend Select the compilation backend (valid values are: 'c', 'cpp' and 'bytecode'). Note
--backend Select the compilation backend (valid values are: 'c' and 'bytecode'). Note
that the REPL always uses the bytecode target. Defaults to 'bytecode'
-o, --output Rename the output file with this value (with --backend:bytecode, a '.pbc' extension
is added if not already present)
--debug-dump Debug the bytecode serializer. Only makes sense with --backend:bytecode
--debug-lexer Debug the peon lexer
--debug-parser Debug the peon parser
"""

View File

@ -40,7 +40,7 @@ export ast, token, symbols, config, errors
type
PeonBackend* = enum
## An enumeration of the peon backends
Bytecode, NativeC, NativeCpp
Bytecode, NativeC
PragmaKind* = enum
## An enumeration of pragma types

View File

@ -88,7 +88,7 @@ proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: Comp
tokens = tokenizer.lex(input, "stdin")
if tokens.len() == 0:
continue
when debugLexer:
if debugLexer:
styledEcho fgCyan, "Tokenization step:"
for i, token in tokens:
if i == tokens.high():
@ -99,19 +99,19 @@ proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: Comp
tree = parser.parse(tokens, "stdin", tokenizer.getLines(), input, persist=true)
if tree.len() == 0:
continue
when debugParser:
if debugParser:
styledEcho fgCyan, "Parsing step:"
for node in tree:
styledEcho fgGreen, "\t", $node
echo ""
compiled = compiler.compile(tree, "stdin", tokenizer.getLines(), input, chunk=compiled, showMismatches=mismatches, disabledWarnings=warnings, mode=mode, incremental=true)
when debugCompiler:
if debugCompiler:
styledEcho fgCyan, "Compilation step:\n"
debugger.disassembleChunk(compiled, "stdin")
echo ""
serialized = serializer.loadBytes(serializer.dumpBytes(compiled, "stdin"))
when debugSerializer:
if debugSerializer:
styledEcho fgCyan, "Serialization step: "
styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.version.major}.{serialized.version.minor}.{serialized.version.patch}", fgBlue, " (commit ", fgYellow, serialized.commit[0..8], fgBlue, ") on branch ", fgYellow, serialized.branch
stdout.styledWriteLine(fgBlue, "\t- Compilation date & time: ", fgYellow, fromUnix(serialized.compileDate).format("d/M/yyyy HH:mm:ss"))
@ -154,7 +154,7 @@ proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: Comp
quit(0)
proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints: seq[uint64] = @[], dis: bool = false,
proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints: seq[uint64] = @[],
warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug, run: bool = true,
backend: PeonBackend = PeonBackend.Bytecode, output: string) =
var
@ -183,7 +183,7 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
tokens = tokenizer.lex(input, f)
if tokens.len() == 0:
return
when debugLexer:
if debugLexer:
styledEcho fgCyan, "Tokenization step:"
for i, token in tokens:
if i == tokens.high():
@ -194,7 +194,7 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
tree = parser.parse(tokens, f, tokenizer.getLines(), input)
if tree.len() == 0:
return
when debugParser:
if debugParser:
styledEcho fgCyan, "Parsing step:"
for node in tree:
styledEcho fgGreen, "\t", $node
@ -202,11 +202,9 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
case backend:
of PeonBackend.Bytecode:
compiled = compiler.compile(tree, f, tokenizer.getLines(), input, disabledWarnings=warnings, showMismatches=mismatches, mode=mode)
when debugCompiler:
if debugCompiler:
styledEcho fgCyan, "Compilation step:\n"
debugger.disassembleChunk(compiled, f)
if dis:
debugger.disassembleChunk(compiled, f)
var path = splitFile(if output.len() > 0: output else: f).dir
if path.len() > 0:
path &= "/"
@ -221,36 +219,35 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, "the selected backend is not implemented yet")
elif backend == PeonBackend.Bytecode:
serialized = serializer.loadFile(f)
if backend == PeonBackend.Bytecode:
when debugSerializer:
styledEcho fgCyan, "Serialization step: "
styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.version.major}.{serialized.version.minor}.{serialized.version.patch}", fgBlue, " (commit ", fgYellow, serialized.commit[0..8], fgBlue, ") on branch ", fgYellow, serialized.branch
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"
stdout.styledWrite(fgBlue, "\t- Functions segment: ")
if serialized.chunk.functions == compiled.functions:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
stdout.styledWrite(fgBlue, "\t- Modules segment: ")
if serialized.chunk.modules == compiled.modules:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
if backend == PeonBackend.Bytecode and debugSerializer:
styledEcho fgCyan, "Serialization step: "
styledEcho fgBlue, "\t- Peon version: ", fgYellow, &"{serialized.version.major}.{serialized.version.minor}.{serialized.version.patch}", fgBlue, " (commit ", fgYellow, serialized.commit[0..8], fgBlue, ") on branch ", fgYellow, serialized.branch
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"
stdout.styledWrite(fgBlue, "\t- Functions segment: ")
if serialized.chunk.functions == compiled.functions:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
stdout.styledWrite(fgBlue, "\t- Modules segment: ")
if serialized.chunk.modules == compiled.modules:
styledEcho fgGreen, "OK"
else:
styledEcho fgRed, "Corrupted"
if run:
case backend:
of PeonBackend.Bytecode:
@ -286,7 +283,6 @@ when isMainModule:
var dump: bool = true
var warnings: seq[WarningKind] = @[]
var breaks: seq[uint64] = @[]
var dis: bool = false
var mismatches: bool = false
var mode: CompileMode = CompileMode.Debug
var run: bool = true
@ -352,7 +348,7 @@ when isMainModule:
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"error: invalid breakpoint value '{point}'")
quit()
of "disassemble":
dis = true
debugCompiler = true
of "compile":
run = false
of "output":
@ -363,8 +359,12 @@ when isMainModule:
backend = PeonBackend.Bytecode
of "c":
backend = PeonBackend.NativeC
of "cpp":
backend = PeonBackend.NativeCpp
of "debug-dump":
debugSerializer = true
of "debug-lexer":
debugLexer = true
of "debug-parser":
debugParser = true
else:
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"error: unkown option '{key}'")
quit()
@ -405,7 +405,7 @@ when isMainModule:
of "c":
run = false
of "d":
dis = true
debugCompiler = true
else:
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"unkown option '{key}'")
quit()
@ -417,4 +417,4 @@ when isMainModule:
if file == "":
repl(warnings, mismatches, mode, breaks)
else:
runFile(file, fromString, dump, breaks, dis, warnings, mismatches, mode, run, backend, output)
runFile(file, fromString, dump, breaks, warnings, mismatches, mode, run, backend, output)