summary refs log blame commit diff stats
path: root/compiler/main.nim
blob: cdea7b5ca9f47cb6f631b0fd39593da4149b992c (plain) (tree)
1
2
3
4
5
6
7
8
9


                               
                                         




                                                   
                                                        
 

                                                                             
                                         
                                                           
                              
                                                                         

                                                                              
 
                                                
 
     
                         
 
                     

                



                                      


                       
                     

                          
 
                       
                  
                             
                           
                  


                                                                           
 
                   
                                                             
                                                                               
           
                  
 
                  

                                                             
                           
                              

                              
 
                        
                  

                        
                              




                                          
                  
                    
                    
                                                           
 
               





















                                                           
 
                      









                                                                         
 

                             

                                       
             
                                
                    
 
                         
                                    
                        
                


                                                         
                  
                         
                  
 
                        
                                    
                                     
               
                          
                                     



                           
                         
                                                             
                     
                       
                         
                                                        
       
                             
                               
                                              
 

                                                   

                                          

                               

                         

                                                          
                                                 
 
                       

                                                        
                   
                                                                          
 
                    
                                                             



                          
 
                  
                                              
                                      

                   
               

                  
                           
               
                       
                   
                                    
                 
       
                                    
 
                     





                                                                     
                       


                                                       

                                   



                                                               




                                                                           
 
                     
                           
                              
                                                    


                                                
 
                                                                
 

                              
                                                     



                                              
                                                                
 


                         
                   

                  




                                       
 














                                     
 
                  







                                                                     








                                 
 



                               
                   

                                       
 

                                                                             
                            
                                         


                                                     
            
                                     
                                     
                        
                                        

                                        
                    
                       
                           

                          
                                       
                    

                       
                           

                         
                    

                        
           
                 
                    
                         
                           
                         
         
                                             
                         
                         
                    
                        
                     
                           
                    
                         
                            
         
                                             
              
                    
                    
                   
           
                 
                          
                    
                

                 
                          
                    

                          
                
                      
                          
                    
                     
               
                     
                             
                    
                    

                 
                          
                    

                          

                  

                          
                 
                       
                    
                      
            

                                             





                                                                 
                                                                      







                                                      
                           
         


                                                           
 
                                                           
             
                   
                    
                  
             
                   
                    
                                      
            
                  
                    

                                                                           
         
                         
                        


                                               
             
                 
                
                      



                            
                      
             
                    
                                       
                                                               
                      

                                           
 


                                                    


                                                                     
 





                                                                                              
 

                             
 
#
#
#           The Nimrod Compiler
#        (c) Copyright 2014 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

# implements the command dispatcher and several commands

import
  llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
  os, condsyms, rodread, rodwrite, times,
  wordrecg, sem, semdata, idents, passes, docgen, extccomp,
  cgen, jsgen, json, nversion,
  platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
  tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists,
  pretty

from magicsys import systemModule, resetSysTypes

const
  hasLLVM_Backend = false

when hasLLVM_Backend:
  import llvmgen

proc rodPass =
  if optSymbolFiles in gGlobalOptions:
    registerPass(rodwritePass)

proc codegenPass =
  registerPass cgenPass

proc semanticPasses =
  registerPass verbosePass
  registerPass semPass

proc commandGenDepend =
  semanticPasses()
  registerPass(gendependPass)
  registerPass(cleanupPass)
  compileProject()
  generateDot(gProjectFull)
  execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
      ' ' & changeFileExt(gProjectFull, "dot"))

proc commandCheck =
  msgs.gErrorMax = high(int)  # do not stop after first error
  semanticPasses()            # use an empty backend for semantic checking only
  rodPass()
  compileProject()

proc commandDoc2 =
  msgs.gErrorMax = high(int)  # do not stop after first error
  semanticPasses()
  registerPass(docgen2Pass)
  #registerPass(cleanupPass())
  compileProject()
  finishDoc2Pass(gProjectName)

