scripts.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. # author: Ethosa
  2. ## It provides runtime scripts loader.
  3. import
  4. compiler / [
  5. astalgo, ast, vmdef, vm, options,
  6. modulegraphs, idents, modules,
  7. pathutils, llstream, passes, sem,
  8. condsyms
  9. ],
  10. exceptions,
  11. os
  12. type
  13. CompiledScript = ref object
  14. pctx*: PCtx
  15. graph*: ModuleGraph
  16. module*: PSym
  17. filename*: string
  18. var
  19. ident_cache = newIdentCache()
  20. cfg = newConfigRef()
  21. once:
  22. # Search .nimble/lib folder 👀
  23. cfg.libpath = AbsoluteDir(getHomeDir() / ".nimble" / "lib")
  24. cfg.searchPaths.add(cfg.libpath)
  25. cfg.searchPaths.add(AbsoluteDir($cfg.libpath / "pure"))
  26. # --- Convert default Nim types to PNode --- #
  27. converter toNode*(x: float): PNode = newFloatNode(nkFloatLit, x)
  28. converter toNode*(x: int): PNode = newIntNode(nkIntLit, x)
  29. converter toNode*(x: string): PNode = newStrNode(nkStrLit, x)
  30. converter toNode*(x: bool): PNode = x.ord.toNode()
  31. converter toNode*(x: enum): PNode = x.ord.toNode()
  32. converter toNode*(x: openarray[int|float|string|bool|enum]): PNode =
  33. result = newNode(nkBracket)
  34. result.sons.initialize(x.len)
  35. for i in x.low..x.high:
  36. result[i] = x[i].toNode()
  37. converter toNode*(x: tuple | object): PNode =
  38. result = newTree(nkPar)
  39. for field in x.fields:
  40. result.sons.add(field.toNode())
  41. converter toNode*(x: ref tuple | ref object): PNode =
  42. result = newTree(nkPar)
  43. if x.isNil():
  44. return result
  45. for field in x.fields:
  46. result.sons.add(field.toNode())
  47. proc setupModule(self: CompiledScript) =
  48. self.graph.connectCallbacks()
  49. initDefines(cfg.symbols)
  50. defineSymbol(cfg.symbols, "nimscript")
  51. defineSymbol(cfg.symbols, "nimconfig")
  52. self.graph.registerPass(semPass)
  53. self.graph.registerPass(evalPass)
  54. proc cleanupModule(self: CompiledScript) =
  55. initDefines(cfg.symbols)
  56. undefSymbol(cfg.symbols, "nimscript")
  57. undefSymbol(cfg.symbols, "nimconfig")
  58. clearPasses(self.graph)
  59. proc compileScript*(file: string): CompiledScript =
  60. ## Compiles script with std module.
  61. new result
  62. result.filename = file
  63. result.graph = newModuleGraph(ident_cache, cfg)
  64. result.setupModule()
  65. result.module = makeModule(result.graph, file)
  66. # Create context
  67. incl(result.module.flags, sfMainModule)
  68. result.pctx = newCtx(result.module, identCache, result.graph)
  69. result.pctx.mode = emRepl
  70. # Setup context
  71. setupGlobalCtx(result.module, result.graph)
  72. registerAdditionalOps(result.pctx)
  73. # Compile std
  74. compileSystemModule(result.graph)
  75. # Compile module
  76. if not processModule(result.graph, result.module, llStreamOpen(AbsoluteFile(file), fmRead)):
  77. raise newException(VMError, "Failed to process `" & file & "`")
  78. # Cleanup
  79. setupGlobalCtx(nil, result.graph)
  80. result.cleanupModule()
  81. proc getProc*(self: CompiledScript, routine: string): PSym =
  82. strTableGet(self.module.tab, getIdent(identCache, routine))
  83. proc hasProc*(self: CompiledScript, routine: string): bool =
  84. ## Returns true, if `routine` available.
  85. not self.getProc(routine).isNil()
  86. proc call*(self: CompiledScript, routine: string,
  87. args: varargs[PNode]): PNode {.discardable.} =
  88. ## Calls routine by name
  89. # Setup context
  90. setupGlobalCtx(self.module, self.graph)
  91. # Find routine
  92. let prc = self.getProc(routine)
  93. if prc.isNil():
  94. raise newException(VMError, "\nUnable to locate proc `" & routine & "` in `" & self.filename & "`")
  95. # Call routine
  96. result = execProc(self.pctx, prc, args)