summary refs log blame commit diff stats
path: root/compiler/scriptconfig.nim
blob: 0c31eadbebd26d1b514834258fde54128fc5a0ac (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                           
                                                  
                                                                      
                                                    

                                                      
                                             







                                                      

                                                                  
                                           
                                














                                                              
                      
























                                                                               

                                                 


                                                                     


                                                








                                              















                                                                       

                                                                      

                                   


                           


                                                
          
                                             
                     
                           


                                 
                                                                    
                  
                                                                  

                     
                                                                     
                    


                                                   



                                   
                               

                                     


                                               
 
                                                         
                                                              

                                     
                                    
                                





                           
                                  
 
                                      
                             
                                                      
 

                                                                              

                                                                    
                        
                    



                                     
#
#
#           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, passaux, condsyms,
  options, nimconf, sem, semdata, llstream, vm, vmdef, commands, msgs,
  os, times, osproc, wordrecg, strtabs, modulegraphs

# 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;
              config: ConfigRef = nil): PEvalContext =
  # For Nimble we need to export 'setupVM'.
  result = newCtx(module, cache)
  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) =
        errorMsg = nil
        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 copyFile:
    os.copyFile(getString(a, 0), getString(a, 1))
  cbos getLastModificationTime:
    setResult(a, toSeconds(getLastModificationTime(getString(a, 0))))

  cbos rawExec:
    setResult(a, osproc.execCmd getString(a, 0))

  cbconf getEnv:
    setResult(a, os.getEnv(a.getString 0))
  cbconf existsEnv:
    setResult(a, os.existsEnv(a.getString 0))
  cbconf dirExists:
    setResult(a, os.dirExists(a.getString 0))
  cbconf fileExists:
    setResult(a, os.fileExists(a.getString 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 cmpIgnoreCase:
    setResult(a, strutils.cmpIgnoreCase(a.getString 0, a.getString 1))
  cbconf setCommand:
    options.command = a.getString 0
    let arg = a.getString 1
    if arg.len > 0:
      gProjectName = arg
      let path =
        if gProjectName.isAbsolute: gProjectName
        else: gProjectPath / gProjectName
      try:
        gProjectFull = canonicalizePath(path)
      except OSError:
        gProjectFull = path
  cbconf getCommand:
    setResult(a, options.command)
  cbconf switch:
    processSwitch(a.getString 0, a.getString 1, passPP, module.info)
  cbconf hintImpl:
    processSpecificNote(a.getString 0, wHint, passPP, module.info,
      a.getString 1)
  cbconf warningImpl:
    processSpecificNote(a.getString 0, wWarning, passPP, module.info,
      a.getString 1)
  cbconf patchFile:
    let key = a.getString(0) & "_" & a.getString(1)
    var val = a.getString(2).addFileExt(NimExt)
    if {'$', '~'} in val:
      val = pathSubs(val, vthisDir)
    elif not isAbsolute(val):
      val = vthisDir / val
    gModuleOverrides[key] = val
  cbconf selfExe:
    setResult(a, os.getAppFilename())
  cbconf cppDefine:
    if config != nil:
      options.cppDefine(config, a.getString(0))

proc runNimScript*(cache: IdentCache; scriptName: string;
                   freshDefines=true; config: ConfigRef=nil) =
  passes.gIncludeFile = includeModule
  passes.gImportModule = importModule
  let graph = newModuleGraph(config)
  if freshDefines: initDefines()

  defineSymbol("nimscript")
  defineSymbol("nimconfig")
  registerPass(semPass)
  registerPass(evalPass)

  searchPaths.add(options.libpath)

  var m = graph.makeModule(scriptName)
  incl(m.flags, sfMainModule)
  vm.globalCtx = setupVM(m, cache, scriptName, config)

  graph.compileSystemModule(cache)
  discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)

  # ensure we load 'system.nim' again for the real non-config stuff!
  resetSystemArtifacts()
  vm.globalCtx = nil
  # do not remove the defined symbols
  #initDefines()
  undefSymbol("nimscript")
  undefSymbol("nimconfig")