I've recently experimented with using the compiler API for hot code reloading. I know there is already an hcr module, but I think using the Nimscript interpreter could be a simpler and more reliable way of doing it (not to mention lispier!).
My approach was to make a separate module that I want to reload, such as src/core.nim, and in my main module I would do something like...
when defined(release):
import core
else:
# load core.nim with the compiler API and use a file watcher to reload it when it's edited
The only problem is that currently, when the compiler API runs into an error, it aborts the process. I believe that's happening here. Wouldn't it make sense for evalScript to throw an exception, so I can catch it and print it out? That would make it much more usable for this purpose.
This is a hack, but it works for me on 1.2.6. If you include rather than import nimeval, you can access the ModuleGraph for the interpreter and register an error hook. This will be called for all sorts of things, but if you validate that errorCount >= errorMax you should be able to filter out fatal errors that would otherwise quit the process.
With the hook installed you can then catch ScriptError and grab the error and the line info. It might also be possible to get a stack trace out of ModuleGraph, but I didn't get that far.
import compiler / [vm, vmdef, options, lineinfos, ast]
include compiler/nimeval
type
ScriptError* = ref object of CatchableError
info*: TLineInfo
proc loadScript*(scriptFile: string): Interpreter =
let
stdLib = findNimStdLib()
sourcePaths = [stdLib, stdLib & "/core"]
result = createInterpreter(scriptFile, sourcePaths)
result.graph.config.structuredErrorHook =
proc(config: ConfigRef, info: TLineInfo, msg: string, severity: Severity) =
if severity == Error and config.errorCounter >= config.errorMax:
raise ScriptError(msg: msg, info: info)
result.evalScript()
Please let me know if you've found another way to do this, without modifying the compiler. Thanks!
You can use the system module to capture the standard output and standard error streams when evaluating the script with evalScript. This way, you can check if there are any errors in the standard error output and handle them in your code.
Here's an example of how you can modify your code to achieve this: import system
let errorMessage = e.msg stderr.writeLine("Error in ", script, ": ", errorMessage)
main()