diff options
Diffstat (limited to 'compiler')
-rwxr-xr-x | compiler/astalgo.nim | 5 | ||||
-rw-r--r-- | compiler/ccgmerge.nim | 253 | ||||
-rwxr-xr-x | compiler/cgen.nim | 145 | ||||
-rw-r--r-- | compiler/cgendata.nim | 116 | ||||
-rw-r--r-- | compiler/idgen.nim | 9 | ||||
-rwxr-xr-x | compiler/rodutils.nim | 4 | ||||
-rwxr-xr-x | compiler/ropes.nim | 6 |
7 files changed, 422 insertions, 116 deletions
diff --git a/compiler/astalgo.nim b/compiler/astalgo.nim index b06194daf..472a8d803 100755 --- a/compiler/astalgo.nim +++ b/compiler/astalgo.nim @@ -720,6 +720,11 @@ proc IdTableGet(t: TIdTable, key: int): PObject = var index = IdTableRawGet(t, key) if index >= 0: result = t.data[index].val else: result = nil + +iterator pairs*(t: TIdTable): tuple[key: int, value: PObject] = + for i in 0..high(t.data): + if t.data[i].key != nil: + yield (t.data[i].key.id, t.data[i].val) proc IdTableRawInsert(data: var TIdPairSeq, key: PIdObj, val: PObject) = var h: THash diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim new file mode 100644 index 000000000..252b11079 --- /dev/null +++ b/compiler/ccgmerge.nim @@ -0,0 +1,253 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 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, astalgo, ropes, options, strutils, lexbase, msgs, cgendata, rodutils, + intsets, platform, llstream + +# Careful! Section marks need to contain a tabulator so that they cannot +# be part of C string literals. + +const + CFileSectionNames: array[TCFileSection, string] = [ + cfsMergeInfo: "", + cfsHeaders: "NIM_merge_HEADERS", + cfsForwardTypes: "NIM_merge_FORWARD_TYPES", + cfsTypes: "NIM_merge_TYPES", + cfsSeqTypes: "NIM_merge_SEQ_TYPES", + cfsFieldInfo: "NIM_merge_FIELD_INFO", + 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", + cfsTypeInit1: "NIM_merge_TYPE_INIT1", + cfsTypeInit2: "NIM_merge_TYPE_INIT2", + cfsTypeInit3: "NIM_merge_TYPE_INIT3", + cfsDebugInit: "NIM_merge_DEBUG_INIT", + cfsDynLibInit: "NIM_merge_DYNLIB_INIT", + cfsDynLibDeinit: "NIM_merge_DYNLIB_DEINIT", + ] + CProcSectionNames: array[TCProcSection, string] = [ + cpsLocals: "NIM_merge_PROC_LOCALS", + cpsInit: "NIM_merge_PROC_INIT", + cpsStmts: "NIM_merge_PROC_BODY" + ] + +proc genSectionStart*(fs: TCFileSection): PRope = + if optSymbolFiles in gGlobalOptions: + result = toRope(tnl) + app(result, "/*\t") + app(result, CFileSectionNames[fs]) + app(result, "*/") + app(result, tnl) + +proc genSectionEnd*(fs: TCFileSection): PRope = + if optSymbolFiles in gGlobalOptions: + result = toRope("/*\tNIM_merge_END*/" & tnl) + +proc genSectionStart*(ps: TCProcSection): PRope = + if optSymbolFiles in gGlobalOptions: + result = toRope(tnl) + app(result, "/*\t") + app(result, CProcSectionNames[ps]) + app(result, "*/") + app(result, tnl) + +proc genSectionEnd*(ps: TCProcSection): PRope = + if optSymbolFiles in gGlobalOptions: + result = toRope("/*\tNIM_merge_END*/" & tnl) + +proc writeTypeCache(a: TIdTable, s: var string) = + var i = 0 + for id, value in pairs(a): + if i == 10: + i = 0 + s.add(tnl) + else: + s.add(' ') + encodeVInt(id, s) + s.add(':') + encodeStr(PRope(value).ropeToStr, s) + inc i + s.add('}') + +proc writeIntSet(a: TIntSet, s: var string) = + var i = 0 + for x in items(a): + if i == 10: + i = 0 + s.add(tnl) + else: + s.add(' ') + encodeVInt(x, s) + inc i + s.add('}') + +proc genMergeInfo*(m: BModule): PRope = + if optSymbolFiles notin gGlobalOptions: return nil + var s = "/*\tNIM_merge_INFO:" + s.add(tnl) + s.add("typeCache:{") + writeTypeCache(m.typeCache, s) + s.add("declared:{") + writeIntSet(m.declaredThings, s) + s.add("typeInfo:{") + writeIntSet(m.typeInfoMarker, s) + s.add("labels:") + encodeVInt(m.labels, s) + s.add(tnl) + s.add("*/") + result = s.toRope + +template `^`(pos: expr): expr = L.buf[pos] + +proc skipWhite(L: var TBaseLexer) = + var pos = L.bufpos + while true: + case ^pos + of CR: pos = lexbase.HandleCR(L, pos) + of LF: pos = lexbase.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 = lexbase.HandleCR(L, pos) + of LF: pos = lexbase.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 readVerbatimSection(L: var TBaseLexer): PRope = + const section = "/*\tNIM_merge_END*/" + var pos = L.bufpos + var buf = L.buf + result = newMutableRope(30_000) + while true: + case buf[pos] + of CR: + pos = lexbase.HandleCR(L, pos) + buf = L.buf + result.data.add(tnl) + of LF: + pos = lexbase.HandleLF(L, pos) + buf = L.buf + result.data.add(tnl) + of '\0': break + else: nil + if buf[pos] == section[0]: + var s = 0 + while buf[pos+1] == section[s+1]: + inc s + inc pos + if section[s] != '\0': + # reset: + dec pos, s + else: + break + result.data.add(buf[pos]) + inc pos + L.bufpos = pos + result.length = result.data.len + +proc readKey(L: var TBaseLexer): string = + var pos = L.bufpos + var buf = L.buf + while buf[pos] in IdentChars: + result.add(buf[pos]) + inc pos + if buf[pos] != ':': internalError("ccgmerge: ':' expected") + L.bufpos = pos + 1 # skip ':' + +proc NewFakeType(id: int): PType = + new(result) + result.id = id + +proc readTypeCache(L: var TBaseLexer, result: var TIdTable) = + if ^L.bufpos != '{': internalError("ccgmerge: '{' expected") + inc L.bufpos + while ^L.bufpos != '}': + skipWhite(L) + var key = decodeVInt(L.buf, L.bufpos) + if ^L.bufpos != ':': internalError("ccgmerge: ':' expected") + inc L.bufpos + var value = decodeStr(L.buf, L.bufpos) + # XXX little hack: we create a "fake" type object with the correct Id + # better would be to adapt the data structure to not even store the + # object as key, but only the Id + IdTablePut(result, newFakeType(key), value.toRope) + inc L.bufpos + +proc readIntSet(L: var TBaseLexer, result: var TIntSet) = + if ^L.bufpos != '{': internalError("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) = + while true: + skipWhite(L) + if ^L.bufpos == '*' and ^(L.bufpos+1) == '/': + inc(L.bufpos, 2) + break + var k = readKey(L) + case k + of "typeCache": readTypeCache(L, m.typeCache) + of "declared": readIntSet(L, m.declaredThings) + of "typeInfo": readIntSet(L, m.typeInfoMarker) + of "labels": m.labels = decodeVInt(L.buf, L.bufpos) + else: InternalError("ccgmerge: unkown key: " & k) + +proc readMergeInfo*(cfilename: string, m: BModule) = + ## reads the merge information into `m`. + var s = LLStreamOpen(cfilename, fmRead) + if s == nil: return + var L: TBaseLexer + openBaseLexer(L, s) + while true: + skipUntilCmd(L) + if ^L.bufpos == '\0': break + var k = readKey(L) + if k == "NIM_merge_INFO": + processMergeInfo(L, m) + 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.s[TCFileSection(sectionA)] = verbatim + else: + var sectionB = CProcSectionNames.find(k) + if sectionB >= 0 and sectionB <= high(TCProcSection).int: + m.initProc.s[TCProcSection(sectionB)] = verbatim + else: + InternalError("ccgmerge: unknown section: " & k) + else: + InternalError("ccgmerge: */ expected") + closeBaseLexer(L) + diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 7cfcbe098..9c0a1d1f7 100755 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -15,7 +15,7 @@ import options, intsets, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, - rodutils, renderer, idgen + rodutils, renderer, idgen, cgendata, ccgmerge when options.hasTinyCBackend: import tccgen @@ -23,96 +23,6 @@ when options.hasTinyCBackend: proc cgenPass*(): TPass # implementation -type - TLabel = PRope # for the C generator a label is just a rope - TCFileSection = enum # the sections a generated C file consists of - cfsHeaders, # section for C include file headers - cfsForwardTypes, # section for C forward typedefs - cfsTypes, # section for C typedefs - cfsSeqTypes, # section for sequence types only - # this is needed for strange type generation - # reasons - cfsFieldInfo, # section for field information - cfsTypeInfo, # section for type information - cfsProcHeaders, # section for C procs prototypes - cfsData, # section for C constant data - cfsVars, # section for C variable declarations - cfsProcs, # section for C procs that are not inline - cfsTypeInit1, # section 1 for declarations of type information - cfsTypeInit2, # section 2 for init of type information - cfsTypeInit3, # section 3 for init of type information - cfsDebugInit, # section for init of debug information - cfsDynLibInit, # section for init of dynamic library binding - cfsDynLibDeinit # section for deinitialization of dynamic - # libraries - TCTypeKind = enum # describes the type kind of a C type - ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64, - ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64, - ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString - TCFileSections = array[TCFileSection, PRope] # represents a generated C file - TCProcSection = enum # the sections a generated C proc consists of - cpsLocals, # section of local variables for C proc - cpsInit, # section for init of variables for C proc - cpsStmts # section of local statements for C proc - TCProcSections = array[TCProcSection, PRope] # represents a generated C proc - BModule = ref TCGen - BProc = ref TCProc - TBlock{.final.} = object - id*: int # the ID of the label; positive means that it - # has been used (i.e. the label should be emitted) - nestedTryStmts*: int # how many try statements is it nested into - - TCProc{.final.} = object # represents C proc that is currently generated - s: TCProcSections # the procs sections; short name for readability - prc: PSym # the Nimrod proc that this C proc belongs to - BeforeRetNeeded: bool # true iff 'BeforeRet' label for proc is needed - ThreadVarAccessed: bool # true if the proc already accessed some threadvar - nestedTryStmts: seq[PNode] # in how many nested try statements we are - # (the vars must be volatile then) - labels: Natural # for generating unique labels in the C proc - blocks: seq[TBlock] # nested blocks - options: TOptions # options that should be used for code - # generation; this is the same as prc.options - # unless prc == nil - frameLen: int # current length of frame descriptor - sendClosure: PType # closure record type that we pass - receiveClosure: PType # closure record type that we get - module: BModule # used to prevent excessive parameter passing - withinLoop: int # > 0 if we are within a loop - - TTypeSeq = seq[PType] - TCGen = object of TPassContext # represents a C source file - module*: PSym - filename*: string - s*: TCFileSections # sections of the C file - PreventStackTrace: bool # true if stack traces need to be prevented - usesThreadVars: bool # true if the module uses a thread var - cfilename*: string # filename of the module (including path, - # without extension) - typeCache*: TIdTable # cache the generated types - forwTypeCache*: TIdTable # cache for forward declarations of types - declaredThings*: TIntSet # things we have declared in this .c file - declaredProtos*: TIntSet # prototypes we have declared in this .c file - headerFiles*: TLinkedList # needed headers to include - typeInfoMarker*: TIntSet # needed for generating type information - initProc*: BProc # code for init procedure - typeStack*: TTypeSeq # used for type generation - dataCache*: TNodeTable - forwardedProcs*: TSymSeq # keep forwarded procs here - typeNodes*, nimTypes*: int # used for type info generation - typeNodesName*, nimTypesName*: PRope # used for type info generation - labels*: natural # for generating unique module-scope names - -var - mainModProcs, mainModInit: PRope # parts of the main module - gMapping: PRope # the generated mapping file (if requested) - gProcProfile: Natural # proc profile counter - gGeneratedSyms: TIntSet # set of ID's of generated symbols - gPendingModules: seq[BModule] = @[] # list of modules that are not - # finished with code generation - gForwardedProcsCounter: int = 0 - gNimDat: BModule # generated global data - proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope = if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args) else: result = ropef(cformat, args) @@ -157,15 +67,6 @@ proc fillLoc(a: var TLoc, k: TLocKind, typ: PType, r: PRope, s: TStorageLoc) = a.s = s if a.r == nil: a.r = r -proc newProc(prc: PSym, module: BModule): BProc = - new(result) - result.prc = prc - result.module = module - if prc != nil: result.options = prc.options - else: result.options = gOptions - result.blocks = @[] - result.nestedTryStmts = @[] - proc isSimpleConst(typ: PType): bool = result = not (skipTypes(typ, abstractVar).kind in {tyTuple, tyObject, tyArray, tyArrayConstr, tySet, tySequence}) @@ -864,31 +765,53 @@ proc genInitCode(m: BModule) = # BUT: the generated init code might depend on a current frame, so # declare it nevertheless: getFrameDecl(m.initProc) + + app(prc, genSectionStart(cpsLocals)) + app(prc, m.initProc.s[cpsLocals]) + app(prc, genSectionEnd(cpsLocals)) + + app(prc, genSectionStart(cfsTypeInit1)) + app(prc, m.s[cfsTypeInit1]) if optStackTrace in m.initProc.options and not m.PreventStackTrace: - app(prc, m.initProc.s[cpsLocals]) - app(prc, m.s[cfsTypeInit1]) var procname = CStringLit(m.initProc, prc, m.module.name.s) var filename = CStringLit(m.initProc, prc, toFilename(m.module.info)) app(prc, initFrame(m.initProc, procname, filename)) - else: - app(prc, m.initProc.s[cpsLocals]) - app(prc, m.s[cfsTypeInit1]) - app(prc, m.s[cfsTypeInit2]) - app(prc, m.s[cfsTypeInit3]) - app(prc, m.s[cfsDebugInit]) - app(prc, m.s[cfsDynLibInit]) + app(prc, genSectionEnd(cfsTypeInit1)) + + for i in cfsTypeInit2..cfsDynLibInit: + app(prc, genSectionStart(i)) + app(prc, m.s[i]) + app(prc, genSectionEnd(i)) + + app(prc, genSectionStart(cpsInit)) app(prc, m.initProc.s[cpsInit]) + app(prc, genSectionEnd(cpsInit)) + + app(prc, genSectionStart(cpsStmts)) app(prc, m.initProc.s[cpsStmts]) if optStackTrace in m.initProc.options and not m.PreventStackTrace: app(prc, deinitFrame(m.initProc)) + app(prc, genSectionEnd(cpsStmts)) appf(prc, "}$n$n") - app(m.s[cfsProcs], prc) + # we cannot simply add the init proc to ``m.s[cfsProcs]`` anymore because + # that would lead to a *nesting* of merge sections which the merger does + # not support. So we add it to another special section: ``cfsInitProc`` + app(m.s[cfsInitProc], prc) proc genModule(m: BModule, cfilenoext: string): PRope = result = getFileHeader(cfilenoext) + result.app(genMergeInfo(m)) + + app(m.s[cfsHeaders], genSectionStart(cfsHeaders)) generateHeaders(m) + app(m.s[cfsHeaders], genSectionEnd(cfsHeaders)) + generateThreadLocalStorage(m) - for i in countup(low(TCFileSection), cfsProcs): app(result, m.s[i]) + for i in countup(low(TCFileSection), cfsProcs): + app(result, genSectionStart(i)) + app(result, m.s[i]) + app(result, genSectionEnd(i)) + app(result, m.s[cfsInitProc]) proc rawNewModule(module: PSym, filename: string): BModule = new(result) diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim new file mode 100644 index 000000000..a25e7e3db --- /dev/null +++ b/compiler/cgendata.nim @@ -0,0 +1,116 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2011 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## This module contains the data structures for the C code generation phase. + +import + ast, astalgo, ropes, passes, options, intsets, lists, platform + +type + TLabel* = PRope # for the C generator a label is just a rope + TCFileSection* = enum # the sections a generated C file consists of + cfsMergeInfo, # section containing merge information + cfsHeaders, # section for C include file headers + cfsForwardTypes, # section for C forward typedefs + cfsTypes, # section for C typedefs + cfsSeqTypes, # section for sequence types only + # this is needed for strange type generation + # reasons + cfsFieldInfo, # section for field information + cfsTypeInfo, # section for type information + cfsProcHeaders, # section for C procs prototypes + cfsData, # section for C constant data + cfsVars, # section for C variable declarations + cfsProcs, # section for C procs that are not inline + cfsInitProc, # section for the C init proc + cfsTypeInit1, # section 1 for declarations of type information + cfsTypeInit2, # section 2 for init of type information + cfsTypeInit3, # section 3 for init of type information + cfsDebugInit, # section for init of debug information + cfsDynLibInit, # section for init of dynamic library binding + cfsDynLibDeinit # section for deinitialization of dynamic + # libraries + TCTypeKind* = enum # describes the type kind of a C type + ctVoid, ctChar, ctBool, ctUInt, ctUInt8, ctUInt16, ctUInt32, ctUInt64, + ctInt, ctInt8, ctInt16, ctInt32, ctInt64, ctFloat, ctFloat32, ctFloat64, + ctFloat128, ctArray, ctStruct, ctPtr, ctNimStr, ctNimSeq, ctProc, ctCString + TCFileSections = array[TCFileSection, PRope] # represents a generated C file + TCProcSection* = enum # the sections a generated C proc consists of + cpsLocals, # section of local variables for C proc + cpsInit, # section for init of variables for C proc + cpsStmts # section of local statements for C proc + TCProcSections = array[TCProcSection, PRope] # represents a generated C proc + BModule* = ref TCGen + BProc* = ref TCProc + TBlock{.final.} = object + id*: int # the ID of the label; positive means that it + # has been used (i.e. the label should be emitted) + nestedTryStmts*: int # how many try statements is it nested into + + TCProc{.final.} = object # represents C proc that is currently generated + s*: TCProcSections # the procs sections; short name for readability + prc*: PSym # the Nimrod proc that this C proc belongs to + BeforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed + ThreadVarAccessed*: bool # true if the proc already accessed some threadvar + nestedTryStmts*: seq[PNode] # in how many nested try statements we are + # (the vars must be volatile then) + labels*: Natural # for generating unique labels in the C proc + blocks*: seq[TBlock] # nested blocks + options*: TOptions # options that should be used for code + # generation; this is the same as prc.options + # unless prc == nil + frameLen*: int # current length of frame descriptor + sendClosure*: PType # closure record type that we pass + receiveClosure*: PType # closure record type that we get + module*: BModule # used to prevent excessive parameter passing + withinLoop*: int # > 0 if we are within a loop + + TTypeSeq* = seq[PType] + TCGen = object of TPassContext # represents a C source file + module*: PSym + filename*: string + s*: TCFileSections # sections of the C file + PreventStackTrace*: bool # true if stack traces need to be prevented + usesThreadVars*: bool # true if the module uses a thread var + cfilename*: string # filename of the module (including path, + # without extension) + typeCache*: TIdTable # cache the generated types + forwTypeCache*: TIdTable # cache for forward declarations of types + declaredThings*: TIntSet # things we have declared in this .c file + declaredProtos*: TIntSet # prototypes we have declared in this .c file + headerFiles*: TLinkedList # needed headers to include + typeInfoMarker*: TIntSet # needed for generating type information + initProc*: BProc # code for init procedure + typeStack*: TTypeSeq # used for type generation + dataCache*: TNodeTable + forwardedProcs*: TSymSeq # keep forwarded procs here + typeNodes*, nimTypes*: int # used for type info generation + typeNodesName*, nimTypesName*: PRope # used for type info generation + labels*: natural # for generating unique module-scope names + +var + mainModProcs*, mainModInit*: PRope # parts of the main module + gMapping*: PRope # the generated mapping file (if requested) + gProcProfile*: Natural # proc profile counter + gGeneratedSyms*: TIntSet # set of ID's of generated symbols + gPendingModules*: seq[BModule] = @[] # list of modules that are not + # finished with code generation + gForwardedProcsCounter*: int = 0 + gNimDat*: BModule # generated global data + + +proc newProc*(prc: PSym, module: BModule): BProc = + new(result) + result.prc = prc + result.module = module + if prc != nil: result.options = prc.options + else: result.options = gOptions + result.blocks = @[] + result.nestedTryStmts = @[] + diff --git a/compiler/idgen.nim b/compiler/idgen.nim index f5ae8a1f8..8bcfa37b7 100644 --- a/compiler/idgen.nim +++ b/compiler/idgen.nim @@ -9,7 +9,7 @@ ## This module contains a simple persistent id generator. -import idents, strutils, os +import idents, strutils, os, options var gFrontEndId, gBackendId*: int @@ -40,15 +40,18 @@ proc setId*(id: int) {.inline.} = proc IDsynchronizationPoint*(idRange: int) = gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1 +proc toGid(f: string): string = + result = options.completeGeneratedFilePath(f.addFileExt("gid")) + proc saveMaxIds*(project: string) = - var f = open(project.addFileExt("gid"), fmWrite) + var f = open(project.toGid, fmWrite) f.writeln($gFrontEndId) f.writeln($gBackEndId) f.close() proc loadMaxIds*(project: string) = var f: TFile - if open(f, project.addFileExt("gid"), fmRead): + if open(f, project.toGid, fmRead): var frontEndId = parseInt(f.readLine) var backEndId = parseInt(f.readLine) gFrontEndId = max(gFrontEndId, frontEndId) diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 5b6ffc57f..c6ef85a2b 100755 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -59,8 +59,8 @@ const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" # since negative numbers require a leading '-' they use up 1 byte. Thus we -# subtract/add vintDelta here to save space for little negative numbers -# which are common in ROD files: +# subtract/add `vintDelta` here to save space for small negative numbers +# which are common in ROD files: const vintDelta = 5 diff --git a/compiler/ropes.nim b/compiler/ropes.nim index 7e0d6c8e2..298d2d517 100755 --- a/compiler/ropes.nim +++ b/compiler/ropes.nim @@ -111,6 +111,12 @@ proc newRope(data: string = nil): PRope = result.length = len(data) result.data = data +proc newMutableRope*(capacity = 30): PRope = + ## creates a new rope that supports direct modifications of the rope's + ## 'data' and 'length' fields. + new(result) + result.data = newStringOfCap(capacity) + var cache: PRope # the root of the cache tree misses, hits: int |