123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2015 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,
- docgen2, service, parser, modules, ccgutils, sigmatch, ropes,
- modulegraphs
- from magicsys import systemModule, resetSysTypes
- proc rodPass =
- if optSymbolFiles in gGlobalOptions:
- registerPass(rodwritePass)
- proc codegenPass =
- registerPass cgenPass
- proc semanticPasses =
- registerPass verbosePass
- registerPass semPass
- proc writeDepsFile(g: ModuleGraph; project: string) =
- let f = open(changeFileExt(project, "deps"), fmWrite)
- for m in g.modules:
- if m != nil:
- f.writeLine(toFullPath(m.position.int32))
- f.close()
- proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
- semanticPasses()
- registerPass(gendependPass)
- #registerPass(cleanupPass)
- compileProject(graph, cache)
- writeDepsFile(graph, gProjectFull)
- generateDot(gProjectFull)
- execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
- ' ' & changeFileExt(gProjectFull, "dot"))
- proc commandCheck(graph: ModuleGraph; cache: IdentCache) =
- msgs.gErrorMax = high(int) # do not stop after first error
- defineSymbol("nimcheck")
- semanticPasses() # use an empty backend for semantic checking only
- rodPass()
- compileProject(graph, cache)
- proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) =
- msgs.gErrorMax = high(int) # do not stop after first error
- semanticPasses()
- if json: registerPass(docgen2JsonPass)
- else: registerPass(docgen2Pass)
- #registerPass(cleanupPass())
- compileProject(graph, cache)
- finishDoc2Pass(gProjectName)
- proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
- extccomp.initVars()
- semanticPasses()
- registerPass(cgenPass)
- rodPass()
- #registerPass(cleanupPass())
- compileProject(graph, cache)
- cgenWriteModules(graph.backend, graph.config)
- if gCmd != cmdRun:
- let proj = changeFileExt(gProjectFull, "")
- extccomp.callCCompiler(proj)
- extccomp.writeJsonBuildInstructions(proj)
- proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
- #incl(gGlobalOptions, optSafeCode)
- setTarget(osJS, cpuJS)
- #initDefines()
- defineSymbol("nimrod") # 'nimrod' is always defined
- defineSymbol("ecmascript") # For backward compatibility
- defineSymbol("js")
- if gCmd == cmdCompileToPHP: defineSymbol("nimphp")
- semanticPasses()
- registerPass(JSgenPass)
- compileProject(graph, cache)
- proc interactivePasses(graph: ModuleGraph; cache: IdentCache) =
- #incl(gGlobalOptions, optSafeCode)
- #setTarget(osNimrodVM, cpuNimrodVM)
- initDefines()
- defineSymbol("nimscript")
- when hasFFI: defineSymbol("nimffi")
- registerPass(verbosePass)
- registerPass(semPass)
- registerPass(evalPass)
- proc commandInteractive(graph: ModuleGraph; cache: IdentCache) =
- msgs.gErrorMax = high(int) # do not stop after first error
- interactivePasses(graph, cache)
- compileSystemModule(graph, cache)
- if commandArgs.len > 0:
- discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {})
- else:
- var m = graph.makeStdinModule()
- incl(m.flags, sfMainModule)
- processModule(graph, m, llStreamOpenStdIn(), nil, cache)
- const evalPasses = [verbosePass, semPass, evalPass]
- proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) =
- carryPasses(graph, nodes, module, cache, evalPasses)
- proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
- if systemModule == nil:
- interactivePasses(graph, cache)
- compileSystemModule(graph, cache)
- let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
- evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache)
- proc commandScan(cache: IdentCache) =
- var f = addFileExt(mainCommandArg(), NimExt)
- var stream = llStreamOpen(f, fmRead)
- if stream != nil:
- var
- L: TLexer
- tok: TToken
- initToken(tok)
- openLexer(L, f, stream, cache)
- while true:
- rawGetTok(L, tok)
- printTok(tok)
- if tok.tokType == tkEof: break
- closeLexer(L)
- else:
- rawMessage(errCannotOpenFile, f)
- const
- SimulateCaasMemReset = false
- PrintRopeCacheStats = false
- proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
- when SimulateCaasMemReset:
- gGlobalOptions.incl(optCaasEnabled)
- # In "nim serve" scenario, each command must reset the registered passes
- clearPasses()
- gLastCmdTime = epochTime()
- searchPaths.add(options.libpath)
- when false: # gProjectFull.len != 0:
- # current path is always looked first for modules
- prependStr(searchPaths, gProjectPath)
- setId(100)
- case command.normalize
- of "c", "cc", "compile", "compiletoc":
- # compile means compileToC currently
- gCmd = cmdCompileToC
- commandCompileToC(graph, cache)
- of "cpp", "compiletocpp":
- gCmd = cmdCompileToCpp
- defineSymbol("cpp")
- commandCompileToC(graph, cache)
- of "objc", "compiletooc":
- gCmd = cmdCompileToOC
- defineSymbol("objc")
- commandCompileToC(graph, cache)
- of "run":
- gCmd = cmdRun
- when hasTinyCBackend:
- extccomp.setCC("tcc")
- commandCompileToC(graph, cache)
- else:
- rawMessage(errInvalidCommandX, command)
- of "js", "compiletojs":
- gCmd = cmdCompileToJS
- commandCompileToJS(graph, cache)
- of "php":
- gCmd = cmdCompileToPHP
- commandCompileToJS(graph, cache)
- of "doc":
- wantMainModule()
- gCmd = cmdDoc
- loadConfigs(DocConfig, cache)
- commandDoc()
- of "doc2":
- gCmd = cmdDoc
- loadConfigs(DocConfig, cache)
- defineSymbol("nimdoc")
- commandDoc2(graph, cache, false)
- of "rst2html":
- gCmd = cmdRst2html
- loadConfigs(DocConfig, cache)
- commandRst2Html()
- of "rst2tex":
- gCmd = cmdRst2tex
- loadConfigs(DocTexConfig, cache)
- commandRst2TeX()
- of "jsondoc":
- wantMainModule()
- gCmd = cmdDoc
- loadConfigs(DocConfig, cache)
- wantMainModule()
- defineSymbol("nimdoc")
- commandJson()
- of "jsondoc2":
- gCmd = cmdDoc
- loadConfigs(DocConfig, cache)
- wantMainModule()
- defineSymbol("nimdoc")
- commandDoc2(graph, cache, true)
- of "buildindex":
- gCmd = cmdDoc
- loadConfigs(DocConfig, cache)
- commandBuildIndex()
- of "gendepend":
- gCmd = cmdGenDepend
- commandGenDepend(graph, cache)
- of "dump":
- gCmd = cmdDump
- if getConfigVar("dump.format") == "json":
- wantMainModule()
- var definedSymbols = newJArray()
- for s in definedSymbolNames(): definedSymbols.elems.add(%s)
- var libpaths = newJArray()
- for dir in 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)
- ]
- msgWriteln($dumpdata, {msgStdout, msgSkipHook})
- else:
- msgWriteln("-- list of currently defined symbols --",
- {msgStdout, msgSkipHook})
- for s in definedSymbolNames(): msgWriteln(s, {msgStdout, msgSkipHook})
- msgWriteln("-- end of list --", {msgStdout, msgSkipHook})
- for it in searchPaths: msgWriteln(it)
- of "check":
- gCmd = cmdCheck
- commandCheck(graph, cache)
- of "parse":
- gCmd = cmdParse
- wantMainModule()
- discard parseFile(gProjectMainIdx, cache)
- of "scan":
- gCmd = cmdScan
- wantMainModule()
- commandScan(cache)
- msgWriteln("Beware: Indentation tokens depend on the parser's state!")
- of "secret":
- gCmd = cmdInteractive
- commandInteractive(graph, cache)
- of "e":
- commandEval(graph, cache, mainCommandArg())
- of "nop", "help":
- # prevent the "success" message:
- gCmd = cmdDump
- else:
- rawMessage(errInvalidCommandX, command)
- if msgs.gErrorCounter == 0 and
- gCmd notin {cmdInterpret, cmdRun, cmdDump}:
- when declared(system.getMaxMem):
- let usedMem = formatSize(getMaxMem()) & " peakmem"
- else:
- let usedMem = formatSize(getTotalMem())
- rawMessage(hintSuccessX, [$gLinesCompiled,
- formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
- usedMem,
- if condSyms.isDefined("release"): "Release Build"
- else: "Debug Build"])
- 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 SimulateCaasMemReset:
- resetMemory()
- resetAttributes()
- proc mainCommand*() = mainCommand(newModuleGraph(newConfigRef()), newIdentCache())
|