implements experimental new config system based on NimScript

This commit is contained in:
Araq 2015-08-16 13:40:52 +02:00
commit 69b32637b1
13 changed files with 398 additions and 69 deletions

View file

@ -641,7 +641,7 @@ proc processSwitch*(pass: TCmdLinePass; p: OptParser) =
proc processArgument*(pass: TCmdLinePass; p: OptParser; proc processArgument*(pass: TCmdLinePass; p: OptParser;
argsCount: var int): bool = argsCount: var int): bool =
if argsCount == 0: if argsCount == 0:
options.command = p.key if pass != passCmd2: options.command = p.key
else: else:
if pass == passCmd1: options.commandArgs.add p.key if pass == passCmd1: options.commandArgs.add p.key
if argsCount == 1: if argsCount == 1:

View file

@ -116,7 +116,7 @@ proc interactivePasses =
#incl(gGlobalOptions, optSafeCode) #incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM) #setTarget(osNimrodVM, cpuNimrodVM)
initDefines() initDefines()
defineSymbol("nimrodvm") defineSymbol("nimscript")
when hasFFI: defineSymbol("nimffi") when hasFFI: defineSymbol("nimffi")
registerPass(verbosePass) registerPass(verbosePass)
registerPass(semPass) registerPass(semPass)
@ -356,6 +356,7 @@ proc mainCommand* =
gGlobalOptions.incl(optCaasEnabled) gGlobalOptions.incl(optCaasEnabled)
msgs.gErrorMax = high(int) # do not stop after first error msgs.gErrorMax = high(int) # do not stop after first error
serve(mainCommand) serve(mainCommand)
of "nop": discard
else: else:
rawMessage(errInvalidCommandX, command) rawMessage(errInvalidCommandX, command)

View file

@ -85,6 +85,15 @@ proc resetAllModules* =
resetPackageCache() resetPackageCache()
# for m in cgenModules(): echo "CGEN MODULE FOUND" # 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 = proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty = template markDirty =
resetModule(fileIdx) resetModule(fileIdx)
@ -205,9 +214,8 @@ proc compileProject*(projectFileIdx = -1'i32) =
compileSystemModule() compileSystemModule()
discard compileModule(projectFile, {sfMainModule}) discard compileModule(projectFile, {sfMainModule})
var stdinModule: PSym proc makeModule*(filename: string): PSym =
proc makeStdinModule*(): PSym = result = newModule(fileInfoIdx filename)
if stdinModule == nil: result.id = getID()
stdinModule = newModule(fileInfoIdx"stdin")
stdinModule.id = getID() proc makeStdinModule*(): PSym = makeModule"stdin"
result = stdinModule

View file

@ -1,7 +1,7 @@
# #
# #
# The Nim Compiler # The Nim Compiler
# (c) Copyright 2013 Andreas Rumpf # (c) Copyright 2015 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -16,7 +16,7 @@ when defined(gcc) and defined(windows):
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service, extccomp, strutils, os, osproc, platform, main, parseopt, service,
nodejs nodejs, scriptconfig
when hasTinyCBackend: when hasTinyCBackend:
import tccgen import tccgen
@ -54,6 +54,11 @@ proc handleCmdLine() =
else: else:
gProjectPath = getCurrentDir() gProjectPath = getCurrentDir()
loadConfigs(DefaultConfig) # load all config files 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 # now process command line arguments again, because some options in the
# command line can overwite the config file's settings # command line can overwite the config file's settings
extccomp.initVars() extccomp.initVars()

View file

@ -210,7 +210,7 @@ proc removeTrailingDirSep*(path: string): string =
else: else:
result = path result = path
proc getGeneratedPath: string = proc getNimcacheDir*: string =
result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir / result = if nimcacheDir.len > 0: nimcacheDir else: gProjectPath.shortenDir /
genSubDir genSubDir
@ -266,7 +266,7 @@ proc toGeneratedFile*(path, ext: string): string =
## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod" ## converts "/home/a/mymodule.nim", "rod" to "/home/a/nimcache/mymodule.rod"
var (head, tail) = splitPath(path) var (head, tail) = splitPath(path)
#if len(head) > 0: head = shortenDir(head & dirSep) #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 #echo "toGeneratedFile(", path, ", ", ext, ") = ", result
when noTimeMachine: when noTimeMachine:
@ -294,7 +294,7 @@ when noTimeMachine:
proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string = proc completeGeneratedFilePath*(f: string, createSubDir: bool = true): string =
var (head, tail) = splitPath(f) var (head, tail) = splitPath(f)
#if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep)) #if len(head) > 0: head = removeTrailingDirSep(shortenDir(head & dirSep))
var subdir = getGeneratedPath() # / head var subdir = getNimcacheDir() # / head
if createSubDir: if createSubDir:
try: try:
createDir(subdir) createDir(subdir)

119
compiler/scriptconfig.nim Normal file
View file

@ -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()

View file

@ -1407,7 +1407,7 @@ include vmops
# storing&loading the 'globals' environment to get what a component system # storing&loading the 'globals' environment to get what a component system
# requires. # requires.
var var
globalCtx: PCtx globalCtx*: PCtx
proc setupGlobalCtx(module: PSym) = proc setupGlobalCtx(module: PSym) =
if globalCtx.isNil: if globalCtx.isNil:

View file

@ -30,6 +30,16 @@ proc setResult*(a: VmArgs; v: string) =
s[a.ra].node = newNode(nkStrLit) s[a.ra].node = newNode(nkStrLit)
s[a.ra].node.strVal = v 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.} = template getX(k, field) {.immediate, dirty.} =
doAssert i < a.rc-1 doAssert i < a.rc-1
let s = cast[seq[TFullReg]](a.slots) let s = cast[seq[TFullReg]](a.slots)

