summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/commands.nim2
-rw-r--r--compiler/main.nim3
-rw-r--r--compiler/modules.nim20
-rw-r--r--compiler/nim.nim9
-rw-r--r--compiler/options.nim6
-rw-r--r--compiler/scriptconfig.nim119
-rw-r--r--compiler/vm.nim4
-rw-r--r--compiler/vmhooks.nim12
8 files changed, 159 insertions, 16 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)