Created
September 22, 2023 00:25
-
-
Save Vindaar/036c9d50babff420455dc9eb25e86ade to your computer and use it in GitHub Desktop.
Toy dynlib based Nim REPL
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import noise, strutils, strformat, shell, tables, dynlib | |
proc printHelp() = echo "" | |
const procTmpl = """ | |
{.push cdecl, exportc, dynlib.} | |
$# | |
{.pop.} | |
""" | |
const exprTmpl = """ | |
$# # <- insert code to importc & | |
{.push cdecl, exportc, dynlib.} | |
proc tmp() = | |
$# | |
{.pop.} | |
""" | |
proc callTmp(fname, procName: string) = | |
## XXX: do not unload lib! | |
echo "Loading: ", fname, " name: ", procName | |
let lib = loadLib(fname) | |
doAssert lib != nil | |
let foo = cast[(proc() {.nimcall.})](lib.symAddr(procName)) | |
doAssert foo != nil | |
foo() | |
unloadLib(lib) | |
var count = 0 | |
# maps known functions to their dynlib | |
var fnTab = initTable[string, (string, string)]() | |
proc loadIt(fn, signature, lib: string): string = | |
result = signature & "{.importc: \"" & fn & "\", dynlib: \"" & lib & "\".}" | |
proc codeToLoad(): string = | |
for fn, (file, signature) in fnTab: | |
result.add loadIt(fn, signature, file) & "\n" | |
proc handleUserInput(line: string) = | |
## nim stuff! | |
# simple: if `proc` in input, just simple proc exported | |
# else: wrap in tmp proc | |
var content = "" | |
let loadCode = codeToLoad() | |
let isProc = "proc" in line | |
if isProc: content = procTmpl % line | |
else: content = exprTmpl % [loadCode, line] | |
# write file | |
let fname = "tmp_file_$#.nim" % $count | |
let file = "/t/$#" % fname | |
writeFile(file, content) | |
echo "\tWrote:\n", content | |
inc count | |
# compile as lib | |
shell: | |
nim c "--app:lib --verbosity:0" ($file) | |
let outfile = ("/t/lib" & fname).replace(".nim", ".so") | |
if not isProc: | |
# call tmp function | |
callTmp(outfile, "tmp") | |
else: | |
## XXX: save the procedures to a table, then | |
var fnName = line | |
fnName.removePrefix("proc ") | |
fnName = fnName.split("(")[0] | |
var signature = line | |
signature = signature.split("=")[0] ## XXX: Better extract real proc signature!!! | |
fnTab[fnName] = (outfile, signature) | |
proc main() = | |
var noise = Noise.init() | |
let prompt = Styler.init(fgRed, "Red ", fgGreen, "nim> ") | |
noise.setPrompt(prompt) | |
when promptPreloadBuffer: | |
noise.preloadBuffer("") | |
when promptHistory: | |
var file = "history" | |
discard noise.historyLoad(file) | |
when promptCompletion: | |
proc completionHook(noise: var Noise, text: string): int = | |
const words = ["apple", "diamond", "diadem", "diablo", "horse", "home", "quartz", "quit"] | |
for w in words: | |
if w.find(text) != -1: | |
noise.addCompletion w | |
noise.setCompletionHook(completionHook) | |
while true: | |
let ok = noise.readLine() | |
if not ok: break | |
## XXX: figure out how to input multiple lines | |
let line = noise.getLine | |
case line | |
of ".help": printHelp() | |
of ".quit": break | |
else: | |
if line.len > 0: | |
handleUserInput(line.strip) | |
when promptHistory: | |
if line.len > 0: | |
noise.historyAdd(line) | |
when promptHistory: | |
discard noise.historySave(file) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment