scriptconfig.nim 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## Implements the new configuration system for Nim. Uses Nim as a scripting
  10. ## language.
  11. import
  12. ast, modules, idents, condsyms,
  13. options, llstream, vm, vmdef, commands,
  14. wordrecg, modulegraphs,
  15. pathutils, pipelines
  16. when defined(nimPreviewSlimSystem):
  17. import std/[syncio, assertions]
  18. import std/[strtabs, os, times, osproc]
  19. # we support 'cmpIgnoreStyle' natively for efficiency:
  20. from std/strutils import cmpIgnoreStyle, contains
  21. proc listDirs(a: VmArgs, filter: set[PathComponent]) =
  22. let dir = getString(a, 0)
  23. var result: seq[string] = @[]
  24. for kind, path in walkDir(dir):
  25. if kind in filter: result.add path
  26. setResult(a, result)
  27. proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
  28. graph: ModuleGraph; idgen: IdGenerator): PEvalContext =
  29. # For Nimble we need to export 'setupVM'.
  30. result = newCtx(module, cache, graph, idgen)
  31. result.mode = emRepl
  32. registerAdditionalOps(result)
  33. let conf = graph.config
  34. # captured vars:
  35. var errorMsg: string
  36. var vthisDir = scriptName.splitFile.dir
  37. template cbconf(name, body) {.dirty.} =
  38. result.registerCallback "stdlib.system." & astToStr(name),
  39. proc (a: VmArgs) =
  40. body
  41. template cbexc(name, exc, body) {.dirty.} =
  42. result.registerCallback "stdlib.system." & astToStr(name),
  43. proc (a: VmArgs) =
  44. errorMsg = ""
  45. try:
  46. body
  47. except exc:
  48. errorMsg = getCurrentExceptionMsg()
  49. template cbos(name, body) {.dirty.} =
  50. cbexc(name, OSError, body)
  51. # Idea: Treat link to file as a file, but ignore link to directory to prevent
  52. # endless recursions out of the box.
  53. cbos listFilesImpl:
  54. listDirs(a, {pcFile, pcLinkToFile})
  55. cbos listDirsImpl:
  56. listDirs(a, {pcDir})
  57. cbos removeDir:
  58. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  59. discard
  60. else:
  61. os.removeDir(getString(a, 0), getBool(a, 1))
  62. cbos removeFile:
  63. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  64. discard
  65. else:
  66. os.removeFile getString(a, 0)
  67. cbos createDir:
  68. os.createDir getString(a, 0)
  69. result.registerCallback "stdlib.system.getError",
  70. proc (a: VmArgs) = setResult(a, errorMsg)
  71. cbos setCurrentDir:
  72. os.setCurrentDir getString(a, 0)
  73. cbos getCurrentDir:
  74. setResult(a, os.getCurrentDir())
  75. cbos moveFile:
  76. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  77. discard
  78. else:
  79. os.moveFile(getString(a, 0), getString(a, 1))
  80. cbos moveDir:
  81. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  82. discard
  83. else:
  84. os.moveDir(getString(a, 0), getString(a, 1))
  85. cbos copyFile:
  86. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  87. discard
  88. else:
  89. os.copyFile(getString(a, 0), getString(a, 1))
  90. cbos copyDir:
  91. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  92. discard
  93. else:
  94. os.copyDir(getString(a, 0), getString(a, 1))
  95. cbos getLastModificationTime:
  96. setResult(a, getLastModificationTime(getString(a, 0)).toUnix)
  97. cbos findExe:
  98. setResult(a, os.findExe(getString(a, 0)))
  99. cbos rawExec:
  100. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  101. discard
  102. else:
  103. setResult(a, osproc.execCmd getString(a, 0))
  104. cbconf getEnv:
  105. setResult(a, os.getEnv(a.getString 0, a.getString 1))
  106. cbconf existsEnv:
  107. setResult(a, os.existsEnv(a.getString 0))
  108. cbconf putEnv:
  109. os.putEnv(a.getString 0, a.getString 1)
  110. cbconf delEnv:
  111. os.delEnv(a.getString 0)
  112. cbconf dirExists:
  113. setResult(a, os.dirExists(a.getString 0))
  114. cbconf fileExists:
  115. setResult(a, os.fileExists(a.getString 0))
  116. cbconf projectName:
  117. setResult(a, conf.projectName)
  118. cbconf projectDir:
  119. setResult(a, conf.projectPath.string)
  120. cbconf projectPath:
  121. setResult(a, conf.projectFull.string)
  122. cbconf thisDir:
  123. setResult(a, vthisDir)
  124. cbconf put:
  125. options.setConfigVar(conf, getString(a, 0), getString(a, 1))
  126. cbconf get:
  127. setResult(a, options.getConfigVar(conf, a.getString 0))
  128. cbconf exists:
  129. setResult(a, options.existsConfigVar(conf, a.getString 0))
  130. cbconf nimcacheDir:
  131. setResult(a, options.getNimcacheDir(conf).string)
  132. cbconf paramStr:
  133. setResult(a, os.paramStr(int a.getInt 0))
  134. cbconf paramCount:
  135. setResult(a, os.paramCount())
  136. cbconf cmpIgnoreStyle:
  137. setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1))
  138. cbconf cmpIgnoreCase:
  139. setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
  140. cbconf setCommand:
  141. conf.setCommandEarly(a.getString 0)
  142. let arg = a.getString 1
  143. incl(conf.globalOptions, optWasNimscript)
  144. if arg.len > 0: setFromProjectName(conf, arg)
  145. cbconf getCommand:
  146. setResult(a, conf.command)
  147. cbconf switch:
  148. conf.currentConfigDir = vthisDir
  149. processSwitch(a.getString 0, a.getString 1, passPP, module.info, conf)
  150. cbconf hintImpl:
  151. processSpecificNote(a.getString 0, wHint, passPP, module.info,
  152. a.getString 1, conf)
  153. cbconf warningImpl:
  154. processSpecificNote(a.getString 0, wWarning, passPP, module.info,
  155. a.getString 1, conf)
  156. cbconf patchFile:
  157. let key = a.getString(0) & "_" & a.getString(1)
  158. var val = a.getString(2).addFileExt(NimExt)
  159. if {'$', '~'} in val:
  160. val = pathSubs(conf, val, vthisDir)
  161. elif not isAbsolute(val):
  162. val = vthisDir / val
  163. conf.moduleOverrides[key] = val
  164. cbconf selfExe:
  165. setResult(a, os.getAppFilename())
  166. cbconf cppDefine:
  167. options.cppDefine(conf, a.getString(0))
  168. cbexc stdinReadLine, EOFError:
  169. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  170. setResult(a, "")
  171. else:
  172. setResult(a, stdin.readLine())
  173. cbexc stdinReadAll, EOFError:
  174. if defined(nimsuggest) or graph.config.cmd == cmdCheck:
  175. setResult(a, "")
  176. else:
  177. setResult(a, stdin.readAll())
  178. proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
  179. idgen: IdGenerator;
  180. freshDefines=true; conf: ConfigRef, stream: PLLStream) =
  181. let oldSymbolFiles = conf.symbolFiles
  182. conf.symbolFiles = disabledSf
  183. let graph = newModuleGraph(cache, conf)
  184. connectPipelineCallbacks(graph)
  185. if freshDefines: initDefines(conf.symbols)
  186. defineSymbol(conf.symbols, "nimscript")
  187. defineSymbol(conf.symbols, "nimconfig")
  188. conf.searchPaths.add(conf.libpath)
  189. let oldGlobalOptions = conf.globalOptions
  190. let oldSelectedGC = conf.selectedGC
  191. unregisterArcOrc(conf)
  192. conf.globalOptions.excl optOwnedRefs
  193. conf.selectedGC = gcUnselected
  194. var m = graph.makeModule(scriptName)
  195. incl(m.flags, sfMainModule)
  196. var vm = setupVM(m, cache, scriptName.string, graph, idgen)
  197. graph.vm = vm
  198. graph.setPipeLinePass(EvalPass)
  199. graph.compilePipelineSystemModule()
  200. discard graph.processPipelineModule(m, vm.idgen, stream)
  201. # watch out, "newruntime" can be set within NimScript itself and then we need
  202. # to remember this:
  203. if conf.selectedGC == gcUnselected:
  204. conf.selectedGC = oldSelectedGC
  205. if optOwnedRefs in oldGlobalOptions:
  206. conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
  207. defineSymbol(conf.symbols, "nimv2")
  208. if conf.selectedGC in {gcArc, gcOrc, gcAtomicArc}:
  209. conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
  210. defineSymbol(conf.symbols, "nimv2")
  211. defineSymbol(conf.symbols, "gcdestructors")
  212. defineSymbol(conf.symbols, "nimSeqsV2")
  213. case conf.selectedGC
  214. of gcArc:
  215. defineSymbol(conf.symbols, "gcarc")
  216. of gcOrc:
  217. defineSymbol(conf.symbols, "gcorc")
  218. of gcAtomicArc:
  219. defineSymbol(conf.symbols, "gcatomicarc")
  220. else:
  221. raiseAssert "unreachable"
  222. # ensure we load 'system.nim' again for the real non-config stuff!
  223. resetSystemArtifacts(graph)
  224. # do not remove the defined symbols
  225. #initDefines()
  226. undefSymbol(conf.symbols, "nimscript")
  227. undefSymbol(conf.symbols, "nimconfig")
  228. conf.symbolFiles = oldSymbolFiles