proc commandCompileToC =
  semanticPasses()
  registerPass(cgenPass)
  rodPass()
  #registerPass(cleanupPass())
  if optCaasEnabled in gGlobalOptions:
    # echo "BEFORE CHECK DEP"
    # discard checkDepMem(gProjectMainIdx)
    # echo "CHECK DEP COMPLETE"

  compileProject()
  cgenWriteModules()
  if gCmd != cmdRun:
    extccomp.callCCompiler(changeFileExt(gProjectFull, ""))

  if isServing:
    # caas will keep track only of the compilation commands
    lastCaasCmd = curCaasCmd
    resetCgenModules()
    for i in 0 .. <gMemCacheData.len:
      gMemCacheData[i].crcStatus = crcCached
      gMemCacheData[i].needsRecompile = Maybe

      # XXX: clean these global vars
      # ccgstmts.gBreakpoints
      # ccgthreadvars.nimtv
      # ccgthreadvars.nimtVDeps
      # ccgthreadvars.nimtvDeclared
      # cgendata
      # cgmeth?
      # condsyms?
      # depends?
      # lexer.gLinesCompiled
      # msgs - error counts
      # magicsys, when system.nim changes
      # rodread.rodcompilerProcs
      # rodread.gTypeTable
      # rodread.gMods

      # !! ropes.cache
      # semthreads.computed?
      #
      # suggest.usageSym
      #
      # XXX: can we run out of IDs?
      # XXX: detect config reloading (implement as error/require restart)
      # XXX: options are appended (they will accumulate over time)
    resetCompilationLists()
    ccgutils.resetCaches()
    GC_fullCollect()

when hasLLVM_Backend:
  proc commandCompileToLLVM =
    semanticPasses()
    registerPass(llvmgen.llvmgenPass())
    rodPass()
    #registerPass(cleanupPass())
    compileProject()

proc commandCompileToJS =
  #incl(gGlobalOptions, optSafeCode)
  setTarget(osJS, cpuJS)
  #initDefines()
  defineSymbol("nimrod") # 'nimrod' is always defined
  defineSymbol("ecmascript") # For backward compatibility
  defineSymbol("js")
  semanticPasses()
  registerPass(JSgenPass)
  compileProject()

proc interactivePasses =
  #incl(gGlobalOptions, optSafeCode)
  #setTarget(osNimrodVM, cpuNimrodVM)
  initDefines()
  defineSymbol("nimrodvm")
  when hasFFI: DefineSymbol("nimffi")
  registerPass(verbosePass)
  registerPass(semPass)
  registerPass(evalPass)

proc commandInteractive =
  msgs.gErrorMax = high(int)  # do not stop after first error
  interactivePasses()
  compileSystemModule()
  if commandArgs.len > 0:
    discard compileModule(fileInfoIdx(gProjectFull), {})
  else:
    var m = makeStdinModule()
    incl(m.flags, sfMainModule)
    processModule(m, llStreamOpenStdIn(), nil)

const evalPasses = [verbosePass, semPass, evalPass]

proc evalNim(nodes: PNode, module: PSym) =
  carryPasses(nodes, module, evalPasses)

proc commandEval(exp: string) =
  if systemModule == nil:
    interactivePasses()
    compileSystemModule()
  var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
  evalNim(echoExp.parseString, makeStdinModule())

proc commandPrettyOld =
  var projectFile = addFileExt(mainCommandArg(), NimExt)
  var module = parseFile(projectFile.fileInfoIdx)
  if module != nil:
    renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))

proc commandPretty =
  msgs.gErrorMax = high(int)  # do not stop after first error
  semanticPasses()
  registerPass(prettyPass)
  compileProject()
  pretty.overwriteFiles()

proc commandScan =
  var f = addFileExt(mainCommandArg(), NimExt)
  var stream = llStreamOpen(f, fmRead)
  if stream != nil:
    var
      L: TLexer
      tok: TToken
    initToken(tok)
    openLexer(L, f, stream)
    while true:
      rawGetTok(L, tok)
      printTok(tok)
      if tok.tokType == tkEof: break
    closeLexer(L)
  else:
    rawMessage(errCannotOpenFile, f)

