nimeval.nim 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2018 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## exposes the Nim VM to clients.
  10. import
  11. ast, astalgo, modules, passes, condsyms,
  12. options, sem, semdata, llstream, vm, vmdef,
  13. modulegraphs, idents, os, pathutils
  14. type
  15. Interpreter* = ref object ## Use Nim as an interpreter with this object
  16. mainModule: PSym
  17. graph: ModuleGraph
  18. scriptName: string
  19. iterator exportedSymbols*(i: Interpreter): PSym =
  20. assert i != nil
  21. assert i.mainModule != nil, "no main module selected"
  22. var it: TTabIter
  23. var s = initTabIter(it, i.mainModule.tab)
  24. while s != nil:
  25. yield s
  26. s = nextIter(it, i.mainModule.tab)
  27. proc selectUniqueSymbol*(i: Interpreter; name: string;
  28. symKinds: set[TSymKind] = {skLet, skVar}): PSym =
  29. ## Can be used to access a unique symbol of ``name`` and
  30. ## the given ``symKinds`` filter.
  31. assert i != nil
  32. assert i.mainModule != nil, "no main module selected"
  33. let n = getIdent(i.graph.cache, name)
  34. var it: TIdentIter
  35. var s = initIdentIter(it, i.mainModule.tab, n)
  36. result = nil
  37. while s != nil:
  38. if s.kind in symKinds:
  39. if result == nil: result = s
  40. else: return nil # ambiguous
  41. s = nextIdentIter(it, i.mainModule.tab)
  42. proc selectRoutine*(i: Interpreter; name: string): PSym =
  43. ## Selects a declared rountine (proc/func/etc) from the main module.
  44. ## The routine needs to have the export marker ``*``. The only matching
  45. ## routine is returned and ``nil`` if it is overloaded.
  46. result = selectUniqueSymbol(i, name, {skTemplate, skMacro, skFunc,
  47. skMethod, skProc, skConverter})
  48. proc callRoutine*(i: Interpreter; routine: PSym; args: openArray[PNode]): PNode =
  49. assert i != nil
  50. result = vm.execProc(PCtx i.graph.vm, routine, args)
  51. proc getGlobalValue*(i: Interpreter; letOrVar: PSym): PNode =
  52. result = vm.getGlobalValue(PCtx i.graph.vm, letOrVar)
  53. proc implementRoutine*(i: Interpreter; pkg, module, name: string;
  54. impl: proc (a: VmArgs) {.closure, gcsafe.}) =
  55. assert i != nil
  56. let vm = PCtx(i.graph.vm)
  57. vm.registerCallback(pkg & "." & module & "." & name, impl)
  58. proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
  59. ## This can also be used to *reload* the script.
  60. assert i != nil
  61. assert i.mainModule != nil, "no main module selected"
  62. initStrTable(i.mainModule.tab)
  63. i.mainModule.ast = nil
  64. let s = if scriptStream != nil: scriptStream
  65. else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
  66. processModule(i.graph, i.mainModule, s)
  67. proc findNimStdLib*(): string =
  68. ## Tries to find a path to a valid "system.nim" file.
  69. ## Returns "" on failure.
  70. try:
  71. let nimexe = os.findExe("nim")
  72. if nimexe.len == 0: return ""
  73. result = nimexe.splitPath()[0] /../ "lib"
  74. if not fileExists(result / "system.nim"):
  75. when defined(unix):
  76. result = nimexe.expandSymlink.splitPath()[0] /../ "lib"
  77. if not fileExists(result / "system.nim"): return ""
  78. except OSError, ValueError:
  79. return ""
  80. proc findNimStdLibCompileTime*(): string =
  81. ## Same as ``findNimStdLib`` but uses source files used at compile time,
  82. ## and asserts on error.
  83. const sourcePath = currentSourcePath()
  84. result = sourcePath.parentDir.parentDir / "lib"
  85. doAssert fileExists(result / "system.nim"), "result:" & result
  86. proc createInterpreter*(scriptName: string;
  87. searchPaths: openArray[string];
  88. flags: TSandboxFlags = {}): Interpreter =
  89. var conf = newConfigRef()
  90. var cache = newIdentCache()
  91. var graph = newModuleGraph(cache, conf)
  92. connectCallbacks(graph)
  93. initDefines(conf.symbols)
  94. defineSymbol(conf.symbols, "nimscript")
  95. defineSymbol(conf.symbols, "nimconfig")
  96. registerPass(graph, semPass)
  97. registerPass(graph, evalPass)
  98. for p in searchPaths:
  99. conf.searchPaths.add(AbsoluteDir p)
  100. if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
  101. var m = graph.makeModule(scriptName)
  102. incl(m.flags, sfMainModule)
  103. var vm = newCtx(m, cache, graph)
  104. vm.mode = emRepl
  105. vm.features = flags
  106. graph.vm = vm
  107. graph.compileSystemModule()
  108. result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName)
  109. proc destroyInterpreter*(i: Interpreter) =
  110. ## destructor.
  111. discard "currently nothing to do."