ccgmerge_unused.nim 8.1 KB

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