proc commandSuggest =
  if isServing:
    # XXX: hacky work-around ahead
    # Currently, it's possible to issue a idetools command, before
    # issuing the first compile command. This will leave the compiler
    # cache in a state where "no recompilation is necessary", but the
    # cgen pass was never executed at all.
    commandCompileToC()
    if gDirtyBufferIdx != 0:
      discard compileModule(gDirtyBufferIdx, {sfDirty})
      resetModule(gDirtyBufferIdx)
    if optDef in gGlobalOptions:
      defFromSourceMap(optTrackPos)
  else:
    msgs.gErrorMax = high(int)  # do not stop after first error
    semanticPasses()
    rodPass()
    # XXX: this handles the case when the dirty buffer is the main file,
    # but doesn't handle the case when it's imported module
    var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx
                   else: gProjectMainIdx
    compileProject(projFile)

proc wantMainModule =
  if gProjectFull.len == 0:
    if optMainModule.len == 0:
      fatal(gCmdLineInfo, errCommandExpectsFilename)
    else:
      gProjectName = optMainModule
      gProjectFull = gProjectPath / gProjectName

  gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx

proc requireMainModuleOption =
  if optMainModule.len == 0:
    fatal(gCmdLineInfo, errMainModuleMustBeSpecified)
  else:
    gProjectName = optMainModule
    gProjectFull = gProjectPath / gProjectName

  gProjectMainIdx = addFileExt(gProjectFull, NimExt).fileInfoIdx

proc resetMemory =
  resetCompilationLists()
  ccgutils.resetCaches()
  resetAllModules()
  resetRopeCache()
  resetSysTypes()
  gOwners = @[]
  rangeDestructorProc = nil
  for i in low(buckets)..high(buckets):
    buckets[i] = nil
  idAnon = nil

  # XXX: clean these global vars
  # ccgstmts.gBreakpoints
  # ccgthreadvars.nimtv
  # ccgthreadvars.nimtVDeps
  # ccgthreadvars.nimtvDeclared
  # cgendata
  # cgmeth?
  # condsyms?
  # depends?
  # lexer.gLinesCompiled
  # msgs - error counts
  # magicsys, when system.nim changes
  # rodread.rodcompilerProcs
  # rodread.gTypeTable
  # rodread.gMods

  # !! ropes.cache
  # semthreads.computed?
  #
  # suggest.usageSym
  #
  # XXX: can we run out of IDs?
  # XXX: detect config reloading (implement as error/require restart)
  # XXX: options are appended (they will accumulate over time)
  # vis = visimpl
  when compileOption("gc", "v2"):
    gcDebugging = true
    echo "COLLECT 1"
    GC_fullCollect()
    echo "COLLECT 2"
    GC_fullCollect()
    echo "COLLECT 3"
    GC_fullCollect()
    echo GC_getStatistics()

const
  SimiluateCaasMemReset = false
  PrintRopeCacheStats = false

