scriptconfig.nim 7.5 KB

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