#
#
# The Nim Compiler
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements the new configuration system for Nim. Uses Nim as a scripting
## language.
import
ast, modules, idents, passes, condsyms,
options, sem, llstream, vm, vmdef, commands,
os, times, osproc, wordrecg, strtabs, modulegraphs,
pathutils
when defined(nimPreviewSlimSystem):
import std/syncio
# we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle, contains
proc listDirs(a: VmArgs, filter: set[PathComponent]) =
let dir = getString(a, 0)
var result: seq[string] = @[]
for kind, path in walkDir(dir):
if kind in filter: result.add path
setResult(a, result)
proc setupVM*(module: PSym; cache: IdentCache; scriptName: string;
graph: ModuleGraph; idgen: IdGenerator): PEvalContext =
# For Nimble we need to export 'setupVM'.
result = newCtx(module, cache, graph, idgen)
result.mode = emRepl
registerAdditionalOps(result)
let conf = graph.config
# captured vars:
var errorMsg: string
var vthisDir = scriptName.splitFile.dir
template cbconf(name, body) {.dirty.} =
result.registerCallback "stdlib.system." & astToStr(name),
proc (a: VmArgs) =
body
template cbexc(name, exc, body) {.dirty.} =
result.registerCallback "stdlib.system." & astToStr(name),
proc (a: VmArgs) =
errorMsg = ""
try:
body
except exc:
errorMsg = getCurrentExceptionMsg()
template cbos(name, body) {.dirty.} =
cbexc(name, OSError, body)
# Idea: Treat link to file as a file, but ignore link to directory to prevent
# endless recursions out of the box.
cbos listFilesImpl:
listDirs(a, {pcFile, pcLinkToFile})
cbos listDirsImpl:
listDirs(a, {pcDir})
cbos removeDir:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
os.removeDir(getString(a, 0), getBool(a, 1))
cbos removeFile:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
os.removeFile getString(a, 0)
cbos createDir:
os.createDir getString(a, 0)
result.registerCallback "stdlib.system.getError",
proc (a: VmArgs) = setResult(a, errorMsg)
cbos setCurrentDir:
os.setCurrentDir getString(a, 0)
cbos getCurrentDir:
setResult(a, os.getCurrentDir())
cbos moveFile:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
os.moveFile(getString(a, 0), getString(a, 1))
cbos moveDir:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
os.moveDir(getString(a, 0), getString(a, 1))
cbos copyFile:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
os.copyFile(getString(a, 0), getString(a, 1))
cbos copyDir:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
os.copyDir(getString(a, 0), getString(a, 1))
cbos getLastModificationTime:
setResult(a, getLastModificationTime(getString(a, 0)).toUnix)
cbos findExe:
setResult(a, os.findExe(getString(a, 0)))
cbos rawExec:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
discard
else:
setResult(a, osproc.execCmd getString(a, 0))
cbconf getEnv:
setResult(a, os.getEnv(a.getString 0, a.getString 1))
cbconf existsEnv:
setResult(a, os.existsEnv(a.getString 0))
cbconf putEnv:
os.putEnv(a.getString 0, a.getString 1)
cbconf delEnv:
os.delEnv(a.getString 0)
cbconf dirExists:
setResult(a, os.dirExists(a.getString 0))
cbconf fileExists:
setResult(a, os.fileExists(a.getString 0))
cbconf projectName:
setResult(a, conf.projectName)
cbconf projectDir:
setResult(a, conf.projectPath.string)
cbconf projectPath:
setResult(a, conf.projectFull.string)
cbconf thisDir:
setResult(a, vthisDir)
cbconf put:
options.setConfigVar(conf, getString(a, 0), getString(a, 1))
cbconf get:
setResult(a, options.getConfigVar(conf, a.getString 0))
cbconf exists:
setResult(a, options.existsConfigVar(conf, a.getString 0))
cbconf nimcacheDir:
setResult(a, options.getNimcacheDir(conf).string)
cbconf paramStr:
setResult(a, os.paramStr(int a.getInt 0))
cbconf paramCount:
setResult(a, os.paramCount())
cbconf cmpIgnoreStyle:
setResult(a, strutils.cmpIgnoreStyle(a.getString 0, a.getString 1))
cbconf cmpIgnoreCase:
setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
cbconf setCommand:
conf.setCommandEarly(a.getString 0)
let arg = a.getString 1
incl(conf.globalOptions, optWasNimscript)
if arg.len > 0: setFromProjectName(conf, arg)
cbconf getCommand:
setResult(a, conf.command)
cbconf switch:
processSwitch(a.getString 0, a.getString 1, passPP, module.info, conf)
cbconf hintImpl:
processSpecificNote(a.getString 0, wHint, passPP, module.info,
a.getString 1, conf)
cbconf warningImpl:
processSpecificNote(a.getString 0, wWarning, passPP, module.info,
a.getString 1, conf)
cbconf patchFile:
let key = a.getString(0) & "_" & a.getString(1)
var val = a.getString(2).addFileExt(NimExt)
if {'$', '~'} in val:
val = pathSubs(conf, val, vthisDir)
elif not isAbsolute(val):
val = vthisDir / val
conf.moduleOverrides[key] = val
cbconf selfExe:
setResult(a, os.getAppFilename())
cbconf cppDefine:
options.cppDefine(conf, a.getString(0))
cbexc stdinReadLine, EOFError:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
setResult(a, "")
else:
setResult(a, stdin.readLine())
cbexc stdinReadAll, EOFError:
if defined(nimsuggest) or graph.config.cmd == cmdCheck:
setResult(a, "")
else:
setResult(a, stdin.readAll())
proc runNimScript*(cache: IdentCache; scriptName: AbsoluteFile;
idgen: IdGenerator;
freshDefines=true; conf: ConfigRef, stream: PLLStream) =
let oldSymbolFiles = conf.symbolFiles
conf.symbolFiles = disabledSf
let graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
if freshDefines: initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig")
registerPass(graph, semPass)
registerPass(graph, evalPass)
conf.searchPaths.add(conf.libpath)
let oldGlobalOptions = conf.globalOptions
let oldSelectedGC = conf.selectedGC
undefSymbol(conf.symbols, "nimv2")
conf.globalOptions.excl {optTinyRtti, optOwnedRefs, optSeqDestructors}
conf.selectedGC = gcUnselected
var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule)
var vm = setupVM(m, cache, scriptName.string, graph, idgen)
graph.vm = vm
graph.compileSystemModule()
discard graph.processModule(m, vm.idgen, stream)
# watch out, "newruntime" can be set within NimScript itself and then we need
# to remember this:
if conf.selectedGC == gcUnselected:
conf.selectedGC = oldSelectedGC
if optOwnedRefs in oldGlobalOptions:
conf.globalOptions.incl {optTinyRtti, optOwnedRefs, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
if conf.selectedGC in {gcArc, gcOrc}:
conf.globalOptions.incl {optTinyRtti, optSeqDestructors}
defineSymbol(conf.symbols, "nimv2")
# ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph)
# do not remove the defined symbols
#initDefines()
undefSymbol(conf.symbols, "nimscript")
undefSymbol(conf.symbols, "nimconfig")
conf.symbolFiles = oldSymbolFiles