nimeval.nim 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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, lineinfos, vm,
  13. vmdef, modulegraphs, idents, os, pathutils,
  14. passaux, scriptconfig
  15. type
  16. Interpreter* = ref object ## Use Nim as an interpreter with this object
  17. mainModule: PSym
  18. graph: ModuleGraph
  19. scriptName: string
  20. idgen: IdGenerator
  21. iterator exportedSymbols*(i: Interpreter): PSym =
  22. assert i != nil
  23. assert i.mainModule != nil, "no main module selected"
  24. var it: TTabIter
  25. var s = initTabIter(it, i.mainModule.tab)
  26. while s != nil:
  27. yield s
  28. s = nextIter(it, i.mainModule.tab)
  29. proc selectUniqueSymbol*(i: Interpreter; name: string;
  30. symKinds: set[TSymKind] = {skLet, skVar}): PSym =
  31. ## Can be used to access a unique symbol of ``name`` and
  32. ## the given ``symKinds`` filter.
  33. assert i != nil
  34. assert i.mainModule != nil, "no main module selected"
  35. let n = getIdent(i.graph.cache, name)
  36. var it: TIdentIter
  37. var s = initIdentIter(it, i.mainModule.tab, n)
  38. result = nil
  39. while s != nil:
  40. if s.kind in symKinds:
  41. if result == nil: result = s
  42. else: return nil # ambiguous
  43. s = nextIdentIter(it, i.mainModule.tab)
  44. proc selectRoutine*(i: Interpreter; name: string): PSym =
  45. ## Selects a declared routine (proc/func/etc) from the main module.
  46. ## The routine needs to have the export marker ``*``. The only matching
  47. ## routine is returned and ``nil`` if it is overloaded.
  48. result = selectUniqueSymbol(i, name, {skTemplate, skMacro, skFunc,
  49. skMethod, skProc, skConverter})
  50. proc callRoutine*(i: Interpreter; routine: PSym; args: openArray[PNode]): PNode =
  51. assert i != nil
  52. result = vm.execProc(PCtx i.graph.vm, routine, args)
  53. proc getGlobalValue*(i: Interpreter; letOrVar: PSym): PNode =
  54. result = vm.getGlobalValue(PCtx i.graph.vm, letOrVar)
  55. proc implementRoutine*(i: Interpreter; pkg, module, name: string;
  56. impl: proc (a: VmArgs) {.closure, gcsafe.}) =
  57. assert i != nil
  58. let vm = PCtx(i.graph.vm)
  59. vm.registerCallback(pkg & "." & module & "." & name, impl)
  60. proc evalScript*(i: Interpreter; scriptStream: PLLStream = nil) =
  61. ## This can also be used to *reload* the script.
  62. assert i != nil
  63. assert i.mainModule != nil, "no main module selected"
  64. initStrTable(i.mainModule.tab)
  65. i.mainModule.ast = nil
  66. let s = if scriptStream != nil: scriptStream
  67. else: llStreamOpen(findFile(i.graph.config, i.scriptName), fmRead)
  68. processModule(i.graph, i.mainModule, i.idgen, s)
  69. proc findNimStdLib*(): string =
  70. ## Tries to find a path to a valid "system.nim" file.
  71. ## Returns "" on failure.
  72. try:
  73. let nimexe = os.findExe("nim")
  74. # this can't work with choosenim shims, refs https://github.com/dom96/choosenim/issues/189
  75. # it'd need `nim dump --dump.format:json . | jq -r .libpath`
  76. # which we should simplify as `nim dump --key:libpath`
  77. if nimexe.len == 0: return ""
  78. result = nimexe.splitPath()[0] /../ "lib"
  79. if not fileExists(result / "system.nim"):
  80. when defined(unix):
  81. result = nimexe.expandSymlink.splitPath()[0] /../ "lib"
  82. if not fileExists(result / "system.nim"): return ""
  83. except OSError, ValueError:
  84. return ""
  85. proc findNimStdLibCompileTime*(): string =
  86. ## Same as ``findNimStdLib`` but uses source files used at compile time,
  87. ## and asserts on error.
  88. const exe = getCurrentCompilerExe()
  89. result = exe.splitFile.dir.parentDir / "lib"
  90. doAssert fileExists(result / "system.nim"), "result:" & result
  91. proc createInterpreter*(scriptName: string;
  92. searchPaths: openArray[string];
  93. flags: TSandboxFlags = {},
  94. defines = @[("nimscript", "true")],
  95. registerOps = true): Interpreter =
  96. var conf = newConfigRef()
  97. var cache = newIdentCache()
  98. var graph = newModuleGraph(cache, conf)
  99. connectCallbacks(graph)
  100. initDefines(conf.symbols)
  101. for define in defines:
  102. defineSymbol(conf.symbols, define[0], define[1])
  103. registerPass(graph, semPass)
  104. registerPass(graph, evalPass)
  105. for p in searchPaths:
  106. conf.searchPaths.add(AbsoluteDir p)
  107. if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
  108. var m = graph.makeModule(scriptName)
  109. incl(m.flags, sfMainModule)
  110. var idgen = idGeneratorFromModule(m)
  111. var vm = newCtx(m, cache, graph, idgen)
  112. vm.mode = emRepl
  113. vm.features = flags
  114. if registerOps:
  115. vm.registerAdditionalOps() # Required to register parts of stdlib modules
  116. graph.vm = vm
  117. graph.compileSystemModule()
  118. result = Interpreter(mainModule: m, graph: graph, scriptName: scriptName, idgen: idgen)
  119. proc destroyInterpreter*(i: Interpreter) =
  120. ## destructor.
  121. discard "currently nothing to do."
  122. proc registerErrorHook*(i: Interpreter, hook:
  123. proc (config: ConfigRef; info: TLineInfo; msg: string;
  124. severity: Severity) {.gcsafe.}) =
  125. i.graph.config.structuredErrorHook = hook
  126. proc runRepl*(r: TLLRepl;
  127. searchPaths: openArray[string];
  128. supportNimscript: bool) =
  129. ## deadcode but please don't remove... might be revived
  130. var conf = newConfigRef()
  131. var cache = newIdentCache()
  132. var graph = newModuleGraph(cache, conf)
  133. for p in searchPaths:
  134. conf.searchPaths.add(AbsoluteDir p)
  135. if conf.libpath.isEmpty: conf.libpath = AbsoluteDir p
  136. conf.cmd = cmdInteractive
  137. conf.setErrorMaxHighMaybe
  138. initDefines(conf.symbols)
  139. defineSymbol(conf.symbols, "nimscript")
  140. if supportNimscript: defineSymbol(conf.symbols, "nimconfig")
  141. when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
  142. registerPass(graph, verbosePass)
  143. registerPass(graph, semPass)
  144. registerPass(graph, evalPass)
  145. var m = graph.makeStdinModule()
  146. incl(m.flags, sfMainModule)
  147. var idgen = idGeneratorFromModule(m)
  148. if supportNimscript: graph.vm = setupVM(m, cache, "stdin", graph, idgen)
  149. graph.compileSystemModule()
  150. processModule(graph, m, idgen, llStreamOpenStdIn(r))