main.nim 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # implements the command dispatcher and several commands
  10. when not defined(nimcore):
  11. {.error: "nimcore MUST be defined for Nim's core tooling".}
  12. import
  13. llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
  14. os, condsyms, times,
  15. wordrecg, sem, semdata, idents, passes, docgen, extccomp,
  16. cgen, jsgen, json, nversion,
  17. platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen,
  18. docgen2, parser, modules, ccgutils, sigmatch, ropes,
  19. modulegraphs, tables, rod, lineinfos, pathutils
  20. from magicsys import resetSysTypes
  21. proc codegenPass(g: ModuleGraph) =
  22. registerPass g, cgenPass
  23. proc semanticPasses(g: ModuleGraph) =
  24. registerPass g, verbosePass
  25. registerPass g, semPass
  26. proc writeDepsFile(g: ModuleGraph; project: AbsoluteFile) =
  27. let f = open(changeFileExt(project, "deps").string, fmWrite)
  28. for m in g.modules:
  29. if m != nil:
  30. f.writeLine(toFullPath(g.config, m.position.FileIndex))
  31. for k in g.inclToMod.keys:
  32. if g.getModule(k).isNil: # don't repeat includes which are also modules
  33. f.writeLine(toFullPath(g.config, k))
  34. f.close()
  35. proc commandGenDepend(graph: ModuleGraph) =
  36. semanticPasses(graph)
  37. registerPass(graph, gendependPass)
  38. compileProject(graph)
  39. let project = graph.config.projectFull
  40. writeDepsFile(graph, project)
  41. generateDot(graph, project)
  42. execExternalProgram(graph.config, "dot -Tpng -o" &
  43. changeFileExt(project, "png").string &
  44. ' ' & changeFileExt(project, "dot").string)
  45. proc commandCheck(graph: ModuleGraph) =
  46. graph.config.errorMax = high(int) # do not stop after first error
  47. defineSymbol(graph.config.symbols, "nimcheck")
  48. semanticPasses(graph) # use an empty backend for semantic checking only
  49. compileProject(graph)
  50. proc commandDoc2(graph: ModuleGraph; json: bool) =
  51. graph.config.errorMax = high(int) # do not stop after first error
  52. semanticPasses(graph)
  53. if json: registerPass(graph, docgen2JsonPass)
  54. else: registerPass(graph, docgen2Pass)
  55. compileProject(graph)
  56. finishDoc2Pass(graph.config.projectName)
  57. proc commandCompileToC(graph: ModuleGraph) =
  58. let conf = graph.config
  59. extccomp.initVars(conf)
  60. semanticPasses(graph)
  61. registerPass(graph, cgenPass)
  62. compileProject(graph)
  63. cgenWriteModules(graph.backend, conf)
  64. if conf.cmd != cmdRun:
  65. let proj = changeFileExt(conf.projectFull, "")
  66. extccomp.callCCompiler(conf, proj)
  67. extccomp.writeJsonBuildInstructions(conf, proj)
  68. if optGenScript in graph.config.globalOptions:
  69. writeDepsFile(graph, toGeneratedFile(conf, proj, ""))
  70. proc commandJsonScript(graph: ModuleGraph) =
  71. let proj = changeFileExt(graph.config.projectFull, "")
  72. extccomp.runJsonBuildInstructions(graph.config, proj)
  73. proc commandCompileToJS(graph: ModuleGraph) =
  74. #incl(gGlobalOptions, optSafeCode)
  75. setTarget(graph.config.target, osJS, cpuJS)
  76. #initDefines()
  77. defineSymbol(graph.config.symbols, "ecmascript") # For backward compatibility
  78. defineSymbol(graph.config.symbols, "js")
  79. semanticPasses(graph)
  80. registerPass(graph, JSgenPass)
  81. compileProject(graph)
  82. proc interactivePasses(graph: ModuleGraph) =
  83. initDefines(graph.config.symbols)
  84. defineSymbol(graph.config.symbols, "nimscript")
  85. when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
  86. registerPass(graph, verbosePass)
  87. registerPass(graph, semPass)
  88. registerPass(graph, evalPass)
  89. proc commandInteractive(graph: ModuleGraph) =
  90. graph.config.errorMax = high(int) # do not stop after first error
  91. interactivePasses(graph)
  92. compileSystemModule(graph)
  93. if graph.config.commandArgs.len > 0:
  94. discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
  95. else:
  96. var m = graph.makeStdinModule()
  97. incl(m.flags, sfMainModule)
  98. processModule(graph, m, llStreamOpenStdIn())
  99. const evalPasses = [verbosePass, semPass, evalPass]
  100. proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym) =
  101. carryPasses(graph, nodes, module, evalPasses)
  102. proc commandEval(graph: ModuleGraph; exp: string) =
  103. if graph.systemModule == nil:
  104. interactivePasses(graph)
  105. compileSystemModule(graph)
  106. let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
  107. evalNim(graph, echoExp.parseString(graph.cache, graph.config),
  108. makeStdinModule(graph))
  109. proc commandScan(cache: IdentCache, config: ConfigRef) =
  110. var f = addFileExt(AbsoluteFile mainCommandArg(config), NimExt)
  111. var stream = llStreamOpen(f, fmRead)
  112. if stream != nil:
  113. var
  114. L: TLexer
  115. tok: TToken
  116. initToken(tok)
  117. openLexer(L, f, stream, cache, config)
  118. while true:
  119. rawGetTok(L, tok)
  120. printTok(config, tok)
  121. if tok.tokType == tkEof: break
  122. closeLexer(L)
  123. else:
  124. rawMessage(config, errGenerated, "cannot open file: " & f.string)
  125. const
  126. PrintRopeCacheStats = false
  127. proc mainCommand*(graph: ModuleGraph) =
  128. let conf = graph.config
  129. let cache = graph.cache
  130. setupModuleCache(graph)
  131. # In "nim serve" scenario, each command must reset the registered passes
  132. clearPasses(graph)
  133. conf.lastCmdTime = epochTime()
  134. conf.searchPaths.add(conf.libpath)
  135. setId(100)
  136. case conf.command.normalize
  137. of "c", "cc", "compile", "compiletoc":
  138. # compile means compileToC currently
  139. conf.cmd = cmdCompileToC
  140. commandCompileToC(graph)
  141. of "cpp", "compiletocpp":
  142. conf.cmd = cmdCompileToCpp
  143. defineSymbol(graph.config.symbols, "cpp")
  144. commandCompileToC(graph)
  145. of "objc", "compiletooc":
  146. conf.cmd = cmdCompileToOC
  147. defineSymbol(graph.config.symbols, "objc")
  148. commandCompileToC(graph)
  149. of "run":
  150. conf.cmd = cmdRun
  151. when hasTinyCBackend:
  152. extccomp.setCC("tcc")
  153. commandCompileToC(graph)
  154. else:
  155. rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
  156. of "js", "compiletojs":
  157. conf.cmd = cmdCompileToJS
  158. commandCompileToJS(graph)
  159. of "doc0":
  160. wantMainModule(conf)
  161. conf.cmd = cmdDoc
  162. loadConfigs(DocConfig, cache, conf)
  163. commandDoc(cache, conf)
  164. of "doc2", "doc":
  165. conf.cmd = cmdDoc
  166. loadConfigs(DocConfig, cache, conf)
  167. defineSymbol(conf.symbols, "nimdoc")
  168. commandDoc2(graph, false)
  169. of "rst2html":
  170. conf.cmd = cmdRst2html
  171. loadConfigs(DocConfig, cache, conf)
  172. commandRst2Html(cache, conf)
  173. of "rst2tex":
  174. conf.cmd = cmdRst2tex
  175. loadConfigs(DocTexConfig, cache, conf)
  176. commandRst2TeX(cache, conf)
  177. of "jsondoc0":
  178. wantMainModule(conf)
  179. conf.cmd = cmdDoc
  180. loadConfigs(DocConfig, cache, conf)
  181. wantMainModule(conf)
  182. defineSymbol(conf.symbols, "nimdoc")
  183. commandJson(cache, conf)
  184. of "jsondoc2", "jsondoc":
  185. conf.cmd = cmdDoc
  186. loadConfigs(DocConfig, cache, conf)
  187. wantMainModule(conf)
  188. defineSymbol(conf.symbols, "nimdoc")
  189. commandDoc2(graph, true)
  190. of "ctags":
  191. wantMainModule(conf)
  192. conf.cmd = cmdDoc
  193. loadConfigs(DocConfig, cache, conf)
  194. defineSymbol(conf.symbols, "nimdoc")
  195. commandTags(cache, conf)
  196. of "buildindex":
  197. conf.cmd = cmdDoc
  198. loadConfigs(DocConfig, cache, conf)
  199. commandBuildIndex(cache, conf)
  200. of "gendepend":
  201. conf.cmd = cmdGenDepend
  202. commandGenDepend(graph)
  203. of "dump":
  204. conf.cmd = cmdDump
  205. if getConfigVar(conf, "dump.format") == "json":
  206. wantMainModule(conf)
  207. var definedSymbols = newJArray()
  208. for s in definedSymbolNames(conf.symbols): definedSymbols.elems.add(%s)
  209. var libpaths = newJArray()
  210. for dir in conf.searchPaths: libpaths.elems.add(%dir.string)
  211. var dumpdata = % [
  212. (key: "version", val: %VersionAsString),
  213. (key: "project_path", val: %conf.projectFull.string),
  214. (key: "defined_symbols", val: definedSymbols),
  215. (key: "lib_paths", val: libpaths)
  216. ]
  217. msgWriteln(conf, $dumpdata, {msgStdout, msgSkipHook})
  218. else:
  219. msgWriteln(conf, "-- list of currently defined symbols --",
  220. {msgStdout, msgSkipHook})
  221. for s in definedSymbolNames(conf.symbols): msgWriteln(conf, s, {msgStdout, msgSkipHook})
  222. msgWriteln(conf, "-- end of list --", {msgStdout, msgSkipHook})
  223. for it in conf.searchPaths: msgWriteln(conf, it.string)
  224. of "check":
  225. conf.cmd = cmdCheck
  226. commandCheck(graph)
  227. of "parse":
  228. conf.cmd = cmdParse
  229. wantMainModule(conf)
  230. discard parseFile(conf.projectMainIdx, cache, conf)
  231. of "scan":
  232. conf.cmd = cmdScan
  233. wantMainModule(conf)
  234. commandScan(cache, conf)
  235. msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
  236. of "secret":
  237. conf.cmd = cmdInteractive
  238. commandInteractive(graph)
  239. of "e":
  240. incl conf.globalOptions, optWasNimscript
  241. commandEval(graph, mainCommandArg(conf))
  242. of "nop", "help":
  243. # prevent the "success" message:
  244. conf.cmd = cmdDump
  245. of "jsonscript":
  246. conf.cmd = cmdJsonScript
  247. commandJsonScript(graph)
  248. else:
  249. rawMessage(conf, errGenerated, "invalid command: " & conf.command)
  250. if conf.errorCounter == 0 and
  251. conf.cmd notin {cmdInterpret, cmdRun, cmdDump}:
  252. when declared(system.getMaxMem):
  253. let usedMem = formatSize(getMaxMem()) & " peakmem"
  254. else:
  255. let usedMem = formatSize(getTotalMem())
  256. rawMessage(conf, hintSuccessX, [$conf.linesCompiled,
  257. formatFloat(epochTime() - conf.lastCmdTime, ffDecimal, 3),
  258. usedMem,
  259. if isDefined(conf, "release"): "Release Build"
  260. else: "Debug Build"])
  261. when PrintRopeCacheStats:
  262. echo "rope cache stats: "
  263. echo " tries : ", gCacheTries
  264. echo " misses: ", gCacheMisses
  265. echo " int tries: ", gCacheIntTries
  266. echo " efficiency: ", formatFloat(1-(gCacheMisses.float/gCacheTries.float),
  267. ffDecimal, 3)
  268. resetAttributes(conf)