Various components are now debuggable without recompiling
This commit is contained in:
parent
40d0f23135
commit
879fec20fe
|
@ -15,14 +15,14 @@
|
||||||
import strformat
|
import strformat
|
||||||
|
|
||||||
# These variables can be tweaked to debug and test various components of the toolchain
|
# These variables can be tweaked to debug and test various components of the toolchain
|
||||||
const debugLexer* {.booldefine.} = false # Print the tokenizer's output
|
var debugLexer* = false # Print the tokenizer's output
|
||||||
const debugParser* {.booldefine.} = false # Print the AST generated by the parser
|
var debugParser* = false # Print the AST generated by the parser
|
||||||
const debugCompiler* {.booldefine.} = false # Disassemble and/or print the code generated by the compiler
|
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 debugVM* {.booldefine.} = false # Enable the runtime debugger in the bytecode VM
|
||||||
const debugGC* {.booldefine.} = false # Debug the Garbage Collector (extremely verbose)
|
const debugGC* {.booldefine.} = false # Debug the Garbage Collector (extremely verbose)
|
||||||
const debugAlloc* {.booldefine.} = false # Trace object allocation (extremely verbose)
|
const debugAlloc* {.booldefine.} = false # Trace object allocation (extremely verbose)
|
||||||
const debugMem* {.booldefine.} = false # Debug the memory allocator (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 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 debugMarkGC* {.booldefine.} = false # Trace the marking phase object by object (extremely verbose)
|
||||||
const PeonBytecodeMarker* = "PEON_BYTECODE" # Magic value at the beginning of bytecode files
|
const PeonBytecodeMarker* = "PEON_BYTECODE" # Magic value at the beginning of bytecode files
|
||||||
|
@ -70,8 +70,11 @@ Options
|
||||||
yes/on and no/off
|
yes/on and no/off
|
||||||
--noWarn Disable a specific warning (for example, --noWarn:unusedVariable)
|
--noWarn Disable a specific warning (for example, --noWarn:unusedVariable)
|
||||||
--showMismatches Show all mismatches when function dispatching fails (output is really verbose)
|
--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'
|
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
|
-o, --output Rename the output file with this value (with --backend:bytecode, a '.pbc' extension
|
||||||
is added if not already present)
|
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
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -40,7 +40,7 @@ export ast, token, symbols, config, errors
|
||||||
type
|
type
|
||||||
PeonBackend* = enum
|
PeonBackend* = enum
|
||||||
## An enumeration of the peon backends
|
## An enumeration of the peon backends
|
||||||
Bytecode, NativeC, NativeCpp
|
Bytecode, NativeC
|
||||||
|
|
||||||
PragmaKind* = enum
|
PragmaKind* = enum
|
||||||
## An enumeration of pragma types
|
## An enumeration of pragma types
|
||||||
|
|
92
src/main.nim
92
src/main.nim
|
@ -88,7 +88,7 @@ proc repl(warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: Comp
|
||||||
tokens = tokenizer.lex(input, "stdin")
|
tokens = tokenizer.lex(input, "stdin")
|
||||||
if tokens.len() == 0:
|
if tokens.len() == 0:
|
||||||
continue
|
continue
|
||||||
when debugLexer:
|
if debugLexer:
|
||||||
styledEcho fgCyan, "Tokenization step:"
|
styledEcho fgCyan, "Tokenization step:"
|
||||||
for i, token in tokens:
|
for i, token in tokens:
|
||||||
if i == tokens.high():
|
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)
|
tree = parser.parse(tokens, "stdin", tokenizer.getLines(), input, persist=true)
|
||||||
if tree.len() == 0:
|
if tree.len() == 0:
|
||||||
continue
|
continue
|
||||||
when debugParser:
|
if debugParser:
|
||||||
styledEcho fgCyan, "Parsing step:"
|
styledEcho fgCyan, "Parsing step:"
|
||||||
for node in tree:
|
for node in tree:
|
||||||
styledEcho fgGreen, "\t", $node
|
styledEcho fgGreen, "\t", $node
|
||||||
echo ""
|
echo ""
|
||||||
compiled = compiler.compile(tree, "stdin", tokenizer.getLines(), input, chunk=compiled, showMismatches=mismatches, disabledWarnings=warnings, mode=mode, incremental=true)
|
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"
|
styledEcho fgCyan, "Compilation step:\n"
|
||||||
debugger.disassembleChunk(compiled, "stdin")
|
debugger.disassembleChunk(compiled, "stdin")
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
serialized = serializer.loadBytes(serializer.dumpBytes(compiled, "stdin"))
|
serialized = serializer.loadBytes(serializer.dumpBytes(compiled, "stdin"))
|
||||||
when debugSerializer:
|
if debugSerializer:
|
||||||
styledEcho fgCyan, "Serialization step: "
|
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
|
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.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)
|
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,
|
warnings: seq[WarningKind] = @[], mismatches: bool = false, mode: CompileMode = Debug, run: bool = true,
|
||||||
backend: PeonBackend = PeonBackend.Bytecode, output: string) =
|
backend: PeonBackend = PeonBackend.Bytecode, output: string) =
|
||||||
var
|
var
|
||||||
|
@ -183,7 +183,7 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
|
||||||
tokens = tokenizer.lex(input, f)
|
tokens = tokenizer.lex(input, f)
|
||||||
if tokens.len() == 0:
|
if tokens.len() == 0:
|
||||||
return
|
return
|
||||||
when debugLexer:
|
if debugLexer:
|
||||||
styledEcho fgCyan, "Tokenization step:"
|
styledEcho fgCyan, "Tokenization step:"
|
||||||
for i, token in tokens:
|
for i, token in tokens:
|
||||||
if i == tokens.high():
|
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)
|
tree = parser.parse(tokens, f, tokenizer.getLines(), input)
|
||||||
if tree.len() == 0:
|
if tree.len() == 0:
|
||||||
return
|
return
|
||||||
when debugParser:
|
if debugParser:
|
||||||
styledEcho fgCyan, "Parsing step:"
|
styledEcho fgCyan, "Parsing step:"
|
||||||
for node in tree:
|
for node in tree:
|
||||||
styledEcho fgGreen, "\t", $node
|
styledEcho fgGreen, "\t", $node
|
||||||
|
@ -202,11 +202,9 @@ proc runFile(f: string, fromString: bool = false, dump: bool = true, breakpoints
|
||||||
case backend:
|
case backend:
|
||||||
of PeonBackend.Bytecode:
|
of PeonBackend.Bytecode:
|
||||||
compiled = compiler.compile(tree, f, tokenizer.getLines(), input, disabledWarnings=warnings, showMismatches=mismatches, mode=mode)
|
compiled = compiler.compile(tree, f, tokenizer.getLines(), input, disabledWarnings=warnings, showMismatches=mismatches, mode=mode)
|
||||||
when debugCompiler:
|
if debugCompiler:
|
||||||
styledEcho fgCyan, "Compilation step:\n"
|
styledEcho fgCyan, "Compilation step:\n"
|
||||||
debugger.disassembleChunk(compiled, f)
|
debugger.disassembleChunk(compiled, f)
|
||||||
if dis:
|
|
||||||
debugger.disassembleChunk(compiled, f)
|
|
||||||
var path = splitFile(if output.len() > 0: output else: f).dir
|
var path = splitFile(if output.len() > 0: output else: f).dir
|
||||||
if path.len() > 0:
|
if path.len() > 0:
|
||||||
path &= "/"
|
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")
|
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, "the selected backend is not implemented yet")
|
||||||
elif backend == PeonBackend.Bytecode:
|
elif backend == PeonBackend.Bytecode:
|
||||||
serialized = serializer.loadFile(f)
|
serialized = serializer.loadFile(f)
|
||||||
if backend == PeonBackend.Bytecode:
|
if backend == PeonBackend.Bytecode and debugSerializer:
|
||||||
when debugSerializer:
|
styledEcho fgCyan, "Serialization step: "
|
||||||
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
|
||||||
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.styledWriteLine(fgBlue, "\t- Compilation date & time: ", fgYellow, fromUnix(serialized.compileDate).format("d/M/yyyy HH:mm:ss"))
|
stdout.styledWrite(fgBlue, &"\t- Constants segment: ")
|
||||||
stdout.styledWrite(fgBlue, &"\t- Constants segment: ")
|
if serialized.chunk.consts == compiled.consts:
|
||||||
if serialized.chunk.consts == compiled.consts:
|
styledEcho fgGreen, "OK"
|
||||||
styledEcho fgGreen, "OK"
|
else:
|
||||||
else:
|
styledEcho fgRed, "Corrupted"
|
||||||
styledEcho fgRed, "Corrupted"
|
stdout.styledWrite(fgBlue, &"\t- Code segment: ")
|
||||||
stdout.styledWrite(fgBlue, &"\t- Code segment: ")
|
if serialized.chunk.code == compiled.code:
|
||||||
if serialized.chunk.code == compiled.code:
|
styledEcho fgGreen, "OK"
|
||||||
styledEcho fgGreen, "OK"
|
else:
|
||||||
else:
|
styledEcho fgRed, "Corrupted"
|
||||||
styledEcho fgRed, "Corrupted"
|
stdout.styledWrite(fgBlue, "\t- Line info segment: ")
|
||||||
stdout.styledWrite(fgBlue, "\t- Line info segment: ")
|
if serialized.chunk.lines == compiled.lines:
|
||||||
if serialized.chunk.lines == compiled.lines:
|
styledEcho fgGreen, "OK"
|
||||||
styledEcho fgGreen, "OK"
|
else:
|
||||||
else:
|
styledEcho fgRed, "Corrupted"
|
||||||
styledEcho fgRed, "Corrupted"
|
stdout.styledWrite(fgBlue, "\t- Functions segment: ")
|
||||||
stdout.styledWrite(fgBlue, "\t- Functions segment: ")
|
if serialized.chunk.functions == compiled.functions:
|
||||||
if serialized.chunk.functions == compiled.functions:
|
styledEcho fgGreen, "OK"
|
||||||
styledEcho fgGreen, "OK"
|
else:
|
||||||
else:
|
styledEcho fgRed, "Corrupted"
|
||||||
styledEcho fgRed, "Corrupted"
|
stdout.styledWrite(fgBlue, "\t- Modules segment: ")
|
||||||
stdout.styledWrite(fgBlue, "\t- Modules segment: ")
|
if serialized.chunk.modules == compiled.modules:
|
||||||
if serialized.chunk.modules == compiled.modules:
|
styledEcho fgGreen, "OK"
|
||||||
styledEcho fgGreen, "OK"
|
else:
|
||||||
else:
|
styledEcho fgRed, "Corrupted"
|
||||||
styledEcho fgRed, "Corrupted"
|
|
||||||
if run:
|
if run:
|
||||||
case backend:
|
case backend:
|
||||||
of PeonBackend.Bytecode:
|
of PeonBackend.Bytecode:
|
||||||
|
@ -286,7 +283,6 @@ when isMainModule:
|
||||||
var dump: bool = true
|
var dump: bool = true
|
||||||
var warnings: seq[WarningKind] = @[]
|
var warnings: seq[WarningKind] = @[]
|
||||||
var breaks: seq[uint64] = @[]
|
var breaks: seq[uint64] = @[]
|
||||||
var dis: bool = false
|
|
||||||
var mismatches: bool = false
|
var mismatches: bool = false
|
||||||
var mode: CompileMode = CompileMode.Debug
|
var mode: CompileMode = CompileMode.Debug
|
||||||
var run: bool = true
|
var run: bool = true
|
||||||
|
@ -352,7 +348,7 @@ when isMainModule:
|
||||||
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"error: invalid breakpoint value '{point}'")
|
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"error: invalid breakpoint value '{point}'")
|
||||||
quit()
|
quit()
|
||||||
of "disassemble":
|
of "disassemble":
|
||||||
dis = true
|
debugCompiler = true
|
||||||
of "compile":
|
of "compile":
|
||||||
run = false
|
run = false
|
||||||
of "output":
|
of "output":
|
||||||
|
@ -363,8 +359,12 @@ when isMainModule:
|
||||||
backend = PeonBackend.Bytecode
|
backend = PeonBackend.Bytecode
|
||||||
of "c":
|
of "c":
|
||||||
backend = PeonBackend.NativeC
|
backend = PeonBackend.NativeC
|
||||||
of "cpp":
|
of "debug-dump":
|
||||||
backend = PeonBackend.NativeCpp
|
debugSerializer = true
|
||||||
|
of "debug-lexer":
|
||||||
|
debugLexer = true
|
||||||
|
of "debug-parser":
|
||||||
|
debugParser = true
|
||||||
else:
|
else:
|
||||||
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"error: unkown option '{key}'")
|
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"error: unkown option '{key}'")
|
||||||
quit()
|
quit()
|
||||||
|
@ -405,7 +405,7 @@ when isMainModule:
|
||||||
of "c":
|
of "c":
|
||||||
run = false
|
run = false
|
||||||
of "d":
|
of "d":
|
||||||
dis = true
|
debugCompiler = true
|
||||||
else:
|
else:
|
||||||
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"unkown option '{key}'")
|
stderr.styledWriteLine(fgRed, styleBright, "Error: ", fgDefault, &"unkown option '{key}'")
|
||||||
quit()
|
quit()
|
||||||
|
@ -417,4 +417,4 @@ when isMainModule:
|
||||||
if file == "":
|
if file == "":
|
||||||
repl(warnings, mismatches, mode, breaks)
|
repl(warnings, mismatches, mode, breaks)
|
||||||
else:
|
else:
|
||||||
runFile(file, fromString, dump, breaks, dis, warnings, mismatches, mode, run, backend, output)
|
runFile(file, fromString, dump, breaks, warnings, mismatches, mode, run, backend, output)
|
||||||
|
|
Loading…
Reference in New Issue