rewrote nimeval.nim; added tcompilerapi example to show how the compiler can be used as an API

This commit is contained in:
Andreas Rumpf 2018-05-29 01:18:50 +02:00
commit 06122ff711
5 changed files with 152 additions and 20 deletions

View file

@ -1,7 +1,7 @@
#
#
# The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2018 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -9,27 +9,108 @@
## exposes the Nim VM to clients.
import
ast, modules, passes, passaux, condsyms,
options, nimconf, sem, semdata, llstream, vm, modulegraphs, idents
ast, astalgo, modules, passes, condsyms,
options, sem, semdata, llstream, vm, vmdef,
modulegraphs, idents, os
proc execute*(program: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
loadConfigs(DefaultConfig)
type
Interpreter* = ref object ## Use Nim as an interpreter with this object
mainModule: PSym
graph: ModuleGraph
scriptName: string
initDefines()
defineSymbol("nimvm")
defineSymbol("nimscript")
when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass)
registerPass(semPass)
registerPass(evalPass)
iterator exportedSymbols*(i: Interpreter): PSym =
assert i != nil
assert i.mainModule != nil, "no main module selected"
var it: TTabIter
var s = initTabIter(it, i.mainModule.tab)
while s != nil:
yield s
s = nextIter(it, i.mainModule.tab)
searchPaths.add options.libpath
var graph = newModuleGraph()
proc selectUniqueSymbol*(i: Interpreter; name: string;
symKinds: set[TSymKind]): PSym =
## Can be used to access a unique symbol of ``name`` and
## the given ``symKinds`` filter.
assert i != nil
assert i.mainModule != nil, "no main module selected"
let n = getIdent(i.graph.cache, name)
var it: TIdentIter
var s = initIdentIter(it, i.mainModule.tab, n)
result = nil
while s != nil:
if s.kind in symKinds:
if result == nil: result = s
else: return nil # ambiguous
s = nextIdentIter(it, i.mainModule.tab)
proc selectRoutine*(i: Interpreter; name: string): PSym =
## Selects a declared rountine (proc/func/etc) from the main module.
## The routine needs to have the export marker ``*``. The only matching
## routine is returned and ``nil`` if it is overloaded.
result = selectUniqueSymbol(i, name, {skTemplate, skMacro, skFunc,
skMethod, skProc, skConverter})
proc callRoutine*(i: Interpreter; routine: PSym; args: openArray[PNode]): PNode =
assert i != nil
result = vm.execProc(PCtx i.graph.vm, routine, args)
proc declareRoutine*(i: Interpreter; pkg, module, name: string;
impl: proc (a: VmArgs) {.closure, gcsafe.}) =
assert i != nil
let vm = PCtx(i.graph.vm)
vm.registerCallback(pkg & "." & module & "." & name, impl)
proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
## This can also be used to *reload* the script.
assert i != nil
assert i.mainModule != nil, "no main module selected"
initStrTable(i.mainModule.tab)
i.mainModule.ast = nil
let s = if scriptStream != nil: scriptStream
else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
processModule(i.graph, i.mainModule, s, nil, i.graph.cache)
proc findNimStdLib*(): string =
## Tries to find a path to a valid "system.nim" file.
## Returns "" on failure.
try:
let nimexe = os.findExe("nim")
if nimexe.len == 0: return ""
result = nimexe.splitPath()[0] /../ "lib"
if not fileExists(result / "system.nim"):
when defined(unix):
result = nimexe.expandSymlink.splitPath()[0] /../ "lib"
if not fileExists(result / "system.nim"): return ""
except OSError, ValueError:
return ""
proc createInterpreter*(scriptName: string;
searchPaths: openArray[string];
flags: TSandboxFlags = {}): Interpreter =
var conf = newConfigRef()
var cache = newIdentCache()
var m = makeStdinModule(graph)
var graph = newModuleGraph(cache, conf)
initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(graph, semPass)
registerPass(graph, evalPass)
for p in searchPaths:
conf.searchPaths.add(p)
if conf.libpath.len == 0: conf.libpath = p
var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule)
compileSystemModule(graph,cache)
processModule(graph,m, llStreamOpen(program), nil, cache)
var vm = newCtx(m, cache, graph)
vm.mode = emRepl
vm.features = flags
graph.vm = vm
graph.compileSystemModule(cache)
result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName)
proc destroyInterpreter*(i: Interpreter) =
## destructor.
discard "currently nothing to do."