diff options
Diffstat (limited to 'compiler/ccgmerge_unused.nim')
-rw-r--r-- | compiler/ccgmerge_unused.nim | 283 |
1 files changed, 283 insertions, 0 deletions
diff --git a/compiler/ccgmerge_unused.nim b/compiler/ccgmerge_unused.nim new file mode 100644 index 000000000..a1413034f --- /dev/null +++ b/compiler/ccgmerge_unused.nim @@ -0,0 +1,283 @@ +# +# +# The Nim Compiler +# (c) Copyright 2012 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module implements the merge operation of 2 different C files. This +## is needed for incremental compilation. + +import + ast, ropes, options, strutils, nimlexbase, cgendata, rodutils, + intsets, llstream, tables, modulegraphs, pathutils + +# Careful! Section marks need to contain a tabulator so that they cannot +# be part of C string literals. + +const + CFileSectionNames: array[TCFileSection, string] = [ + cfsHeaders: "NIM_merge_HEADERS", + cfsFrameDefines: "NIM_merge_FRAME_DEFINES", + cfsForwardTypes: "NIM_merge_FORWARD_TYPES", + cfsTypes: "NIM_merge_TYPES", + cfsSeqTypes: "NIM_merge_SEQ_TYPES", + cfsTypeInfo: "NIM_merge_TYPE_INFO", + cfsProcHeaders: "NIM_merge_PROC_HEADERS", + cfsData: "NIM_merge_DATA", + cfsVars: "NIM_merge_VARS", + cfsProcs: "NIM_merge_PROCS", + cfsInitProc: "NIM_merge_INIT_PROC", + cfsDatInitProc: "NIM_merge_DATINIT_PROC", + cfsTypeInit1: "NIM_merge_TYPE_INIT1", + cfsTypeInit3: "NIM_merge_TYPE_INIT3", + cfsDynLibInit: "NIM_merge_DYNLIB_INIT" + ] + CProcSectionNames: array[TCProcSection, string] = [ + cpsLocals: "NIM_merge_PROC_LOCALS", + cpsInit: "NIM_merge_PROC_INIT", + cpsStmts: "NIM_merge_PROC_BODY" + ] + NimMergeEndMark = "/*\tNIM_merge_END:*/" + +proc genSectionStart*(fs: TCFileSection; conf: ConfigRef): Rope = + # useful for debugging and only adds at most a few lines in each file + result.add("\n/* section: ") + result.add(CFileSectionNames[fs]) + result.add(" */\n") + if compilationCachePresent(conf): + result = nil + result.add("\n/*\t") + result.add(CFileSectionNames[fs]) + result.add(":*/\n") + +proc genSectionEnd*(fs: TCFileSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = rope(NimMergeEndMark & "\n") + +proc genSectionStart*(ps: TCProcSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = rope("") + result.add("\n/*\t") + result.add(CProcSectionNames[ps]) + result.add(":*/\n") + +proc genSectionEnd*(ps: TCProcSection; conf: ConfigRef): Rope = + if compilationCachePresent(conf): + result = rope(NimMergeEndMark & "\n") + +proc writeTypeCache(a: TypeCache, s: var string) = + var i = 0 + for id, value in pairs(a): + if i == 10: + i = 0 + s.add('\L') + else: + s.add(' ') + encodeStr($id, s) + s.add(':') + encodeStr($value, s) + inc i + s.add('}') + +proc writeIntSet(a: IntSet, s: var string) = + var i = 0 + for x in items(a): + if i == 10: + i = 0 + s.add('\L') + else: + s.add(' ') + encodeVInt(x, s) + inc i + s.add('}') + +proc genMergeInfo*(m: BModule): Rope = + if not compilationCachePresent(m.config): return nil + var s = "/*\tNIM_merge_INFO:\n" + s.add("typeCache:{") + writeTypeCache(m.typeCache, s) + s.add("declared:{") + writeIntSet(m.declaredThings, s) + when false: + s.add("typeInfo:{") + writeIntSet(m.typeInfoMarker, s) + s.add("labels:") + encodeVInt(m.labels, s) + s.add(" flags:") + encodeVInt(cast[int](m.flags), s) + s.add("\n*/") + result = s.rope + +template `^`(pos: int): untyped = L.buf[pos] + +proc skipWhite(L: var TBaseLexer) = + var pos = L.bufpos + while true: + case ^pos + of CR: pos = nimlexbase.handleCR(L, pos) + of LF: pos = nimlexbase.handleLF(L, pos) + of ' ': inc pos + else: break + L.bufpos = pos + +proc skipUntilCmd(L: var TBaseLexer) = + var pos = L.bufpos + while true: + case ^pos + of CR: pos = nimlexbase.handleCR(L, pos) + of LF: pos = nimlexbase.handleLF(L, pos) + of '\0': break + of '/': + if ^(pos+1) == '*' and ^(pos+2) == '\t': + inc pos, 3 + break + inc pos + else: inc pos + L.bufpos = pos + +proc atEndMark(buf: cstring, pos: int): bool = + var s = 0 + while s < NimMergeEndMark.len and buf[pos+s] == NimMergeEndMark[s]: inc s + result = s == NimMergeEndMark.len + +proc readVerbatimSection(L: var TBaseLexer): Rope = + var pos = L.bufpos + var r = newStringOfCap(30_000) + while true: + case L.buf[pos] + of CR: + pos = nimlexbase.handleCR(L, pos) + r.add('\L') + of LF: + pos = nimlexbase.handleLF(L, pos) + r.add('\L') + of '\0': + doAssert(false, "ccgmerge: expected: " & NimMergeEndMark) + break + else: + if atEndMark(L.buf, pos): + inc pos, NimMergeEndMark.len + break + r.add(L.buf[pos]) + inc pos + L.bufpos = pos + result = r.rope + +proc readKey(L: var TBaseLexer, result: var string) = + var pos = L.bufpos + setLen(result, 0) + while L.buf[pos] in IdentChars: + result.add(L.buf[pos]) + inc pos + if L.buf[pos] != ':': doAssert(false, "ccgmerge: ':' expected") + L.bufpos = pos + 1 # skip ':' + +proc readTypeCache(L: var TBaseLexer, result: var TypeCache) = + if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") + inc L.bufpos + while ^L.bufpos != '}': + skipWhite(L) + var key = decodeStr(L.buf, L.bufpos) + if ^L.bufpos != ':': doAssert(false, "ccgmerge: ':' expected") + inc L.bufpos + discard decodeStr(L.buf, L.bufpos) + inc L.bufpos + +proc readIntSet(L: var TBaseLexer, result: var IntSet) = + if ^L.bufpos != '{': doAssert(false, "ccgmerge: '{' expected") + inc L.bufpos + while ^L.bufpos != '}': + skipWhite(L) + var key = decodeVInt(L.buf, L.bufpos) + result.incl(key) + inc L.bufpos + +proc processMergeInfo(L: var TBaseLexer, m: BModule) = + var k = newStringOfCap("typeCache".len) + while true: + skipWhite(L) + if ^L.bufpos == '*' and ^(L.bufpos+1) == '/': + inc(L.bufpos, 2) + break + readKey(L, k) + case k + of "typeCache": readTypeCache(L, m.typeCache) + of "declared": readIntSet(L, m.declaredThings) + of "typeInfo": + when false: readIntSet(L, m.typeInfoMarker) + of "labels": m.labels = decodeVInt(L.buf, L.bufpos) + of "flags": + m.flags = cast[set[CodegenFlag]](decodeVInt(L.buf, L.bufpos) != 0) + else: doAssert(false, "ccgmerge: unknown key: " & k) + +template withCFile(cfilename: AbsoluteFile, body: untyped) = + var s = llStreamOpen(cfilename, fmRead) + if s == nil: return + var L {.inject.}: TBaseLexer + openBaseLexer(L, s) + var k {.inject.} = newStringOfCap("NIM_merge_FORWARD_TYPES".len) + while true: + skipUntilCmd(L) + if ^L.bufpos == '\0': break + body + closeBaseLexer(L) + +proc readMergeInfo*(cfilename: AbsoluteFile, m: BModule) = + ## reads the merge meta information into `m`. + withCFile(cfilename): + readKey(L, k) + if k == "NIM_merge_INFO": + processMergeInfo(L, m) + break + +type + TMergeSections = object + f: TCFileSections + p: TCProcSections + +proc readMergeSections(cfilename: AbsoluteFile, m: var TMergeSections) = + ## reads the merge sections into `m`. + withCFile(cfilename): + readKey(L, k) + if k == "NIM_merge_INFO": + discard + elif ^L.bufpos == '*' and ^(L.bufpos+1) == '/': + inc(L.bufpos, 2) + # read back into section + skipWhite(L) + var verbatim = readVerbatimSection(L) + skipWhite(L) + var sectionA = CFileSectionNames.find(k) + if sectionA > 0 and sectionA <= high(TCFileSection).int: + m.f[TCFileSection(sectionA)] = verbatim + else: + var sectionB = CProcSectionNames.find(k) + if sectionB >= 0 and sectionB <= high(TCProcSection).int: + m.p[TCProcSection(sectionB)] = verbatim + else: + doAssert(false, "ccgmerge: unknown section: " & k) + else: + doAssert(false, "ccgmerge: '*/' expected") + +proc mergeRequired*(m: BModule): bool = + for i in cfsHeaders..cfsProcs: + if m.s[i] != nil: + #echo "not empty: ", i, " ", m.s[i] + return true + for i in TCProcSection: + if m.initProc.s(i) != nil: + #echo "not empty: ", i, " ", m.initProc.s[i] + return true + +proc mergeFiles*(cfilename: AbsoluteFile, m: BModule) = + ## merges the C file with the old version on hard disc. + var old: TMergeSections + readMergeSections(cfilename, old) + # do the merge; old section before new section: + for i in TCFileSection: + m.s[i] = old.f[i] & m.s[i] + for i in TCProcSection: + m.initProc.s(i) = old.p[i] & m.initProc.s(i) |