View file

@ -347,7 +347,7 @@ const
include "system/inclrtl" 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'. ## "fake variables" like 'var EBADF {.importc.}: cint'.
const ArrayDummySize = when defined(cpu16): 10_000 else: 100_000_000 const ArrayDummySize = when defined(cpu16): 10_000 else: 100_000_000
@ -365,7 +365,7 @@ when not defined(JS):
data: UncheckedCharArray data: UncheckedCharArray
NimString = ptr NimStringDesc 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.} = template space(s: PGenericSeq): int {.dirty.} =
s.reserved and not seqShallowFlag s.reserved and not seqShallowFlag
@ -1260,11 +1260,11 @@ template sysAssert(cond: bool, msg: string) =
echo "[SYSASSERT] ", msg echo "[SYSASSERT] ", msg
quit 1 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" 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 setStackBottom(theStackBottom: pointer) {.compilerRtl, noinline, benign.}
proc addChar(s: NimString, c: char): NimString {.compilerProc, 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: ## is used instead: This means ``substr`` can also be used to `cut`:idx:
## or `limit`:idx: a string's length. ## or `limit`:idx: a string's length.
when not defined(nimrodVM): when not defined(nimscript):
proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.} proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.}
## overwrites the contents of the memory at ``p`` with the value 0. ## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure ## 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` ## The stringify operator for an integer argument. Returns `x`
## converted to a decimal string. ## converted to a decimal string.
when not defined(NimrodVM): when not defined(nimscript):
when not defined(JS) and hasAlloc: when not defined(JS) and hasAlloc:
proc `$` *(x: uint64): string {.noSideEffect.} proc `$` *(x: uint64): string {.noSideEffect.}
## The stringify operator for an unsigned integer argument. Returns `x` ## The stringify operator for an unsigned integer argument. Returns `x`
@ -1675,7 +1675,7 @@ const
# GC interface: # GC interface:
when not defined(nimrodVM) and hasAlloc: when not defined(nimscript) and hasAlloc:
proc getOccupiedMem*(): int {.rtl.} proc getOccupiedMem*(): int {.rtl.}
## returns the number of bytes that are owned by the process and hold data. ## 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: for i in 0..y.len-1:
result[i+1] = y[i] result[i+1] = y[i]
when not defined(NimrodVM): when not defined(nimscript):
when not defined(JS): when not defined(JS):
proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} = proc seqToPtr[T](x: seq[T]): pointer {.inline, nosideeffect.} =
result = cast[pointer](x) result = cast[pointer](x)
@ -2235,7 +2235,7 @@ when false:
# ----------------- GC interface --------------------------------------------- # ----------------- GC interface ---------------------------------------------
when not defined(nimrodVM) and hasAlloc: when not defined(nimscript) and hasAlloc:
proc GC_disable*() {.rtl, inl, benign.} proc GC_disable*() {.rtl, inl, benign.}
## disables the GC. If called n-times, n calls to `GC_enable` are needed to ## 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 ## reactivate the GC. Note that in most circumstances one should only disable
@ -2457,10 +2457,10 @@ else:
if x < 0: -x else: x if x < 0: -x else: x
{.pop.} {.pop.}
when not defined(JS): #and not defined(NimrodVM): when not defined(JS): #and not defined(nimscript):
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when not defined(NimrodVM) and not defined(nogc): when not defined(nimscript) and not defined(nogc):
proc initGC() proc initGC()
when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc): when not defined(boehmgc) and not defined(useMalloc) and not defined(gogc):
proc initAllocator() {.inline.} proc initAllocator() {.inline.}
@ -2488,13 +2488,19 @@ when not defined(JS): #and not defined(NimrodVM):
strDesc.kind = tyString strDesc.kind = tyString
strDesc.flags = {ntfAcyclic} strDesc.flags = {ntfAcyclic}
when not defined(nimscript):
include "system/ansi_c" include "system/ansi_c"
proc cmp(x, y: string): int = proc cmp(x, y: string): int =
result = int(c_strcmp(x, y)) 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 const pccHack = if defined(pcc): "_" else: "" # Hack for PCC
when not defined(NimrodVM): when not defined(nimscript):
when defined(windows): when defined(windows):
# work-around C's sucking abstraction: # work-around C's sucking abstraction:
# BUGFIX: stdin and stdout should be binary files! # BUGFIX: stdin and stdout should be binary files!
@ -2536,6 +2542,7 @@ when not defined(JS): #and not defined(NimrodVM):
{.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].} {.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].}
when not defined(nimscript):
# text file handling: # text file handling:
var var
stdin* {.importc: "stdin", header: "<stdio.h>".}: File stdin* {.importc: "stdin", header: "<stdio.h>".}: File
@ -2738,7 +2745,7 @@ when not defined(JS): #and not defined(NimrodVM):
inc(i) inc(i)
dealloc(a) dealloc(a)
when not defined(NimrodVM): when not defined(nimscript):
proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, proc atomicInc*(memLoc: var int, x: int = 1): int {.inline,
discardable, benign.} discardable, benign.}
## atomic increment of `memLoc`. Returns the value after the operation. ## atomic increment of `memLoc`. Returns the value after the operation.
@ -2765,11 +2772,11 @@ when not defined(JS): #and not defined(NimrodVM):
when hasThreadSupport: when hasThreadSupport:
include "system/syslocks" include "system/syslocks"
when hostOS != "standalone": include "system/threads" 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 not defined(useNimRtl) and not defined(createNimRtl): initStackBottom()
when declared(initGC): initGC() when declared(initGC): initGC()
when not defined(NimrodVM): when not defined(nimscript):
proc setControlCHook*(hook: proc () {.noconv.} not nil) proc setControlCHook*(hook: proc () {.noconv.} not nil)
## allows you to override the behaviour of your application when CTRL+C ## allows you to override the behaviour of your application when CTRL+C
## is pressed. Only one such hook is supported. ## 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
{.pop.} # stack trace {.pop.} # stack trace
when hostOS != "standalone" and not defined(NimrodVM): when hostOS != "standalone" and not defined(nimscript):
include "system/dyncalls" include "system/dyncalls"
when not defined(NimrodVM): when not defined(nimscript):
include "system/sets" include "system/sets"
when defined(gogc): when defined(gogc):
@ -2875,11 +2882,11 @@ when not defined(JS): #and not defined(NimrodVM):
var res = TaintedString(newStringOfCap(80)) var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res while f.readLine(res): yield res
when not defined(NimrodVM) and hasAlloc: when not defined(nimscript) and hasAlloc:
include "system/assign" include "system/assign"
include "system/repr" include "system/repr"
when hostOS != "standalone" and not defined(NimrodVM): when hostOS != "standalone" and not defined(nimscript):
proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} = proc getCurrentException*(): ref Exception {.compilerRtl, inl, benign.} =
## retrieves the current exception; if there is none, nil is returned. ## retrieves the current exception; if there is none, nil is returned.
result = currException result = currException
@ -2907,14 +2914,14 @@ when not defined(JS): #and not defined(NimrodVM):
currException = exc currException = exc
{.push stack_trace: off, profiler:off.} {.push stack_trace: off, profiler:off.}
when defined(endb) and not defined(NimrodVM): when defined(endb) and not defined(nimscript):
include "system/debugger" include "system/debugger"
when defined(profiler) or defined(memProfiler): when defined(profiler) or defined(memProfiler):
include "system/profiler" include "system/profiler"
{.pop.} # stacktrace {.pop.} # stacktrace
when not defined(NimrodVM): when not defined(nimscript):
proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.} proc likely*(val: bool): bool {.importc: "likely", nodecl, nosideeffect.}
## Hints the optimizer that `val` is likely going to be true. ## Hints the optimizer that `val` is likely going to be true.
## ##
@ -2992,7 +2999,7 @@ elif defined(JS):
when defined(JS): when defined(JS):
include "system/jssys" include "system/jssys"
include "system/reprjs" include "system/reprjs"
elif defined(NimrodVM): elif defined(nimscript):
proc cmp(x, y: string): int = proc cmp(x, y: string): int =
if x == y: return 0 if x == y: return 0
if x < y: return -1 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 ## marks a sequence `s` as `shallow`:idx:. Subsequent assignments will not
## perform deep copies of `s`. This is only useful for optimization ## perform deep copies of `s`. This is only useful for optimization
## purposes. ## purposes.
when not defined(JS) and not defined(NimrodVM): when not defined(JS) and not defined(nimscript):
var s = cast[PGenericSeq](s) var s = cast[PGenericSeq](s)
s.reserved = s.reserved or seqShallowFlag 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 ## marks a string `s` as `shallow`:idx:. Subsequent assignments will not
## perform deep copies of `s`. This is only useful for optimization ## perform deep copies of `s`. This is only useful for optimization
## purposes. ## purposes.
when not defined(JS) and not defined(NimrodVM): when not defined(JS) and not defined(nimscript):
var s = cast[PGenericSeq](s) var s = cast[PGenericSeq](s)
s.reserved = s.reserved or seqShallowFlag s.reserved = s.reserved or seqShallowFlag
@ -3402,7 +3409,7 @@ proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
## # -> B is 1 ## # -> B is 1
discard 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".} = 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 ## performs a deep copy of `x`. This is also used by the code generator
## for the implementation of ``spawn``. ## for the implementation of ``spawn``.
@ -3444,3 +3451,6 @@ proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
discard discard
{.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.} {.pop.} #{.push warning[GcMem]: off, warning[Uninit]: off.}
when defined(nimconfig):
include "system/nimscript"