proc mainCommand* =
  when SimiluateCaasMemReset:
    gGlobalOptions.incl(optCaasEnabled)

  # In "nimrod serve" scenario, each command must reset the registered passes
  clearPasses()
  gLastCmdTime = epochTime()
  appendStr(searchPaths, options.libpath)
  if gProjectFull.len != 0:
    # current path is always looked first for modules
    prependStr(searchPaths, gProjectPath)
  setId(100)
  passes.gIncludeFile = includeModule
  passes.gImportModule = importModule
  case command.normalize
  of "c", "cc", "compile", "compiletoc":
    # compile means compileToC currently
    gCmd = cmdCompileToC
    wantMainModule()
    commandCompileToC()
  of "cpp", "compiletocpp":
    extccomp.cExt = ".cpp"
    gCmd = cmdCompileToCpp
    if cCompiler == ccGcc: setCC("gpp")
    wantMainModule()
    defineSymbol("cpp")
    commandCompileToC()
  of "objc", "compiletooc":
    extccomp.cExt = ".m"
    gCmd = cmdCompileToOC
    wantMainModule()
    defineSymbol("objc")
    commandCompileToC()
  of "run":
    gCmd = cmdRun
    wantMainModule()
    when hasTinyCBackend:
      extccomp.setCC("tcc")
      CommandCompileToC()
    else:
      rawMessage(errInvalidCommandX, command)
  of "js", "compiletojs":
    gCmd = cmdCompileToJS
    wantMainModule()
    commandCompileToJS()
  of "compiletollvm":
    gCmd = cmdCompileToLLVM
    wantMainModule()
    when hasLLVM_Backend:
      CommandCompileToLLVM()
    else:
      rawMessage(errInvalidCommandX, command)
  of "pretty":
    gCmd = cmdPretty
    wantMainModule()
    commandPretty()
  of "doc":
    gCmd = cmdDoc
    loadConfigs(DocConfig)
    wantMainModule()
    commandDoc()
  of "doc2":
    gCmd = cmdDoc
    loadConfigs(DocConfig)
    wantMainModule()
    defineSymbol("nimdoc")
    commandDoc2()
  of "rst2html":
    gCmd = cmdRst2html
    loadConfigs(DocConfig)
    wantMainModule()
    commandRst2Html()
  of "rst2tex":
    gCmd = cmdRst2tex
    loadConfigs(DocTexConfig)
    wantMainModule()
    commandRst2TeX()
  of "jsondoc":
    gCmd = cmdDoc
    loadConfigs(DocConfig)
    wantMainModule()
    defineSymbol("nimdoc")
    commandJSON()
  of "buildindex":
    gCmd = cmdDoc
    loadConfigs(DocConfig)
    commandBuildIndex()
  of "gendepend":
    gCmd = cmdGenDepend
    wantMainModule()
    commandGenDepend()
  of "dump":
    gCmd = cmdDump
    if getConfigVar("dump.format") == "json":
      requireMainModuleOption()

      var definedSymbols = newJArray()
      for s in definedSymbolNames(): definedSymbols.elems.add(%s)

      var libpaths = newJArray()
      for dir in iterSearchPath(searchPaths): libpaths.elems.add(%dir)

      var dumpdata = % [
        (key: "version", val: %VersionAsString),
        (key: "project_path", val: %gProjectFull),
        (key: "defined_symbols", val: definedSymbols),
        (key: "lib_paths", val: libpaths)
      ]

      outWriteln($dumpdata)
    else:
      outWriteln("-- list of currently defined symbols --")
      for s in definedSymbolNames(): outWriteln(s)
      outWriteln("-- end of list --")

      for it in iterSearchPath(searchPaths): msgWriteln(it)
  of "check":
    gCmd = cmdCheck
    wantMainModule()
    commandCheck()
  of "parse":
    gCmd = cmdParse
    wantMainModule()
    discard parseFile(gProjectMainIdx)
  of "scan":
    gCmd = cmdScan
    wantMainModule()
    commandScan()
    msgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
  of "i":
    gCmd = cmdInteractive
    commandInteractive()
  of "e":
    # XXX: temporary command for easier testing
    commandEval(mainCommandArg())
  of "reset":
    resetMemory()
  of "idetools":
    gCmd = cmdIdeTools
    if gEvalExpr != "":
      commandEval(gEvalExpr)
    else:
      wantMainModule()
      commandSuggest()
  of "serve":
    isServing = true
    gGlobalOptions.incl(optCaasEnabled)
    msgs.gErrorMax = high(int)  # do not stop after first error
    serve(mainCommand)
  else:
    rawMessage(errInvalidCommandX, command)

  if (msgs.gErrorCounter == 0 and
      gCmd notin {cmdInterpret, cmdRun, cmdDump} and
      gVerbosity > 0):
    rawMessage(hintSuccessX, [$gLinesCompiled,
               formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
               formatSize(getTotalMem())])

  when PrintRopeCacheStats:
    echo "rope cache stats: "
    echo "  tries : ", gCacheTries
    echo "  misses: ", gCacheMisses
    echo "  int tries: ", gCacheIntTries
    echo "  efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float), ffDecimal, 3)

  when SimiluateCaasMemReset:
    resetMemory()