ccgmerge_unused.nim 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 implements the merge operation of 2 different C files. This
  10. ## is needed for incremental compilation.
  11. import
  12. ast, ropes, options, strutils, nimlexbase, cgendata, rodutils,
  13. intsets, llstream, tables, modulegraphs, pathutils
  14. # Careful! Section marks need to contain a tabulator so that they cannot
  15. # be part of C string literals.
  16. const
  17. CFileSectionNames: array[TCFileSection, string] = [
  18. cfsHeaders: "NIM_merge_HEADERS",
  19. cfsFrameDefines: "NIM_merge_FRAME_DEFINES",
  20. cfsForwardTypes: "NIM_merge_FORWARD_TYPES",
  21. cfsTypes: "NIM_merge_TYPES",
  22. cfsSeqTypes: "NIM_merge_SEQ_TYPES",
  23. cfsTypeInfo: "NIM_merge_TYPE_INFO",
  24. cfsProcHeaders: "NIM_merge_PROC_HEADERS",
  25. cfsData: "NIM_merge_DATA",
  26. cfsVars: "NIM_merge_VARS",
  27. cfsProcs: "NIM_merge_PROCS",
  28. cfsInitProc: "NIM_merge_INIT_PROC",
  29. cfsDatInitProc: "NIM_merge_DATINIT_PROC",
  30. cfsTypeInit1: "NIM_merge_TYPE_INIT1",
  31. cfsTypeInit3: "NIM_merge_TYPE_INIT3",
  32. cfsDynLibInit: "NIM_merge_DYNLIB_INIT"
  33. ]
  34. CProcSectionNames: array[TCProcSection, string] = [
  35. cpsLocals: "NIM_merge_PROC_LOCALS",
  36. cpsInit: "NIM_merge_PROC_INIT",
  37. cpsStmts: "NIM_merge_PROC_BODY"
  38. ]
  39. NimMergeEndMark = "/*\tNIM_merge_END:*/"
  40. proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope =
  41. # useful for debugging and only adds at most a few lines in each file
  42. result.add("\n/* section: ")
  43. result.add(CFileSectionNames[fs])
  44. result.add(" */\n")
  45. if compilationCachePresent(conf):
  46. result = nil
  47. result.add("\n/*\t")
  48. result.add(CFileSectionNames[fs])
  49. result.add(":*/\n")
  50. proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope =
  51. if compilationCachePresent(conf):
  52. result = rope(NimMergeEndMark & "\n")
  53. proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope =
  54. if compilationCachePresent(conf):
  55. result = rope("")
  56. result.add("\n/*\t")
  57. result.add(CProcSectionNames[ps])
  58. result.add(":*/\n")
  59. proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope =
  60. if compilationCachePresent(conf):
  61. result = rope(NimMergeEndMark & "\n")
  62. proc writeTypeCache(a: TypeCache, s: var string) =
  63. var i = 0
  64. for id, value in pairs(a):
  65. if i == 10:
  66. i = 0
  67. s.add('\L')
  68. else:
  69. s.add(' ')
  70. encodeStr($id, s)
  71. s.add(':')
  72. encodeStr($value, s)
  73. inc i
  74. s.add('}')
  75. proc writeIntSet(a: IntSet, s: var string) =
  76. var i = 0
  77. for x in items(a):
  78. if i == 10:
  79. i = 0
  80. s.add('\L')
  81. else:
  82. s.add(' ')
  83. encodeVInt(x, s)
  84. inc i
  85. s.add('}')
  86. proc genMergeInfo*(m: BModule): Rope =
  87. if not compilationCachePresent(m.config): return nil
  88. var s = "/*\tNIM_merge_INFO:\n"
  89. s.add("typeCache:{")
  90. writeTypeCache(m.typeCache, s)
  91. s.add("declared:{")
  92. writeIntSet(m.declaredThings, s)
  93. when false:
  94. s.add("typeInfo:{")
  95. writeIntSet(m.typeInfoMarker, s)
  96. s.add("labels:")
  97. encodeVInt(m.labels, s)
  98. s.add(" flags:")
  99. encodeVInt(cast[int](m.flags), s)
  100. s.add("\n*/")
  101. result = s.rope
  102. template `^`(pos: int): untyped = L.buf[pos]
  103. proc skipWhite(L: var TBaseLexer) =
  104. var pos = L.bufpos
  105. while true:
  106. case ^pos
  107. of CR: pos = nimlexbase.handleCR(L, pos)
  108. of LF: pos = nimlexbase.handleLF(L, pos)
  109. of ' ': inc pos
  110. else: break
  111. L.bufpos = pos
  112. proc skipUntilCmd(L: var TBaseLexer) =
  113. var pos = L.bufpos
  114. while true:
  115. case ^pos
  116. of CR: pos = nimlexbase.handleCR(L, pos)
  117. of LF: pos = nimlexbase.handleLF(L, pos)
  118. of '\0': break
  119. of '/':
  120. if ^(pos+1) == '*' and ^(pos+2) == '\t':
  121. inc pos, 3
  122. break
  123. inc pos
  124. else: inc pos
  125. L.bufpos = pos
  126. proc atEndMark(buf: cstring, pos: int): bool =
  127. var s = 0
  128. while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s
  129. result = s == NimMergeEndMark.len
  130. proc readVerbatimSection(L: var TBaseLexer): Rope =
  131. var pos = L.bufpos
  132. var r = newStringOfCap(30_000)
  133. while true:
  134. case L.buf[pos]
  135. of CR:
  136. pos = nimlexbase.handleCR(L, pos)
  137. r.add('\L')
  138. of LF:
  139. pos = nimlexbase.handleLF(L, pos)
  140. r.add('\L')
  141. of '\0':
  142. doAssert(false, "ccgmerge: expected: " & NimMergeEndMark)
  143. break
  144. else:
  145. if atEndMark(L.buf, pos):
  146. inc pos, NimMergeEndMark.len
  147. break
  148. r.add(L.buf[pos])
  149. inc pos
  150. L.bufpos = pos
  151. result = r.rope
  152. proc readKey(L: var TBaseLexer, result: var string) =
  153. var pos = L.bufpos
  154. setLen(result, 0)
  155. while L.buf[pos] in IdentChars:
  156. result.add(L.buf[pos])
  157. inc pos
  158. if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected")
  159. L.bufpos = pos + 1 # skip ':'
  160. proc readTypeCache(L: var TBaseLexer, result: var TypeCache) =
  161. if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
  162. inc L.bufpos
  163. while ^L.bufpos != '}':
  164. skipWhite(L)
  165. var key = decodeStr(L.buf, L.bufpos)
  166. if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected")
  167. inc L.bufpos
  168. discard decodeStr(L.buf, L.bufpos)
  169. inc L.bufpos
  170. proc readIntSet(L: var TBaseLexer, result: var IntSet) =
  171. if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected")
  172. inc L.bufpos
  173. while ^L.bufpos != '}':
  174. skipWhite(L)
  175. var key = decodeVInt(L.buf, L.bufpos)
  176. result.incl(key)
  177. inc L.bufpos
  178. proc processMergeInfo(L: var TBaseLexer, m: BModule) =
  179. var k = newStringOfCap("typeCache".len)
  180. while true:
  181. skipWhite(L)
  182. if ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
  183. inc(L.bufpos, 2)
  184. break
  185. readKey(L, k)
  186. case k
  187. of "typeCache": readTypeCache(L, m.typeCache)
  188. of "declared": readIntSet(L, m.declaredThings)
  189. of "typeInfo":
  190. when false: readIntSet(L, m.typeInfoMarker)
  191. of "labels": m.labels = decodeVInt(L.buf, L.bufpos)
  192. of "flags":
  193. m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0)
  194. else: doAssert(false, "ccgmerge: unknown key: " & k)
  195. template withCFile(cfilename: AbsoluteFile, body: untyped) =
  196. var s = llStreamOpen(cfilename, fmRead)
  197. if s == nil: return
  198. var L {.inject.}: TBaseLexer
  199. openBaseLexer(L, s)
  200. var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len)
  201. while true:
  202. skipUntilCmd(L)
  203. if ^L.bufpos == '\0': break
  204. body
  205. closeBaseLexer(L)
  206. proc readMergeInfo*(cfilename: AbsoluteFile, m: BModule) =
  207. ## reads the merge meta information into `m`.
  208. withCFile(cfilename):
  209. readKey(L, k)
  210. if k == "NIM_merge_INFO":
  211. processMergeInfo(L, m)
  212. break
  213. type
  214. TMergeSections = object
  215. f: TCFileSections
  216. p: TCProcSections
  217. proc readMergeSections(cfilename: AbsoluteFile, m: var TMergeSections) =
  218. ## reads the merge sections into `m`.
  219. withCFile(cfilename):
  220. readKey(L, k)
  221. if k == "NIM_merge_INFO":
  222. discard
  223. elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/':
  224. inc(L.bufpos, 2)
  225. # read back into section
  226. skipWhite(L)
  227. var verbatim = readVerbatimSection(L)
  228. skipWhite(L)
  229. var sectionA = CFileSectionNames.find(k)
  230. if sectionA > 0 and sectionA <= high(TCFileSection).int:
  231. m.f[TCFileSection(sectionA)] = verbatim
  232. else:
  233. var sectionB = CProcSectionNames.find(k)
  234. if sectionB >= 0 and sectionB <= high(TCProcSection).int:
  235. m.p[TCProcSection(sectionB)] = verbatim
  236. else:
  237. doAssert(false, "ccgmerge: unknown section: " & k)
  238. else:
  239. doAssert(false, "ccgmerge: '*/' expected")
  240. proc mergeRequired*(m: BModule): bool =
  241. for i in cfsHeaders..cfsProcs:
  242. if m.s[i] != nil:
  243. #echo "not empty: ", i, " ", m.s[i]
  244. return true
  245. for i in TCProcSection:
  246. if m.initProc.s(i) != nil:
  247. #echo "not empty: ", i, " ", m.initProc.s[i]
  248. return true
  249. proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) =
  250. ## merges the C file with the old version on hard disc.
  251. var old: TMergeSections
  252. readMergeSections(cfilename, old)
  253. # do the merge; old section before new section:
  254. for i in TCFileSection:
  255. m.s[i] = old.f[i] & m.s[i]
  256. for i in TCProcSection:
  257. m.initProc.s(i) = old.p[i] & m.initProc.s(i)