152
lib/system/nimscript.nim Normal file
View file

@ -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`()

View file

@ -182,7 +182,10 @@ proc readAllFile(file: File): string =
proc readAll(file: File): TaintedString = proc readAll(file: File): TaintedString =
# Separate handling needed because we need to buffer when we # Separate handling needed because we need to buffer when we
# don't know the overall length of the File. # don't know the overall length of the File.
when declared(stdin):
let len = if file != stdin: rawFileSize(file) else: -1 let len = if file != stdin: rawFileSize(file) else: -1
else:
let len = rawFileSize(file)
if len > 0: if len > 0:
result = readAllFile(file, len).TaintedString result = readAllFile(file, len).TaintedString
else: else:
@ -216,7 +219,7 @@ proc writeLine[Ty](f: File, x: varargs[Ty, `$`]) =
for i in items(x): write(f, i) for i in items(x): write(f, i)
write(f, "\n") write(f, "\n")
when declared(stdout):
proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x) proc rawEcho(x: string) {.inline, compilerproc.} = write(stdout, x)
proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n") proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")

7
tests/newconfig/tfoo.nim Normal file
View file

@ -0,0 +1,7 @@
discard """
cmd: "nim default $file"
output: '''hello world!'''
msg: '''[NimScript] exec: gcc -v'''
"""
echo "hello world!"

14
tests/newconfig/tfoo.nims Normal file
View file

@ -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"