main.nim 11 KB

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