diff options
-rw-r--r-- | compiler/commands.nim | 2 | ||||
-rw-r--r-- | compiler/main.nim | 3 | ||||
-rw-r--r-- | compiler/modules.nim | 20 | ||||
-rw-r--r-- | compiler/nim.nim | 9 | ||||
-rw-r--r-- | compiler/options.nim | 6 | ||||
-rw-r--r-- | compiler/scriptconfig.nim | 119 | ||||
-rw-r--r-- | compiler/vm.nim | 4 | ||||
-rw-r--r-- | compiler/vmhooks.nim | 12 | ||||
-rw-r--r-- | lib/system.nim | 108 | ||||
-rw-r--r-- | lib/system/nimscript.nim | 152 | ||||
-rw-r--r-- | lib/system/sysio.nim | 11 | ||||
-rw-r--r-- | tests/newconfig/tfoo.nim | 7 | ||||
-rw-r--r-- | tests/newconfig/tfoo.nims | 14 |
13 files changed, 398 insertions, 69 deletions
diff --git a/compiler/commands.nim b/compiler/commands.nim index 7a908b270..fc28577aa 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -641,7 +641,7 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) = proc processArgument*(pass: TCmdLinePass; p: OptParser; argsCount: var int): bool = if argsCount == 0: - options.command = p.key + if pass != passCmd2: options.command = p.key else: if pass == passCmd1: options.commandArgs.add p.key if argsCount == 1: diff --git a/compiler/main.nim b/compiler/main.nim index 47fae7fa7..014605cc9 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -116,7 +116,7 @@ proc interactivePasses = #incl(gGlobalOptions, optSafeCode) #setTarget(osNimrodVM, cpuNimrodVM) initDefines() - defineSymbol("nimrodvm") + defineSymbol("nimscript") when hasFFI: defineSymbol("nimffi") registerPass(verbosePass) registerPass(semPass) @@ -356,6 +356,7 @@ proc mainCommand* = gGlobalOptions.incl(optCaasEnabled) msgs.gErrorMax = high(int) # do not stop after first error serve(mainCommand) + of "nop": discard else: rawMessage(errInvalidCommandX, command) diff --git a/compiler/modules.nim b/compiler/modules.nim index 2d0267c93..ad68e6315 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -85,6 +85,15 @@ proc resetAllModules* = resetPackageCache() # for m in cgenModules(): echo "CGEN MODULE FOUND" +proc resetAllModulesHard* = + resetPackageCache() + gCompiledModules.setLen 0 + gMemCacheData.setLen 0 + magicsys.resetSysTypes() + # XXX + #gOwners = @[] + #rangeDestructorProc = nil + proc checkDepMem(fileIdx: int32): TNeedRecompile = template markDirty = resetModule(fileIdx) @@ -205,9 +214,8 @@ proc compileProject*(projectFileIdx = -1'i32) = compileSystemModule() discard compileModule(projectFile, {sfMainModule}) -var stdinModule: PSym -proc makeStdinModule*(): PSym = - if stdinModule == nil: - stdinModule = newModule(fileInfoIdx"stdin") - stdinModule.id = getID() - result = stdinModule +proc makeModule*(filename: string): PSym = + result = newModule(fileInfoIdx filename) + result.id = getID() + +proc makeStdinModule*(): PSym = makeModule"stdin" diff --git a/compiler/nim.nim b/compiler/nim.nim index ce9028d53..51f4cae92 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2013 Andreas Rumpf +# (c) Copyright 2015 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -16,7 +16,7 @@ when defined(gcc) and defined(windows): import commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, extccomp, strutils, os, osproc, platform, main, parseopt, service, - nodejs + nodejs, scriptconfig when hasTinyCBackend: import tccgen @@ -54,6 +54,11 @@ proc handleCmdLine() = else: gProjectPath = getCurrentDir() loadConfigs(DefaultConfig) # load all config files + let scriptFile = gProjectFull.changeFileExt("nims") + if fileExists(scriptFile): + runNimScript(scriptFile) + # 'nim foo.nims' means to just run the NimScript file and do nothing more: + if scriptFile == gProjectFull: return # now process command line arguments again, because some options in the # command line can overwite the config file's settings extccomp.initVars() diff --git a/compiler/options.nim b/compiler/options.nim index af1e21e60..adf2017d6 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -210,7 +210,7 @@ proc removeTrailingDirSep*(path: string): string = else: result = path -proc getGeneratedPath: string = +proc getNimcacheDir*: string = result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / genSubDir @@ -266,7 +266,7 @@ proc toGeneratedFile*(path, ext: string): string = ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" var (head, tail) = splitPath(path) #if len(head) > 0: head = shortenDir(head & dirSep) - result = joinPath([getGeneratedPath(), changeFileExt(tail, ext)]) + result = joinPath([getNimcacheDir(), changeFileExt(tail, ext)]) #echo "toGeneratedFile(", path, ", ", ext, ") = ", result when noTimeMachine: @@ -294,7 +294,7 @@ when noTimeMachine: proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = var (head, tail) = splitPath(f) #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep)) - var subdir = getGeneratedPath() # / head + var subdir = getNimcacheDir() # / head if createSubDir: try: createDir(subdir) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim new file mode 100644 index 000000000..1e4fc25af --- /dev/null +++ b/compiler/scriptconfig.nim @@ -0,0 +1,119 @@ +# +# +# 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, passes, passaux, condsyms, + options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, + os, times + +# we support 'cmpIgnoreStyle' natively for efficiency: +from strutils import cmpIgnoreStyle + +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; scriptName: string): PEvalContext = + result = newCtx(module) + result.mode = emRepl + registerAdditionalOps(result) + + # 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 cbos(name, body) {.dirty.} = + result.registerCallback "stdlib.system." & astToStr(name), + proc (a: VmArgs) = + try: + body + except OSError: + errorMsg = getCurrentExceptionMsg() + + # Idea: Treat link to file as a file, but ignore link to directory to prevent + # endless recursions out of the box. + cbos listFiles: + listDirs(a, {pcFile, pcLinkToFile}) + cbos listDirs: + listDirs(a, {pcDir}) + cbos removeDir: + os.removeDir getString(a, 0) + cbos removeFile: + os.removeFile getString(a, 0) + cbos createDir: + os.createDir getString(a, 0) + cbos getOsError: + setResult(a, errorMsg) + cbos setCurrentDir: + os.setCurrentDir getString(a, 0) + cbos getCurrentDir: + setResult(a, os.getCurrentDir()) + cbos moveFile: + os.moveFile(getString(a, 0), getString(a, 1)) + cbos getLastModificationTime: + setResult(a, toSeconds(getLastModificationTime(getString(a, 0)))) + + cbconf thisDir: + setResult(a, vthisDir) + cbconf put: + options.setConfigVar(getString(a, 0), getString(a, 1)) + cbconf get: + setResult(a, options.getConfigVar(a.getString 0)) + cbconf exists: + setResult(a, options.existsConfigVar(a.getString 0)) + cbconf nimcacheDir: + setResult(a, options.getNimcacheDir()) + 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 setCommand: + options.command = a.getString 0 + cbconf getCommand: + setResult(a, options.command) + cbconf switch: + processSwitch(a.getString 0, a.getString 1, passPP, unknownLineInfo()) + + +proc runNimScript*(scriptName: string) = + passes.gIncludeFile = includeModule + passes.gImportModule = importModule + initDefines() + + defineSymbol("nimscript") + defineSymbol("nimconfig") + registerPass(semPass) + registerPass(evalPass) + + appendStr(searchPaths, options.libpath) + + var m = makeModule(scriptName) + incl(m.flags, sfMainModule) + vm.globalCtx = setupVM(m, scriptName) + + compileSystemModule() + processModule(m, llStreamOpen(scriptName, fmRead), nil) + + # ensure we load 'system.nim' again for the real non-config stuff! + resetAllModulesHard() + vm.globalCtx = nil + initDefines() diff --git a/compiler/vm.nim b/compiler/vm.nim index b1d71d73b..57ed8397c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -1407,7 +1407,7 @@ include vmops # storing&loading the 'globals' environment to get what a component system # requires. var - globalCtx: PCtx + globalCtx*: PCtx proc setupGlobalCtx(module: PSym) = if globalCtx.isNil: @@ -1516,7 +1516,7 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode = # return value: tos.slots[0].kind = rkNode tos.slots[0].node = newNodeIT(nkEmpty, n.info, sym.typ.sons[0]) - + # setup parameters: for i in 1.. <sym.typ.len: tos.slots[i] = setupMacroParam(n.sons[i], sym.typ.sons[i]) diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim index 6ec5f6044..5dd27feda 100644 --- a/compiler/vmhooks.nim +++ b/compiler/vmhooks.nim @@ -17,7 +17,7 @@ template setX(k, field) {.immediate, dirty.} = proc setResult*(a: VmArgs; v: BiggestInt) = setX(rkInt, intVal) proc setResult*(a: VmArgs; v: BiggestFloat) = setX(rkFloat, floatVal) -proc setResult*(a: VmArgs; v: bool) = +proc setResult*(a: VmArgs; v: bool) = let v = v.ord setX(rkInt, intVal) @@ -30,6 +30,16 @@ proc setResult*(a: VmArgs; v: string) = s[a.ra].node = newNode(nkStrLit) s[a.ra].node.strVal = v +proc setResult*(a: VmArgs; v: seq[string]) = + var s: seq[TFullReg] + move(s, cast[seq[TFullReg]](a.slots)) + if s[a.ra].kind != rkNode: + myreset(s[a.ra]) + s[a.ra].kind = rkNode + var n = newNode(nkBracket) + for x in v: n.add newStrNode(nkStrLit, x) + s[a.ra].node = n + template getX(k, field) {.immediate, dirty.} = doAssert i < a.rc-1 let s = cast[seq[TFullReg]](a.slots) diff --git a/lib/system.nim b/lib/system.nim index 7dae074f3..b2660b1f4 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -190,9 +190,9 @@ proc new*(T: typedesc): auto = ## When ``T`` is a ref type then the resulting type will be ``T``, ## otherwise it will be ``ref T``. when (T is ref): - var r: T + var r: T else: - var r: ref T + var r: ref T new(r) return r @@ -347,7 +347,7 @@ const include "system/inclrtl" -const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \ +const NoFakeVars* = defined(nimscript) ## true if the backend doesn't support \ ## "fake variables" like 'var EBADF {.importc.}: cint'. const ArrayDummySize = when defined(cpu16): 10_000 else: 100_000_000 @@ -365,7 +365,7 @@ when not defined(JS): data: UncheckedCharArray NimString = ptr NimStringDesc -when not defined(JS) and not defined(NimrodVM): +when not defined(JS) and not defined(nimscript): template space(s: PGenericSeq): int {.dirty.} = s.reserved and not seqShallowFlag @@ -1260,11 +1260,11 @@ template sysAssert(cond: bool, msg: string) = echo "[SYSASSERT] ", msg quit 1 -const hasAlloc = hostOS != "standalone" or not defined(nogc) +const hasAlloc = (hostOS != "standalone" or not defined(nogc)) and not defined(nimscript) -when not defined(JS) and not defined(nimrodVm) and hostOS != "standalone": +when not defined(JS) and not defined(nimscript) and hostOS != "standalone": include "system/cgprocs" -when not defined(JS) and not defined(nimrodVm) and hasAlloc: +when not defined(JS) and not defined(nimscript) and hasAlloc: proc setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline, benign.} proc addChar(s: NimString, c: char): NimString {.compilerProc, benign.} @@ -1445,7 +1445,7 @@ proc substr*(s: string, first, last: int): string {. ## is used instead: This means ``substr`` can also be used to `cut`:idx: ## or `limit`:idx: a string's length. -when not defined(nimrodVM): +when not defined(nimscript): proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.} ## overwrites the contents of the memory at ``p`` with the value 0. ## Exactly ``size`` bytes will be overwritten. Like any procedure @@ -1607,7 +1607,7 @@ proc `$`*(x: int64): string {.magic: "Int64ToStr", noSideEffect.} ## The stringify operator for an integer argument. Returns `x` ## converted to a decimal string. -when not defined(NimrodVM): +when not defined(nimscript): when not defined(JS) and hasAlloc: proc `$` *(x: uint64): string {.noSideEffect.} ## The stringify operator for an unsigned integer argument. Returns `x` @@ -1675,7 +1675,7 @@ const # GC interface: -when not defined(nimrodVM) and hasAlloc: +when not defined(nimscript) and hasAlloc: proc getOccupiedMem*(): int {.rtl.} ## returns the number of bytes that are owned by the process and hold data. @@ -2016,7 +2016,7 @@ proc `&` *[T](x: T, y: seq[T]): seq[T] {.noSideEffect.} = for i in 0..y.len-1: result[i+1] = y[i] -when not defined(NimrodVM): +when not defined(nimscript): when not defined(JS): proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} = result = cast[pointer](x) @@ -2235,7 +2235,7 @@ when false: # ----------------- GC interface --------------------------------------------- -when not defined(nimrodVM) and hasAlloc: +when not defined(nimscript) and hasAlloc: proc GC_disable*() {.rtl, inl, benign.} ## disables the GC. If called n-times, n calls to `GC_enable` are needed to ## reactivate the GC. Note that in most circumstances one should only disable @@ -2457,10 +2457,10 @@ else: if x < 0: -x else: x {.pop.} -when not defined(JS): #and not defined(NimrodVM): +when not defined(JS): #and not defined(nimscript): {.push stack_trace: off, profiler:off.} - when not defined(NimrodVM) and not defined(nogc): + when not defined(nimscript) and not defined(nogc): proc initGC() when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc): proc initAllocator() {.inline.} @@ -2488,13 +2488,19 @@ when not defined(JS): #and not defined(NimrodVM): strDesc.kind = tyString strDesc.flags = {ntfAcyclic} - include "system/ansi_c" + when not defined(nimscript): + include "system/ansi_c" - proc cmp(x, y: string): int = - result = int(c_strcmp(x, y)) + proc cmp(x, y: string): int = + result = int(c_strcmp(x, y)) + else: + proc cmp(x, y: string): int = + if x < y: result = -1 + elif x > y: result = 1 + else: result = 0 const pccHack = if defined(pcc): "_" else: "" # Hack for PCC - when not defined(NimrodVM): + when not defined(nimscript): when defined(windows): # work-around C's sucking abstraction: # BUGFIX: stdin and stdout should be binary files! @@ -2536,14 +2542,15 @@ when not defined(JS): #and not defined(NimrodVM): {.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].} - # text file handling: - var - stdin* {.importc: "stdin", header: "<stdio.h>".}: File - ## The standard input stream. - stdout* {.importc: "stdout", header: "<stdio.h>".}: File - ## The standard output stream. - stderr* {.importc: "stderr", header: "<stdio.h>".}: File - ## The standard error stream. + when not defined(nimscript): + # text file handling: + var + stdin* {.importc: "stdin", header: "<stdio.h>".}: File + ## The standard input stream. + stdout* {.importc: "stdout", header: "<stdio.h>".}: File + ## The standard output stream. + stderr* {.importc: "stderr", header: "<stdio.h>".}: File + ## The standard error stream. when defined(useStdoutAsStdmsg): template stdmsg*: File = stdout @@ -2738,7 +2745,7 @@ when not defined(JS): #and not defined(NimrodVM): inc(i) dealloc(a) - when not defined(NimrodVM): + when not defined(nimscript): proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, benign.} ## atomic increment of `memLoc`. Returns the value after the operation. @@ -2749,27 +2756,27 @@ when not defined(JS): #and not defined(NimrodVM): include "system/atomics" - type - PSafePoint = ptr TSafePoint - TSafePoint {.compilerproc, final.} = object - prev: PSafePoint # points to next safe point ON THE STACK - status: int - context: C_JmpBuf - hasRaiseAction: bool - raiseAction: proc (e: ref Exception): bool {.closure.} - SafePoint = TSafePoint -# {.deprecated: [TSafePoint: SafePoint].} + type + PSafePoint = ptr TSafePoint + TSafePoint {.compilerproc, final.} = object + prev: PSafePoint # points to next safe point ON THE STACK + status: int + context: C_JmpBuf + hasRaiseAction: bool + raiseAction: proc (e: ref Exception): bool {.closure.} + SafePoint = TSafePoint + # {.deprecated: [TSafePoint: SafePoint].} when declared(initAllocator): initAllocator() when hasThreadSupport: include "system/syslocks" when hostOS != "standalone": include "system/threads" - elif not defined(nogc) and not defined(NimrodVM): + elif not defined(nogc) and not defined(nimscript): when not defined(useNimRtl) and not defined(createNimRtl): initStackBottom() when declared(initGC): initGC() - when not defined(NimrodVM): + when not defined(nimscript): proc setControlCHook*(hook: proc () {.noconv.} not nil) ## allows you to override the behaviour of your application when CTRL+C ## is pressed. Only one such hook is supported. @@ -2798,9 +2805,9 @@ when not defined(JS): #and not defined(NimrodVM): {.pop.} # stack trace {.pop.} # stack trace - when hostOS != "standalone" and not defined(NimrodVM): + when hostOS != "standalone" and not defined(nimscript): include "system/dyncalls" - when not defined(NimrodVM): + when not defined(nimscript): include "system/sets" when defined(gogc): @@ -2875,11 +2882,11 @@ when not defined(JS): #and not defined(NimrodVM): var res = TaintedString(newStringOfCap(80)) while f.readLine(res): yield res - when not defined(NimrodVM) and hasAlloc: + when not defined(nimscript) and hasAlloc: include "system/assign" include "system/repr" - when hostOS != "standalone" and not defined(NimrodVM): + when hostOS != "standalone" and not defined(nimscript): proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} = ## retrieves the current exception; if there is none, nil is returned. result = currException @@ -2907,14 +2914,14 @@ when not defined(JS): #and not defined(NimrodVM): currException = exc {.push stack_trace: off, profiler:off.} - when defined(endb) and not defined(NimrodVM): + when defined(endb) and not defined(nimscript): include "system/debugger" when defined(profiler) or defined(memProfiler): include "system/profiler" {.pop.} # stacktrace - when not defined(NimrodVM): + when not defined(nimscript): proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} ## Hints the optimizer that `val` is likely going to be true. ## @@ -2992,7 +2999,7 @@ elif defined(JS): when defined(JS): include "system/jssys" include "system/reprjs" - elif defined(NimrodVM): + elif defined(nimscript): proc cmp(x, y: string): int = if x == y: return 0 if x < y: return -1 @@ -3305,7 +3312,7 @@ proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} = ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not ## perform deep copies of `s`. This is only useful for optimization ## purposes. - when not defined(JS) and not defined(NimrodVM): + when not defined(JS) and not defined(nimscript): var s = cast[PGenericSeq](s) s.reserved = s.reserved or seqShallowFlag @@ -3313,7 +3320,7 @@ proc shallow*(s: var string) {.noSideEffect, inline.} = ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not ## perform deep copies of `s`. This is only useful for optimization ## purposes. - when not defined(JS) and not defined(NimrodVM): + when not defined(JS) and not defined(nimscript): var s = cast[PGenericSeq](s) s.reserved = s.reserved or seqShallowFlag @@ -3402,7 +3409,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} = ## # -> B is 1 discard -when hasAlloc and not defined(NimrodVM) and not defined(JS): +when hasAlloc and not defined(nimscript) and not defined(JS): proc deepCopy*[T](x: var T, y: T) {.noSideEffect, magic: "DeepCopy".} = ## performs a deep copy of `x`. This is also used by the code generator ## for the implementation of ``spawn``. @@ -3444,3 +3451,6 @@ proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} = discard {.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.} + +when defined(nimconfig): + include "system/nimscript" diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim new file mode 100644 index 000000000..6f5977869 --- /dev/null +++ b/lib/system/nimscript.nim @@ -0,0 +1,152 @@ +# +# +# Nim's Runtime Library +# (c) Copyright 2015 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + + +# Nim's configuration system now uses Nim for scripting. This module provides +# a few things that are required for this to work. + +template builtin = discard + +proc listDirs*(dir: string): seq[string] = builtin +proc listFiles*(dir: string): seq[string] = builtin + +proc removeDir(dir: string) = builtin +proc removeFile(dir: string) = builtin +proc moveFile(src, dest: string) = builtin +proc createDir(dir: string) = builtin +proc getOsError: string = builtin +proc setCurrentDir(dir: string) = builtin +proc getCurrentDir(): string = builtin +proc paramStr*(i: int): string = builtin +proc paramCount*(): int = builtin + +proc switch*(key: string, val="") = builtin +proc getCommand*(): string = builtin +proc setCommand*(cmd: string) = builtin +proc cmpIgnoreStyle(a, b: string): int = builtin + +proc strip(s: string): string = + var i = 0 + while s[i] in {' ', '\c', '\L'}: inc i + result = s.substr(i) + +template `--`*(key, val: untyped) = switch(astToStr(key), strip astToStr(val)) +template `--`*(key: untyped) = switch(astToStr(key), "") + +type + ScriptMode* {.pure.} = enum + Silent, + Verbose, + Whatif + +var + mode*: ScriptMode ## Set this to influence how mkDir, rmDir, rmFile etc. + ## behave + +template checkOsError = + let err = getOsError() + if err.len > 0: raise newException(OSError, err) + +template log(msg: string, body: untyped) = + if mode == ScriptMode.Verbose or mode == ScriptMode.Whatif: + echo "[NimScript] ", msg + if mode != ScriptMode.WhatIf: + body + +proc rmDir*(dir: string) {.raises: [OSError].} = + log "rmDir: " & dir: + removeDir dir + checkOsError() + +proc rmFile*(dir: string) {.raises: [OSError].} = + log "rmFile: " & dir: + removeFile dir + checkOsError() + +proc mkDir*(dir: string) {.raises: [OSError].} = + log "mkDir: " & dir: + createDir dir + checkOsError() + +proc mvFile*(`from`, to: string) {.raises: [OSError].} = + log "mvFile: " & `from` & ", " & to: + moveFile `from`, to + checkOsError() + +proc exec*(command: string, input = "", cache = "") = + ## Executes an external process. + log "exec: " & command: + echo staticExec(command, input, cache) + +proc put*(key, value: string) = + ## Sets a configuration 'key' like 'gcc.options.always' to its value. + builtin + +proc get*(key: string): string = + ## Retrieves a configuration 'key' like 'gcc.options.always'. + builtin + +proc exists*(key: string): bool = + ## Checks for the existance of a configuration 'key' + ## like 'gcc.options.always'. + builtin + +proc nimcacheDir*(): string = + ## Retrieves the location of 'nimcache'. + builtin + +proc thisDir*(): string = + ## Retrieves the location of the current ``nims`` script file. + builtin + +proc cd*(dir: string) {.raises: [OSError].} = + ## Changes the current directory. + ## + ## The change is permanent for the rest of the execution, since this is just + ## a shortcut for `os.setCurrentDir() + ## <http://nim-lang.org/os.html#setCurrentDir,string>`_ . Use the `withDir() + ## <#withDir>`_ template if you want to perform a temporary change only. + setCurrentDir(dir) + checkOsError() + +template withDir*(dir: string; body: untyped): untyped = + ## Changes the current directory temporarily. + ## + ## If you need a permanent change, use the `cd() <#cd>`_ proc. Usage example: + ## + ## .. code-block:: nimrod + ## withDir "foo": + ## # inside foo + ## #back to last dir + var curDir = getCurrentDir() + try: + cd(dir) + body + finally: + cd(curDir) + +template `==?`(a, b: string): bool = cmpIgnoreStyle(a, b) == 0 + +proc writeTask(name, desc: string) = + if desc.len > 0: + var spaces = " " + for i in 0 ..< 20 - name.len: spaces.add ' ' + echo name, spaces, desc + +template task*(name: untyped; description: string; body: untyped): untyped = + ## Defines a task. Hidden tasks are supported via an empty description. + proc `name Task`() = body + + let cmd = getCommand() + if cmd.len == 0 or cmd ==? "help" or cmd == "nop": + setCommand "nop" + writeTask(astToStr(name), description) + elif cmd ==? astToStr(name): + setCommand "nop" + `name Task`() diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim index 5464ee126..b3316920e 100644 --- a/lib/system/sysio.nim +++ b/lib/system/sysio.nim @@ -182,7 +182,10 @@ proc readAllFile(file: File): string = proc readAll(file: File): TaintedString = # Separate handling needed because we need to buffer when we # don't know the overall length of the File. - let len = if file != stdin: rawFileSize(file) else: -1 + when declared(stdin): + let len = if file != stdin: rawFileSize(file) else: -1 + else: + let len = rawFileSize(file) if len > 0: result = readAllFile(file, len).TaintedString else: @@ -216,9 +219,9 @@ proc writeLine[Ty](f: File, x: varargs[Ty, `$`]) = for i in items(x): write(f, i) write(f, "\n") - -proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x) -proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n") +when declared(stdout): + proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x) + proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n") # interface to the C procs: diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim new file mode 100644 index 000000000..0ace7c88a --- /dev/null +++ b/tests/newconfig/tfoo.nim @@ -0,0 +1,7 @@ +discard """ + cmd: "nim default $file" + output: '''hello world!''' + msg: '''[NimScript] exec: gcc -v''' +""" + +echo "hello world!" diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims new file mode 100644 index 000000000..90205cddb --- /dev/null +++ b/tests/newconfig/tfoo.nims @@ -0,0 +1,14 @@ + +mode = ScriptMode.Whatif + +exec "gcc -v" + +--forceBuild + +task listDirs, "lists every subdirectory": + for x in listDirs("."): + echo "DIR ", x + +task default, "default target": + setCommand "c" + |