rodwrite.nim 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # This module is responsible for writing of rod files. Note that writing of
  10. # rod files is a pass, reading of rod files is not! This is why reading and
  11. # writing of rod files is split into two different modules.
  12. import
  13. intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
  14. condsyms, ropes, idents, securehash, rodread, passes, importer, idgen,
  15. rodutils
  16. from modulegraphs import ModuleGraph
  17. type
  18. TRodWriter = object of TPassContext
  19. module: PSym
  20. hash: SecureHash
  21. options: TOptions
  22. defines: string
  23. inclDeps: string
  24. modDeps: string
  25. interf: string
  26. compilerProcs: string
  27. index, imports: TIndex
  28. converters, methods: string
  29. init: string
  30. data: string
  31. sstack: TSymSeq # a stack of symbols to process
  32. tstack: TTypeSeq # a stack of types to process
  33. files: TStringSeq
  34. origFile: string
  35. cache: IdentCache
  36. PRodWriter = ref TRodWriter
  37. proc getDefines(): string =
  38. result = ""
  39. for d in definedSymbolNames():
  40. if result.len != 0: add(result, " ")
  41. add(result, d)
  42. proc fileIdx(w: PRodWriter, filename: string): int =
  43. for i in countup(0, high(w.files)):
  44. if w.files[i] == filename:
  45. return i
  46. result = len(w.files)
  47. setLen(w.files, result + 1)
  48. w.files[result] = filename
  49. template filename*(w: PRodWriter): string =
  50. w.module.filename
  51. proc newRodWriter(hash: SecureHash, module: PSym; cache: IdentCache): PRodWriter =
  52. new(result)
  53. result.sstack = @[]
  54. result.tstack = @[]
  55. initIiTable(result.index.tab)
  56. initIiTable(result.imports.tab)
  57. result.index.r = ""
  58. result.imports.r = ""
  59. result.hash = hash
  60. result.module = module
  61. result.defines = getDefines()
  62. result.options = options.gOptions
  63. result.files = @[]
  64. result.inclDeps = ""
  65. result.modDeps = ""
  66. result.interf = newStringOfCap(2_000)
  67. result.compilerProcs = ""
  68. result.converters = ""
  69. result.methods = ""
  70. result.init = ""
  71. result.origFile = module.info.toFullPath
  72. result.data = newStringOfCap(12_000)
  73. result.cache = cache
  74. proc addModDep(w: PRodWriter, dep: string; info: TLineInfo) =
  75. if w.modDeps.len != 0: add(w.modDeps, ' ')
  76. let resolved = dep.findModule(info.toFullPath)
  77. encodeVInt(fileIdx(w, resolved), w.modDeps)
  78. const
  79. rodNL = "\x0A"
  80. proc addInclDep(w: PRodWriter, dep: string; info: TLineInfo) =
  81. let resolved = dep.findModule(info.toFullPath)
  82. encodeVInt(fileIdx(w, resolved), w.inclDeps)
  83. add(w.inclDeps, " ")
  84. encodeStr($secureHashFile(resolved), w.inclDeps)
  85. add(w.inclDeps, rodNL)
  86. proc pushType(w: PRodWriter, t: PType) =
  87. # check so that the stack does not grow too large:
  88. if iiTableGet(w.index.tab, t.id) == InvalidKey:
  89. w.tstack.add(t)
  90. proc pushSym(w: PRodWriter, s: PSym) =
  91. # check so that the stack does not grow too large:
  92. if iiTableGet(w.index.tab, s.id) == InvalidKey:
  93. when false:
  94. if s.kind == skMethod:
  95. echo "encoding ", s.id, " ", s.name.s
  96. writeStackTrace()
  97. w.sstack.add(s)
  98. proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode,
  99. result: var string) =
  100. if n == nil:
  101. # nil nodes have to be stored too:
  102. result.add("()")
  103. return
  104. result.add('(')
  105. encodeVInt(ord(n.kind), result)
  106. # we do not write comments for now
  107. # Line information takes easily 20% or more of the filesize! Therefore we
  108. # omit line information if it is the same as the father's line information:
  109. if fInfo.fileIndex != n.info.fileIndex:
  110. result.add('?')
  111. encodeVInt(n.info.col, result)
  112. result.add(',')
  113. encodeVInt(n.info.line, result)
  114. result.add(',')
  115. encodeVInt(fileIdx(w, toFullPath(n.info)), result)
  116. elif fInfo.line != n.info.line:
  117. result.add('?')
  118. encodeVInt(n.info.col, result)
  119. result.add(',')
  120. encodeVInt(n.info.line, result)
  121. elif fInfo.col != n.info.col:
  122. result.add('?')
  123. encodeVInt(n.info.col, result)
  124. # No need to output the file index, as this is the serialization of one
  125. # file.
  126. var f = n.flags * PersistentNodeFlags
  127. if f != {}:
  128. result.add('$')
  129. encodeVInt(cast[int32](f), result)
  130. if n.typ != nil:
  131. result.add('^')
  132. encodeVInt(n.typ.id, result)
  133. pushType(w, n.typ)
  134. case n.kind
  135. of nkCharLit..nkUInt64Lit:
  136. if n.intVal != 0:
  137. result.add('!')
  138. encodeVBiggestInt(n.intVal, result)
  139. of nkFloatLit..nkFloat64Lit:
  140. if n.floatVal != 0.0:
  141. result.add('!')
  142. encodeStr($n.floatVal, result)
  143. of nkStrLit..nkTripleStrLit:
  144. if n.strVal != "":
  145. result.add('!')
  146. encodeStr(n.strVal, result)
  147. of nkIdent:
  148. result.add('!')
  149. encodeStr(n.ident.s, result)
  150. of nkSym:
  151. result.add('!')
  152. encodeVInt(n.sym.id, result)
  153. pushSym(w, n.sym)
  154. else:
  155. for i in countup(0, sonsLen(n) - 1):
  156. encodeNode(w, n.info, n.sons[i], result)
  157. add(result, ')')
  158. proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) =
  159. var oldLen = result.len
  160. result.add('<')
  161. if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
  162. if loc.storage != low(loc.storage):
  163. add(result, '*')
  164. encodeVInt(ord(loc.storage), result)
  165. if loc.flags != {}:
  166. add(result, '$')
  167. encodeVInt(cast[int32](loc.flags), result)
  168. if loc.lode != nil:
  169. add(result, '^')
  170. encodeNode(w, unknownLineInfo(), loc.lode, result)
  171. #encodeVInt(cast[int32](loc.t.id), result)
  172. #pushType(w, loc.t)
  173. if loc.r != nil:
  174. add(result, '!')
  175. encodeStr($loc.r, result)
  176. if oldLen + 1 == result.len:
  177. # no data was necessary, so remove the '<' again:
  178. setLen(result, oldLen)
  179. else:
  180. add(result, '>')
  181. proc encodeType(w: PRodWriter, t: PType, result: var string) =
  182. if t == nil:
  183. # nil nodes have to be stored too:
  184. result.add("[]")
  185. return
  186. # we need no surrounding [] here because the type is in a line of its own
  187. if t.kind == tyForward: internalError("encodeType: tyForward")
  188. # for the new rodfile viewer we use a preceding [ so that the data section
  189. # can easily be disambiguated:
  190. add(result, '[')
  191. encodeVInt(ord(t.kind), result)
  192. add(result, '+')
  193. encodeVInt(t.id, result)
  194. if t.n != nil:
  195. encodeNode(w, unknownLineInfo(), t.n, result)
  196. if t.flags != {}:
  197. add(result, '$')
  198. encodeVInt(cast[int32](t.flags), result)
  199. if t.callConv != low(t.callConv):
  200. add(result, '?')
  201. encodeVInt(ord(t.callConv), result)
  202. if t.owner != nil:
  203. add(result, '*')
  204. encodeVInt(t.owner.id, result)
  205. pushSym(w, t.owner)
  206. if t.sym != nil:
  207. add(result, '&')
  208. encodeVInt(t.sym.id, result)
  209. pushSym(w, t.sym)
  210. if t.size != - 1:
  211. add(result, '/')
  212. encodeVBiggestInt(t.size, result)
  213. if t.align != 2:
  214. add(result, '=')
  215. encodeVInt(t.align, result)
  216. if t.lockLevel.ord != UnspecifiedLockLevel.ord:
  217. add(result, '\14')
  218. encodeVInt(t.lockLevel.int16, result)
  219. if t.destructor != nil and t.destructor.id != 0:
  220. add(result, '\15')
  221. encodeVInt(t.destructor.id, result)
  222. pushSym(w, t.destructor)
  223. if t.deepCopy != nil:
  224. add(result, '\16')
  225. encodeVInt(t.deepcopy.id, result)
  226. pushSym(w, t.deepcopy)
  227. if t.assignment != nil:
  228. add(result, '\17')
  229. encodeVInt(t.assignment.id, result)
  230. pushSym(w, t.assignment)
  231. if t.sink != nil:
  232. add(result, '\18')
  233. encodeVInt(t.sink.id, result)
  234. pushSym(w, t.sink)
  235. for i, s in items(t.methods):
  236. add(result, '\19')
  237. encodeVInt(i, result)
  238. add(result, '\20')
  239. encodeVInt(s.id, result)
  240. pushSym(w, s)
  241. encodeLoc(w, t.loc, result)
  242. for i in countup(0, sonsLen(t) - 1):
  243. if t.sons[i] == nil:
  244. add(result, "^()")
  245. else:
  246. add(result, '^')
  247. encodeVInt(t.sons[i].id, result)
  248. pushType(w, t.sons[i])
  249. proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) =
  250. add(result, '|')
  251. encodeVInt(ord(lib.kind), result)
  252. add(result, '|')
  253. encodeStr($lib.name, result)
  254. add(result, '|')
  255. encodeNode(w, info, lib.path, result)
  256. proc encodeInstantiations(w: PRodWriter; s: seq[PInstantiation];
  257. result: var string) =
  258. for t in s:
  259. result.add('\15')
  260. encodeVInt(t.sym.id, result)
  261. pushSym(w, t.sym)
  262. for tt in t.concreteTypes:
  263. result.add('\17')
  264. encodeVInt(tt.id, result)
  265. pushType(w, tt)
  266. result.add('\20')
  267. encodeVInt(t.compilesId, result)
  268. proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
  269. if s == nil:
  270. # nil nodes have to be stored too:
  271. result.add("{}")
  272. return
  273. # we need no surrounding {} here because the symbol is in a line of its own
  274. encodeVInt(ord(s.kind), result)
  275. result.add('+')
  276. encodeVInt(s.id, result)
  277. result.add('&')
  278. encodeStr(s.name.s, result)
  279. if s.typ != nil:
  280. result.add('^')
  281. encodeVInt(s.typ.id, result)
  282. pushType(w, s.typ)
  283. result.add('?')
  284. if s.info.col != -1'i16: encodeVInt(s.info.col, result)
  285. result.add(',')
  286. if s.info.line != -1'i16: encodeVInt(s.info.line, result)
  287. result.add(',')
  288. encodeVInt(fileIdx(w, toFullPath(s.info)), result)
  289. if s.owner != nil:
  290. result.add('*')
  291. encodeVInt(s.owner.id, result)
  292. pushSym(w, s.owner)
  293. if s.flags != {}:
  294. result.add('$')
  295. encodeVInt(cast[int32](s.flags), result)
  296. if s.magic != mNone:
  297. result.add('@')
  298. encodeVInt(ord(s.magic), result)
  299. if s.options != w.options:
  300. result.add('!')
  301. encodeVInt(cast[int32](s.options), result)
  302. if s.position != 0:
  303. result.add('%')
  304. encodeVInt(s.position, result)
  305. if s.offset != - 1:
  306. result.add('`')
  307. encodeVInt(s.offset, result)
  308. encodeLoc(w, s.loc, result)
  309. if s.annex != nil: encodeLib(w, s.annex, s.info, result)
  310. if s.constraint != nil:
  311. add(result, '#')
  312. encodeNode(w, unknownLineInfo(), s.constraint, result)
  313. case s.kind
  314. of skType, skGenericParam:
  315. for t in s.typeInstCache:
  316. result.add('\14')
  317. encodeVInt(t.id, result)
  318. pushType(w, t)
  319. of routineKinds:
  320. encodeInstantiations(w, s.procInstCache, result)
  321. if s.gcUnsafetyReason != nil:
  322. result.add('\16')
  323. encodeVInt(s.gcUnsafetyReason.id, result)
  324. pushSym(w, s.gcUnsafetyReason)
  325. of skModule, skPackage:
  326. encodeInstantiations(w, s.usedGenerics, result)
  327. # we don't serialize:
  328. #tab*: TStrTable # interface table for modules
  329. of skLet, skVar, skField, skForVar:
  330. if s.guard != nil:
  331. result.add('\18')
  332. encodeVInt(s.guard.id, result)
  333. pushSym(w, s.guard)
  334. if s.bitsize != 0:
  335. result.add('\19')
  336. encodeVInt(s.bitsize, result)
  337. else: discard
  338. # lazy loading will soon reload the ast lazily, so the ast needs to be
  339. # the last entry of a symbol:
  340. if s.ast != nil:
  341. # we used to attempt to save space here by only storing a dummy AST if
  342. # it is not necessary, but Nim's heavy compile-time evaluation features
  343. # make that unfeasible nowadays:
  344. encodeNode(w, s.info, s.ast, result)
  345. proc addToIndex(w: var TIndex, key, val: int) =
  346. if key - w.lastIdxKey == 1:
  347. # we do not store a key-diff of 1 to safe space
  348. encodeVInt(val - w.lastIdxVal, w.r)
  349. else:
  350. encodeVInt(key - w.lastIdxKey, w.r)
  351. add(w.r, ' ')
  352. encodeVInt(val - w.lastIdxVal, w.r)
  353. add(w.r, rodNL)
  354. w.lastIdxKey = key
  355. w.lastIdxVal = val
  356. iiTablePut(w.tab, key, val)
  357. const debugWrittenIds = false
  358. when debugWrittenIds:
  359. var debugWritten = initIntSet()
  360. proc symStack(w: PRodWriter): int =
  361. var i = 0
  362. while i < len(w.sstack):
  363. var s = w.sstack[i]
  364. if sfForward in s.flags:
  365. w.sstack[result] = s
  366. inc result
  367. elif iiTableGet(w.index.tab, s.id) == InvalidKey:
  368. var m = getModule(s)
  369. if m == nil and s.kind != skPackage and sfGenSym notin s.flags:
  370. internalError("symStack: module nil: " & s.name.s)
  371. if s.kind == skPackage or {sfFromGeneric, sfGenSym} * s.flags != {} or m.id == w.module.id:
  372. # put definition in here
  373. var L = w.data.len
  374. addToIndex(w.index, s.id, L)
  375. when debugWrittenIds: incl(debugWritten, s.id)
  376. encodeSym(w, s, w.data)
  377. add(w.data, rodNL)
  378. # put into interface section if appropriate:
  379. if {sfExported, sfFromGeneric} * s.flags == {sfExported} and
  380. s.kind in ExportableSymKinds:
  381. encodeStr(s.name.s, w.interf)
  382. add(w.interf, ' ')
  383. encodeVInt(s.id, w.interf)
  384. add(w.interf, rodNL)
  385. if sfCompilerProc in s.flags:
  386. encodeStr(s.name.s, w.compilerProcs)
  387. add(w.compilerProcs, ' ')
  388. encodeVInt(s.id, w.compilerProcs)
  389. add(w.compilerProcs, rodNL)
  390. if s.kind == skConverter or hasPattern(s):
  391. if w.converters.len != 0: add(w.converters, ' ')
  392. encodeVInt(s.id, w.converters)
  393. if s.kind == skMethod and sfDispatcher notin s.flags:
  394. if w.methods.len != 0: add(w.methods, ' ')
  395. encodeVInt(s.id, w.methods)
  396. elif iiTableGet(w.imports.tab, s.id) == InvalidKey:
  397. addToIndex(w.imports, s.id, m.id)
  398. when debugWrittenIds:
  399. if not contains(debugWritten, s.id):
  400. echo(w.filename)
  401. debug(s)
  402. debug(s.owner)
  403. debug(m)
  404. internalError("Symbol referred to but never written")
  405. inc(i)
  406. setLen(w.sstack, result)
  407. proc typeStack(w: PRodWriter): int =
  408. var i = 0
  409. while i < len(w.tstack):
  410. var t = w.tstack[i]
  411. if t.kind == tyForward:
  412. w.tstack[result] = t
  413. inc result
  414. elif iiTableGet(w.index.tab, t.id) == InvalidKey:
  415. var L = w.data.len
  416. addToIndex(w.index, t.id, L)
  417. encodeType(w, t, w.data)
  418. add(w.data, rodNL)
  419. inc(i)
  420. setLen(w.tstack, result)
  421. proc processStacks(w: PRodWriter, finalPass: bool) =
  422. var oldS = 0
  423. var oldT = 0
  424. while true:
  425. var slen = symStack(w)
  426. var tlen = typeStack(w)
  427. if slen == oldS and tlen == oldT: break
  428. oldS = slen
  429. oldT = tlen
  430. if finalPass and (oldS != 0 or oldT != 0):
  431. internalError("could not serialize some forwarded symbols/types")
  432. proc rawAddInterfaceSym(w: PRodWriter, s: PSym) =
  433. pushSym(w, s)
  434. processStacks(w, false)
  435. proc addInterfaceSym(w: PRodWriter, s: PSym) =
  436. if w == nil: return
  437. if s.kind in ExportableSymKinds and
  438. {sfExported, sfCompilerProc} * s.flags != {}:
  439. rawAddInterfaceSym(w, s)
  440. proc addStmt(w: PRodWriter, n: PNode) =
  441. encodeVInt(w.data.len, w.init)
  442. add(w.init, rodNL)
  443. encodeNode(w, unknownLineInfo(), n, w.data)
  444. add(w.data, rodNL)
  445. processStacks(w, false)
  446. proc writeRod(w: PRodWriter) =
  447. processStacks(w, true)
  448. var f: File
  449. if not open(f, completeGeneratedFilePath(changeFileExt(
  450. w.filename.withPackageName, RodExt)),
  451. fmWrite):
  452. #echo "couldn't write rod file for: ", w.filename
  453. return
  454. # write header:
  455. f.write("NIM:")
  456. f.write(RodFileVersion)
  457. f.write(rodNL)
  458. var id = "ID:"
  459. encodeVInt(w.module.id, id)
  460. f.write(id)
  461. f.write(rodNL)
  462. var orig = "ORIGFILE:"
  463. encodeStr(w.origFile, orig)
  464. f.write(orig)
  465. f.write(rodNL)
  466. var hash = "HASH:"
  467. encodeStr($w.hash, hash)
  468. f.write(hash)
  469. f.write(rodNL)
  470. var options = "OPTIONS:"
  471. encodeVInt(cast[int32](w.options), options)
  472. f.write(options)
  473. f.write(rodNL)
  474. var goptions = "GOPTIONS:"
  475. encodeVInt(cast[int32](gGlobalOptions), goptions)
  476. f.write(goptions)
  477. f.write(rodNL)
  478. var cmd = "CMD:"
  479. encodeVInt(cast[int32](gCmd), cmd)
  480. f.write(cmd)
  481. f.write(rodNL)
  482. f.write("DEFINES:")
  483. f.write(w.defines)
  484. f.write(rodNL)
  485. var files = "FILES(" & rodNL
  486. for i in countup(0, high(w.files)):
  487. encodeStr(w.files[i], files)
  488. files.add(rodNL)
  489. f.write(files)
  490. f.write(')' & rodNL)
  491. f.write("INCLUDES(" & rodNL)
  492. f.write(w.inclDeps)
  493. f.write(')' & rodNL)
  494. f.write("DEPS:")
  495. f.write(w.modDeps)
  496. f.write(rodNL)
  497. f.write("INTERF(" & rodNL)
  498. f.write(w.interf)
  499. f.write(')' & rodNL)
  500. f.write("COMPILERPROCS(" & rodNL)
  501. f.write(w.compilerProcs)
  502. f.write(')' & rodNL)
  503. f.write("INDEX(" & rodNL)
  504. f.write(w.index.r)
  505. f.write(')' & rodNL)
  506. f.write("IMPORTS(" & rodNL)
  507. f.write(w.imports.r)
  508. f.write(')' & rodNL)
  509. f.write("CONVERTERS:")
  510. f.write(w.converters)
  511. f.write(rodNL)
  512. f.write("METHODS:")
  513. f.write(w.methods)
  514. f.write(rodNL)
  515. f.write("INIT(" & rodNL)
  516. f.write(w.init)
  517. f.write(')' & rodNL)
  518. f.write("DATA(" & rodNL)
  519. f.write(w.data)
  520. f.write(')' & rodNL)
  521. # write trailing zero which is necessary because we use memory mapped files
  522. # for reading:
  523. f.write("\0")
  524. f.close()
  525. #echo "interf: ", w.interf.len
  526. #echo "index: ", w.index.r.len
  527. #echo "init: ", w.init.len
  528. #echo "data: ", w.data.len
  529. proc process(c: PPassContext, n: PNode): PNode =
  530. result = n
  531. if c == nil: return
  532. var w = PRodWriter(c)
  533. case n.kind
  534. of nkStmtList:
  535. for i in countup(0, sonsLen(n) - 1): discard process(c, n.sons[i])
  536. #var s = n.sons[namePos].sym
  537. #addInterfaceSym(w, s)
  538. of nkProcDef, nkFuncDef, nkIteratorDef, nkConverterDef,
  539. nkTemplateDef, nkMacroDef:
  540. let s = n.sons[namePos].sym
  541. if s == nil: internalError(n.info, "rodwrite.process")
  542. if n.sons[bodyPos] == nil:
  543. internalError(n.info, "rodwrite.process: body is nil")
  544. if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
  545. sfForward notin s.flags:
  546. addInterfaceSym(w, s)
  547. of nkMethodDef:
  548. let s = n.sons[namePos].sym
  549. if s == nil: internalError(n.info, "rodwrite.process")
  550. if n.sons[bodyPos] == nil:
  551. internalError(n.info, "rodwrite.process: body is nil")
  552. if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
  553. sfForward notin s.flags:
  554. pushSym(w, s)
  555. processStacks(w, false)
  556. of nkVarSection, nkLetSection, nkConstSection:
  557. for i in countup(0, sonsLen(n) - 1):
  558. var a = n.sons[i]
  559. if a.kind == nkCommentStmt: continue
  560. addInterfaceSym(w, a.sons[0].sym)
  561. of nkTypeSection:
  562. for i in countup(0, sonsLen(n) - 1):
  563. var a = n.sons[i]
  564. if a.kind == nkCommentStmt: continue
  565. if a.sons[0].kind != nkSym: internalError(a.info, "rodwrite.process")
  566. var s = a.sons[0].sym
  567. addInterfaceSym(w, s)
  568. # this takes care of enum fields too
  569. # Note: The check for ``s.typ.kind = tyEnum`` is wrong for enum
  570. # type aliasing! Otherwise the same enum symbol would be included
  571. # several times!
  572. #
  573. # if (a.sons[2] <> nil) and (a.sons[2].kind = nkEnumTy) then begin
  574. # a := s.typ.n;
  575. # for j := 0 to sonsLen(a)-1 do
  576. # addInterfaceSym(w, a.sons[j].sym);
  577. # end
  578. of nkImportStmt:
  579. for i in countup(0, sonsLen(n) - 1):
  580. addModDep(w, getModuleName(n.sons[i]), n.info)
  581. addStmt(w, n)
  582. of nkFromStmt, nkImportExceptStmt:
  583. addModDep(w, getModuleName(n.sons[0]), n.info)
  584. addStmt(w, n)
  585. of nkIncludeStmt:
  586. for i in countup(0, sonsLen(n) - 1):
  587. addInclDep(w, getModuleName(n.sons[i]), n.info)
  588. of nkPragma:
  589. addStmt(w, n)
  590. else:
  591. discard
  592. proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
  593. if module.id < 0: internalError("rodwrite: module ID not set")
  594. var w = newRodWriter(module.fileIdx.getHash, module, cache)
  595. rawAddInterfaceSym(w, module)
  596. result = w
  597. proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
  598. result = process(c, n)
  599. var w = PRodWriter(c)
  600. writeRod(w)
  601. idgen.saveMaxIds(options.gProjectPath / options.gProjectName)
  602. const rodwritePass* = makePass(open = myOpen, close = myClose, process = process)