main.nim 8.8 KB

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