summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim38
-rwxr-xr-xcompiler/ccgexprs.nim22
-rwxr-xr-xcompiler/ccgtypes.nim6
-rwxr-xr-xcompiler/cgen.nim2
-rwxr-xr-xcompiler/idents.nim100
-rw-r--r--compiler/idgen.nim57
-rwxr-xr-xcompiler/main.nim42
-rwxr-xr-xcompiler/msgs.nim2
-rwxr-xr-xcompiler/passaux.nim4
-rwxr-xr-xcompiler/passes.nim2
-rwxr-xr-xcompiler/rodread.nim235
-rwxr-xr-xcompiler/rodutils.nim98
-rwxr-xr-xcompiler/rodwrite.nim519
-rwxr-xr-xcompiler/sem.nim2
-rwxr-xr-xcompiler/semstmts.nim2
-rwxr-xr-xcompiler/treetab.nim2
-rwxr-xr-xlib/impure/db_sqlite.nim3
-rwxr-xr-xtodo.txt36
18 files changed, 613 insertions, 559 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index fd79c90e0..351ceeb36 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -10,7 +10,8 @@
 # abstract syntax tree + symbol table
 
 import 
-  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, intsets
+  msgs, hashes, nversion, options, strutils, crc, ropes, idents, lists, 
+  intsets, idgen
 
 const 
   ImportTablePos* = 0
@@ -377,7 +378,6 @@ type
 
 type 
   PNode* = ref TNode
-  PNodePtr* = ptr PNode
   TNodeSeq* = seq[PNode]
   PType* = ref TType
   PSym* = ref TSym
@@ -562,8 +562,8 @@ const
     tySet, tyTuple, tyRange, tyPtr, tyRef, tyVar, tySequence, tyProc,
     tyPointer, 
     tyOpenArray, tyString, tyCString, tyInt..tyInt64, tyFloat..tyFloat128,
-    tyUInt..tyUInt64} 
-  
+    tyUInt..tyUInt64}
+      
   ConstantDataTypes*: TTypeKinds = {tyArrayConstr, tyArray, tySet, 
                                     tyTuple, tySequence}
   ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, 
@@ -577,12 +577,6 @@ const
   resultPos* = 5
   dispatcherPos* = 6
 
-var gId*: int
-
-proc getID*(): int {.inline.}
-proc setID*(id: int) {.inline.}
-proc IDsynchronizationPoint*(idRange: int)
-
 # creator procs:
 proc NewSym*(symKind: TSymKind, Name: PIdent, owner: PSym): PSym
 proc NewType*(kind: TTypeKind, owner: PSym): PType
@@ -660,27 +654,6 @@ proc leValue*(a, b: PNode): bool
   # a <= b? a, b are literals
 proc ValueToString*(a: PNode): string
  
-const 
-  debugIds* = false
-
-when debugIds:
-  var usedIds: TIntSet
-
-proc registerID*(id: PIdObj) = 
-  when debugIDs: 
-    if (id.id == - 1) or ContainsOrIncl(usedIds, id.id): 
-      InternalError("ID already used: " & $(id.id))
-  
-proc getID(): int = 
-  result = gId
-  inc(gId)
-
-proc setId(id: int) = 
-  gId = max(gId, id + 1)
-
-proc IDsynchronizationPoint(idRange: int) = 
-  gId = (gId div IdRange + 1) * IdRange + 1
-
 proc leValue(a, b: PNode): bool = 
   # a <= b?
   result = false
@@ -1031,5 +1004,4 @@ proc getStrOrChar*(a: PNode): string =
   else: 
     internalError(a.info, "getStrOrChar")
     result = ""
-  
-when debugIDs: usedIds = InitIntSet()
+
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 826832438..a06a5db43 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -38,7 +38,7 @@ proc genHexLiteral(v: PNode): PRope =
 
 proc getStrLit(m: BModule, s: string): PRope =
   discard cgsym(m, "TGenericSeq")
-  result = con("TMP", toRope(getID()))
+  result = con("TMP", toRope(backendId()))
   appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
        [result, makeCString(s), ToRope(len(s))])
 
@@ -70,8 +70,8 @@ proc genLiteral(p: BProc, v: PNode, ty: PType): PRope =
     result = toRope("NIM_NIL")
   of nkStrLit..nkTripleStrLit:
     if skipTypes(ty, abstractVarRange).kind == tyString:
-      var id = NodeTableTestOrSet(p.module.dataCache, v, gid)
-      if id == gid:
+      var id = NodeTableTestOrSet(p.module.dataCache, v, gBackendId)
+      if id == gBackendId:
         # string literal not found in the cache:
         result = ropecg(p.module, "((#NimStringDesc*) &$1)", 
                         [getStrLit(p.module, v.strVal)])
@@ -123,11 +123,11 @@ proc genSetNode(p: BProc, n: PNode): PRope =
   var size = int(getSize(n.typ))
   toBitSet(n, cs)
   if size > 8:
-    var id = NodeTableTestOrSet(p.module.dataCache, n, gid)
+    var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
     result = con("TMP", toRope(id))
-    if id == gid:
+    if id == gBackendId:
       # not found in cache:
-      inc(gid)
+      inc(gBackendId)
       appf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
   else:
@@ -618,8 +618,8 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
       v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
       genInExprAux(p, it, u, v, test)
       id = NodeTableTestOrSet(p.module.dataCache,
-                              newStrNode(nkStrLit, field.name.s), gid)
-      if id == gid: strLit = getStrLit(p.module, field.name.s)
+                              newStrNode(nkStrLit, field.name.s), gBackendId)
+      if id == gBackendId: strLit = getStrLit(p.module, field.name.s)
       else: strLit = con("TMP", toRope(id))
       if op.magic == mNot:
         appcg(p, cpsStmts,
@@ -1581,11 +1581,11 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
   if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
     var t = getUniqueType(n.typ)
     discard getTypeDesc(p.module, t) # so that any fields are initialized
-    var id = NodeTableTestOrSet(p.module.dataCache, n, gid)
+    var id = NodeTableTestOrSet(p.module.dataCache, n, gBackendId)
     fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap)
-    if id == gid:
+    if id == gBackendId:
       # expression not found in the cache:
-      inc(gid)
+      inc(gBackendId)
       appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
            [getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
     result = true
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index b1465c215..37df89cfd 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -145,12 +145,10 @@ proc CacheGetType(tab: TIdTable, key: PType): PRope =
   result = PRope(IdTableGet(tab, key))
 
 proc getTempName(): PRope = 
-  result = ropeff("TMP$1", "%TMP$1", [toRope(gId)])
-  inc(gId)
+  result = ropeff("TMP$1", "%TMP$1", [toRope(backendId())])
 
 proc getGlobalTempName(): PRope = 
-  result = ropeff("TMP$1", "@TMP$1", [toRope(gId)])
-  inc(gId)
+  result = ropeff("TMP$1", "@TMP$1", [toRope(backendId())])
 
 proc ccgIntroducedPtr(s: PSym): bool = 
   var pt = skipTypes(s.typ, abstractInst)
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 70b3069cf..d4a9dd278 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
+  rodutils, renderer, idgen
 
 when options.hasTinyCBackend:
   import tccgen
diff --git a/compiler/idents.nim b/compiler/idents.nim
index 422112e4f..efed7ae62 100755
--- a/compiler/idents.nim
+++ b/compiler/idents.nim
@@ -1,14 +1,14 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
 # Identifier handling
-# An identifier is a shared non-modifiable string that can be compared by its
+# An identifier is a shared immutable string that can be compared by its
 # id. This module is essential for the compiler's performance.
 
 import 
@@ -25,76 +25,48 @@ type
     next*: PIdent             # for hash-table chaining
     h*: THash                 # hash value of s
   
-
-proc getIdent*(identifier: string): PIdent
-proc getIdent*(identifier: string, h: THash): PIdent
-proc getIdent*(identifier: cstring, length: int, h: THash): PIdent
-  # special version for the scanner; the scanner's buffering scheme makes
-  # this horribly efficient. Most of the time no character copying is needed!
-proc IdentEq*(id: PIdent, name: string): bool
-# implementation
-
-proc IdentEq(id: PIdent, name: string): bool = 
-  result = id.id == getIdent(name).id
-
 var buckets: array[0..4096 * 2 - 1, PIdent]
 
-proc cmpIgnoreStyle(a, b: cstring, blen: int): int = 
-  var 
-    aa, bb: char
-    i, j: int
-  i = 0
-  j = 0
+proc cmpIgnoreStyle(a, b: cstring, blen: int): int =
+  var i = 0
+  var j = 0
   result = 1
-  while j < blen: 
+  while j < blen:
     while a[i] == '_': inc(i)
     while b[j] == '_': inc(j)
     # tolower inlined:
-    aa = a[i]
-    bb = b[j]
-    if (aa >= 'A') and (aa <= 'Z'): aa = chr(ord(aa) + (ord('a') - ord('A')))
-    if (bb >= 'A') and (bb <= 'Z'): bb = chr(ord(bb) + (ord('a') - ord('A')))
+    var aa = a[i]
+    var bb = b[j]
+    if aa >= 'A' and aa <= 'Z': aa = chr(ord(aa) + (ord('a') - ord('A')))
+    if bb >= 'A' and bb <= 'Z': bb = chr(ord(bb) + (ord('a') - ord('A')))
     result = ord(aa) - ord(bb)
     if (result != 0) or (aa == '\0'): break 
     inc(i)
     inc(j)
-  if result == 0: 
+  if result == 0:
     if a[i] != '\0': result = 1
   
-proc cmpExact(a, b: cstring, blen: int): int = 
-  var 
-    aa, bb: char
-    i, j: int
-  i = 0
-  j = 0
+proc cmpExact(a, b: cstring, blen: int): int =
+  var i = 0
+  var j = 0
   result = 1
-  while j < blen: 
-    aa = a[i]
-    bb = b[j]
+  while j < blen:
+    var aa = a[i]
+    var bb = b[j]
     result = ord(aa) - ord(bb)
     if (result != 0) or (aa == '\0'): break 
     inc(i)
     inc(j)
   if result == 0: 
     if a[i] != '\0': result = 1
-  
-proc getIdent(identifier: string): PIdent = 
-  result = getIdent(cstring(identifier), len(identifier), 
-                    hashIgnoreStyle(identifier))
 
-proc getIdent(identifier: string, h: THash): PIdent = 
-  result = getIdent(cstring(identifier), len(identifier), h)
+var wordCounter = 1
 
-var wordCounter: int = 1
-
-proc getIdent(identifier: cstring, length: int, h: THash): PIdent = 
-  var 
-    idx, id: int
-    last: PIdent
-  idx = h and high(buckets)
+proc getIdent*(identifier: cstring, length: int, h: THash): PIdent =
+  var idx = h and high(buckets)
   result = buckets[idx]
-  last = nil
-  id = 0
+  var last: PIdent = nil
+  var id = 0
   while result != nil: 
     if cmpExact(cstring(result.s), identifier, length) == 0: 
       if last != nil: 
@@ -103,17 +75,7 @@ proc getIdent(identifier: cstring, length: int, h: THash): PIdent =
         result.next = buckets[idx]
         buckets[idx] = result
       return 
-    elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0: 
-      #if (id <> 0) and (id <> result.id) then begin
-      #        result := buckets[idx];
-      #        writeln('current id ', id);
-      #        for i := 0 to len-1 do write(identifier[i]);
-      #        writeln;
-      #        while result <> nil do begin
-      #          writeln(result.s, '  ', result.id);
-      #          result := result.next
-      #        end
-      #      end;
+    elif cmpIgnoreStyle(cstring(result.s), identifier, length) == 0:
       assert((id == 0) or (id == result.id))
       id = result.id
     last = result
@@ -121,12 +83,22 @@ proc getIdent(identifier: cstring, length: int, h: THash): PIdent =
   new(result)
   result.h = h
   result.s = newString(length)
-  for i in countup(0, length + 0 - 1): result.s[i] = identifier[i - 0]
+  for i in countup(0, length - 1): result.s[i] = identifier[i]
   result.next = buckets[idx]
   buckets[idx] = result
   if id == 0: 
     inc(wordCounter)
-    result.id = - wordCounter
+    result.id = -wordCounter
   else: 
-    result.id = id            #  writeln('new word ', result.s);
+    result.id = id
+
+proc getIdent*(identifier: string): PIdent = 
+  result = getIdent(cstring(identifier), len(identifier), 
+                    hashIgnoreStyle(identifier))
+
+proc getIdent*(identifier: string, h: THash): PIdent = 
+  result = getIdent(cstring(identifier), len(identifier), h)
+
+proc IdentEq*(id: PIdent, name: string): bool = 
+  result = id.id == getIdent(name).id
   
diff --git a/compiler/idgen.nim b/compiler/idgen.nim
new file mode 100644
index 000000000..f5ae8a1f8
--- /dev/null
+++ b/compiler/idgen.nim
@@ -0,0 +1,57 @@
+#
+#
+#           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 a simple persistent id generator.
+
+import idents, strutils, os
+
+var gFrontEndId, gBackendId*: int
+
+const
+  debugIds* = false
+
+when debugIds:
+  import intsets
+  
+  var usedIds = InitIntSet()
+
+proc registerID*(id: PIdObj) = 
+  when debugIDs: 
+    if (id.id == - 1) or ContainsOrIncl(usedIds, id.id): 
+      InternalError("ID already used: " & $id.id)
+  
+proc getID*(): int {.inline.} = 
+  result = gFrontEndId
+  inc(gFrontEndId)
+
+proc backendId*(): int {.inline.} = 
+  result = gBackendId
+  inc(gBackendId)
+
+proc setId*(id: int) {.inline.} = 
+  gFrontEndId = max(gFrontEndId, id + 1)
+
+proc IDsynchronizationPoint*(idRange: int) = 
+  gFrontEndId = (gFrontEndId div IdRange + 1) * IdRange + 1
+
+proc saveMaxIds*(project: string) =
+  var f = open(project.addFileExt("gid"), fmWrite)
+  f.writeln($gFrontEndId)
+  f.writeln($gBackEndId)
+  f.close()
+  
+proc loadMaxIds*(project: string) =
+  var f: TFile
+  if open(f, project.addFileExt("gid"), fmRead):
+    var frontEndId = parseInt(f.readLine)
+    var backEndId = parseInt(f.readLine)
+    gFrontEndId = max(gFrontEndId, frontEndId)
+    gBackEndId = max(gBackEndId, backEndId)
+    f.close()
+
diff --git a/compiler/main.nim b/compiler/main.nim
index 017d188b5..f09ceb997 100755
--- a/compiler/main.nim
+++ b/compiler/main.nim
@@ -15,7 +15,7 @@ import
   os, lists, condsyms, rodread, rodwrite, ropes, trees, 
   wordrecg, sem, semdata, idents, passes, docgen, extccomp,
   cgen, ecmasgen,
-  platform, nimconf, importer, passaux, depends, transf, evals, types
+  platform, nimconf, importer, passaux, depends, transf, evals, types, idgen
 
 const
   has_LLVM_Backend = false
@@ -24,24 +24,17 @@ when has_LLVM_Backend:
   import llvmgen
 
 proc MainCommand*(cmd, filename: string)
-# implementation
+
 # ------------------ module handling -----------------------------------------
 
 type 
-  TFileModuleRec{.final.} = object 
-    filename*: string
-    module*: PSym
-
+  TFileModuleRec = tuple[filename: string, module: PSym]
   TFileModuleMap = seq[TFileModuleRec]
 
-var compMods: TFileModuleMap = @[]
+var compMods: TFileModuleMap = @[] # all compiled modules
 
 proc registerModule(filename: string, module: PSym) = 
-  # all compiled modules
-  var length = len(compMods)
-  setlen(compMods, length + 1)
-  compMods[length].filename = filename
-  compMods[length].module = module
+  compMods.add((filename, module))
 
 proc getModule(filename: string): PSym = 
   for i in countup(0, high(compMods)): 
@@ -65,23 +58,22 @@ proc newModule(filename: string): PSym =
   RegisterModule(filename, result)
   StrTableAdd(result.tab, result) # a module knows itself
   
-proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym
+proc CompileModule(filename: string, flags: TSymFlags): PSym
 proc importModule(filename: string): PSym = 
   # this is called by the semantic checking phase
   result = getModule(filename)
   if result == nil: 
     # compile the module
-    result = compileModule(filename, false, false)
+    result = compileModule(filename, {})
   elif sfSystemModule in result.flags: 
     LocalError(result.info, errAttemptToRedefine, result.Name.s)
   
-proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym = 
+proc CompileModule(filename: string, flags: TSymFlags): PSym = 
   var rd: PRodReader = nil
   var f = addFileExt(filename, nimExt)
   result = newModule(filename)
-  if isMainFile: incl(result.flags, sfMainModule)
-  if isSystemFile: incl(result.flags, sfSystemModule)
-  if (gCmd == cmdCompileToC) or (gCmd == cmdCompileToCpp): 
+  result.flags = result.flags + flags
+  if gCmd in {cmdCompileToC, cmdCompileToCpp}: 
     rd = handleSymbolFile(result, f)
     if result.id < 0: 
       InternalError("handleSymbolFile should have set the module\'s ID")
@@ -90,9 +82,9 @@ proc CompileModule(filename: string, isMainFile, isSystemFile: bool): PSym =
   processModule(result, f, nil, rd)
 
 proc CompileProject(filename: string) = 
-  discard CompileModule(JoinPath(options.libpath, addFileExt("system", nimExt)), 
-                        false, true)
-  discard CompileModule(addFileExt(filename, nimExt), true, false)
+  discard CompileModule(options.libpath / addFileExt("system", nimExt),
+                        {sfSystemModule})
+  discard CompileModule(addFileExt(filename, nimExt), {sfMainModule})
 
 proc semanticPasses() = 
   registerPass(verbosePass())
@@ -147,8 +139,8 @@ proc CommandInteractive() =
   registerPass(verbosePass())
   registerPass(sem.semPass())
   registerPass(evals.evalPass()) # load system module:
-  discard CompileModule(JoinPath(options.libpath, addFileExt("system", nimExt)), 
-                        false, true)
+  discard CompileModule(options.libpath / addFileExt("system", nimExt),
+                        {sfSystemModule})
   var m = newModule("stdin")
   m.id = getID()
   incl(m.flags, sfMainModule)
@@ -230,9 +222,9 @@ proc MainCommand(cmd, filename: string) =
       CommandCompileToLLVM(filename)
     else:
       rawMessage(errInvalidCommandX, cmd)
-  of "pretty": 
+  of "pretty":
     gCmd = cmdPretty
-    wantFile(filename)        #CommandExportSymbols(filename);
+    wantFile(filename)
     CommandPretty(filename)
   of "doc": 
     gCmd = cmdDoc
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 4f8a21f54..7fe6f649d 100755
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -76,6 +76,7 @@ type
     errNamedExprNotAllowed, errXExpectsOneTypeParam, 
     errArrayExpectsTwoTypeParams, errInvalidVisibilityX, errInitHereNotAllowed, 
     errXCannotBeAssignedTo, errIteratorNotAllowed, errXNeedsReturnType, 
+    errNoReturnTypeDeclared,
     errInvalidCommandX, errXOnlyAtModuleScope, 
     errXNeedsParamObjectType,
     errTemplateInstantiationTooNested, errInstantiationFrom, 
@@ -284,6 +285,7 @@ const
     errXCannotBeAssignedTo: "\'$1\' cannot be assigned to", 
     errIteratorNotAllowed: "iterators can only be defined at the module\'s top level", 
     errXNeedsReturnType: "$1 needs a return type",
+    errNoReturnTypeDeclared: "no return type declared",
     errInvalidCommandX: "invalid command: \'$1\'", 
     errXOnlyAtModuleScope: "\'$1\' is only allowed at top level", 
     errXNeedsParamObjectType: "'$1' needs a parameter that has an object type",
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index a57963c06..659a9a346 100755
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -10,7 +10,7 @@
 ## implements some little helper passes
 
 import 
-  strutils, ast, astalgo, passes, msgs, options
+  strutils, ast, astalgo, passes, msgs, options, idgen
 
 proc verboseOpen(s: PSym, filename: string): PPassContext = 
   #MessageOut('compiling ' + s.name.s);
@@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
     # system.nim deactivates all hints, for verbosity:3 we want the processing
     # messages nonetheless, so we activate them again unconditionally:
     incl(msgs.gNotes, hintProcessing)
-    Message(n.info, hintProcessing, $ast.gid)
+    Message(n.info, hintProcessing, $idgen.gBackendId)
   
 proc verbosePass*(): TPass = 
   initPass(result)
diff --git a/compiler/passes.nim b/compiler/passes.nim
index 5b60d2805..d5aeb50d1 100755
--- a/compiler/passes.nim
+++ b/compiler/passes.nim
@@ -13,7 +13,7 @@
 import 
   strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, 
   condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, 
-  nimsets, syntaxes, times, rodread, semthreads
+  nimsets, syntaxes, times, rodread, semthreads, idgen
 
 type
   TPassContext* = object of TObject # the pass's context
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 4de77ff42..1a59916a4 100755
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -73,7 +73,7 @@
 
 import 
   os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, 
-  ropes, idents, crc
+  ropes, idents, crc, idgen, rodutils
 
 type 
   TReasonForRecompile* = enum 
@@ -100,12 +100,12 @@ type
   TIndex*{.final.} = object   # an index with compression
     lastIdxKey*, lastIdxVal*: int
     tab*: TIITable
-    r*: PRope                 # writers use this
+    r*: string                # writers use this
     offset*: int              # readers use this
   
   TRodReader* = object of TObject
     pos*: int                 # position; used for parsing
-    s*: string                # the whole file in memory
+    s*: string                # the whole file in memory; XXX mmap this!
     options*: TOptions
     reason*: TReasonForRecompile
     modDeps*: TStringSeq
@@ -116,7 +116,7 @@ type
     filename*: string
     index*, imports*: TIndex
     readerIndex*: int
-    line*: int                # only used for debugging, but is always in the code
+    line*: int            # only used for debugging, but is always in the code
     moduleID*: int
     syms*: TIdTable           # already processed symbols
   
@@ -132,8 +132,7 @@ proc handleSymbolFile*(module: PSym, filename: string): PRodReader
 proc GetCRC*(filename: string): TCrc32
 proc loadInitSection*(r: PRodReader): PNode
 proc loadStub*(s: PSym)
-proc encodeInt*(x: BiggestInt): PRope
-proc encode*(s: string): PRope
+
 # implementation
 
 var gTypeTable: TIdTable
@@ -141,52 +140,19 @@ var gTypeTable: TIdTable
 proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym
   # `info` is only used for debugging purposes
 proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType
-proc decode(r: PRodReader): string
-proc decodeInt(r: PRodReader): int
-proc decodeBInt(r: PRodReader): biggestInt
-
-proc encode(s: string): PRope = 
-  var res = ""
-  for i in countup(0, len(s) - 1): 
-    case s[i]
-    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(res, s[i])
-    else: add(res, '\\' & toHex(ord(s[i]), 2))
-  result = toRope(res)
-
-proc encodeIntAux(str: var string, x: BiggestInt) = 
-  const chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
-  var d: char
-  var v = x
-  var rem: biggestInt = v mod 190
-  if (rem < 0): 
-    add(str, '-')
-    v = - (v div 190)
-    rem = - rem
-  else: 
-    v = v div 190
-  var idx = int(rem)
-  if idx < 62: d = chars[idx + 0]
-  else: d = chr(idx - 62 + 128)
-  if (v != 0): encodeIntAux(str, v)
-  add(str, d)
-
-proc encodeInt(x: BiggestInt): PRope = 
-  var res = ""
-  encodeIntAux(res, x)
-  result = toRope(res)
 
 proc decodeLineInfo(r: PRodReader, info: var TLineInfo) = 
   if r.s[r.pos] == '?': 
     inc(r.pos)
     if r.s[r.pos] == ',': info.col = int16(- 1)
-    else: info.col = int16(decodeInt(r))
+    else: info.col = int16(decodeVInt(r.s, r.pos))
     if r.s[r.pos] == ',': 
       inc(r.pos)
       if r.s[r.pos] == ',': info.line = int16(- 1)
-      else: info.line = int16(decodeInt(r))
+      else: info.line = int16(decodeVInt(r.s, r.pos))
       if r.s[r.pos] == ',': 
         inc(r.pos)
-        info = newLineInfo(r.files[decodeInt(r)], info.line, info.col)
+        info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col)
 
 proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = 
   result = nil
@@ -195,42 +161,42 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
     if r.s[r.pos] == ')': 
       inc(r.pos)
       return                  # nil node
-    result = newNodeI(TNodeKind(decodeInt(r)), fInfo)
+    result = newNodeI(TNodeKind(decodeVInt(r.s, r.pos)), fInfo)
     decodeLineInfo(r, result.info)
     if r.s[r.pos] == '$': 
       inc(r.pos)
-      result.flags = cast[TNodeFlags](int32(decodeInt(r)))
+      result.flags = cast[TNodeFlags](int32(decodeVInt(r.s, r.pos)))
     if r.s[r.pos] == '^': 
       inc(r.pos)
-      var id = decodeInt(r)
+      var id = decodeVInt(r.s, r.pos)
       result.typ = rrGetType(r, id, result.info)
     case result.kind
     of nkCharLit..nkInt64Lit: 
       if r.s[r.pos] == '!': 
         inc(r.pos)
-        result.intVal = decodeBInt(r)
+        result.intVal = decodeVBiggestInt(r.s, r.pos)
     of nkFloatLit..nkFloat64Lit: 
       if r.s[r.pos] == '!': 
         inc(r.pos)
-        var fl = decode(r)
+        var fl = decodeStr(r.s, r.pos)
         result.floatVal = parseFloat(fl)
     of nkStrLit..nkTripleStrLit: 
       if r.s[r.pos] == '!': 
         inc(r.pos)
-        result.strVal = decode(r)
+        result.strVal = decodeStr(r.s, r.pos)
       else: 
         result.strVal = ""    # BUGFIX
     of nkIdent: 
       if r.s[r.pos] == '!': 
         inc(r.pos)
-        var fl = decode(r)
+        var fl = decodeStr(r.s, r.pos)
         result.ident = getIdent(fl)
       else: 
         internalError(result.info, "decodeNode: nkIdent")
     of nkSym: 
       if r.s[r.pos] == '!': 
         inc(r.pos)
-        var id = decodeInt(r)
+        var id = decodeVInt(r.s, r.pos)
         result.sym = rrGetSym(r, id, result.info)
       else: 
         internalError(result.info, "decodeNode: nkSym")
@@ -245,32 +211,32 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
   if r.s[r.pos] == '<': 
     inc(r.pos)
     if r.s[r.pos] in {'0'..'9', 'a'..'z', 'A'..'Z'}: 
-      loc.k = TLocKind(decodeInt(r))
+      loc.k = TLocKind(decodeVInt(r.s, r.pos))
     else: 
       loc.k = low(loc.k)
     if r.s[r.pos] == '*': 
       inc(r.pos)
-      loc.s = TStorageLoc(decodeInt(r))
+      loc.s = TStorageLoc(decodeVInt(r.s, r.pos))
     else: 
       loc.s = low(loc.s)
     if r.s[r.pos] == '$': 
       inc(r.pos)
-      loc.flags = cast[TLocFlags](int32(decodeInt(r)))
+      loc.flags = cast[TLocFlags](int32(decodeVInt(r.s, r.pos)))
     else: 
       loc.flags = {}
     if r.s[r.pos] == '^': 
       inc(r.pos)
-      loc.t = rrGetType(r, decodeInt(r), info)
+      loc.t = rrGetType(r, decodeVInt(r.s, r.pos), info)
     else: 
       loc.t = nil
     if r.s[r.pos] == '!': 
       inc(r.pos)
-      loc.r = toRope(decode(r))
+      loc.r = toRope(decodeStr(r.s, r.pos))
     else: 
       loc.r = nil
     if r.s[r.pos] == '?': 
       inc(r.pos)
-      loc.a = decodeInt(r)
+      loc.a = decodeVInt(r.s, r.pos)
     else: 
       loc.a = 0
     if r.s[r.pos] == '>': inc(r.pos)
@@ -284,10 +250,10 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
       inc(r.pos)
       return                  # nil type
   new(result)
-  result.kind = TTypeKind(decodeInt(r))
+  result.kind = TTypeKind(decodeVInt(r.s, r.pos))
   if r.s[r.pos] == '+': 
     inc(r.pos)
-    result.id = decodeInt(r)
+    result.id = decodeVInt(r.s, r.pos)
     setId(result.id)
     if debugIds: registerID(result)
   else: 
@@ -297,29 +263,29 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
   if r.s[r.pos] == '(': result.n = decodeNode(r, UnknownLineInfo())
   if r.s[r.pos] == '$': 
     inc(r.pos)
-    result.flags = cast[TTypeFlags](int32(decodeInt(r)))
+    result.flags = cast[TTypeFlags](int32(decodeVInt(r.s, r.pos)))
   if r.s[r.pos] == '?': 
     inc(r.pos)
-    result.callConv = TCallingConvention(decodeInt(r))
+    result.callConv = TCallingConvention(decodeVInt(r.s, r.pos))
   if r.s[r.pos] == '*': 
     inc(r.pos)
-    result.owner = rrGetSym(r, decodeInt(r), info)
+    result.owner = rrGetSym(r, decodeVInt(r.s, r.pos), info)
   if r.s[r.pos] == '&': 
     inc(r.pos)
-    result.sym = rrGetSym(r, decodeInt(r), info)
+    result.sym = rrGetSym(r, decodeVInt(r.s, r.pos), info)
   if r.s[r.pos] == '/': 
     inc(r.pos)
-    result.size = decodeInt(r)
+    result.size = decodeVInt(r.s, r.pos)
   else: 
     result.size = - 1
   if r.s[r.pos] == '=': 
     inc(r.pos)
-    result.align = decodeInt(r)
+    result.align = decodeVInt(r.s, r.pos)
   else: 
     result.align = 2
   if r.s[r.pos] == '@': 
     inc(r.pos)
-    result.containerID = decodeInt(r)
+    result.containerID = decodeVInt(r.s, r.pos)
   decodeLoc(r, result.loc, info)
   while r.s[r.pos] == '^': 
     inc(r.pos)
@@ -329,7 +295,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
       else: InternalError(info, "decodeType ^(" & r.s[r.pos])
       addSon(result, nil)
     else: 
-      var d = decodeInt(r)
+      var d = decodeVInt(r.s, r.pos)
       addSon(result, rrGetType(r, d, info))
 
 proc decodeLib(r: PRodReader, info: TLineInfo): PLib = 
@@ -337,10 +303,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
   if r.s[r.pos] == '|': 
     new(result)
     inc(r.pos)
-    result.kind = TLibKind(decodeInt(r))
+    result.kind = TLibKind(decodeVInt(r.s, r.pos))
     if r.s[r.pos] != '|': InternalError("decodeLib: 1")
     inc(r.pos)
-    result.name = toRope(decode(r))
+    result.name = toRope(decodeStr(r.s, r.pos))
     if r.s[r.pos] != '|': InternalError("decodeLib: 2")
     inc(r.pos)
     result.path = decodeNode(r, info)
@@ -355,16 +321,16 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
     if r.s[r.pos] == '}': 
       inc(r.pos)
       return                  # nil sym
-  var k = TSymKind(decodeInt(r))
+  var k = TSymKind(decodeVInt(r.s, r.pos))
   if r.s[r.pos] == '+': 
     inc(r.pos)
-    id = decodeInt(r)
+    id = decodeVInt(r.s, r.pos)
     setId(id)
   else: 
     InternalError(info, "decodeSym: no id")
   if r.s[r.pos] == '&': 
     inc(r.pos)
-    ident = getIdent(decode(r))
+    ident = getIdent(decodeStr(r.s, r.pos))
   else: 
     InternalError(info, "decodeSym: no ident")
   result = PSym(IdTableGet(r.syms, id))
@@ -379,100 +345,37 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
   result.name = ident         # read the rest of the symbol description:
   if r.s[r.pos] == '^': 
     inc(r.pos)
-    result.typ = rrGetType(r, decodeInt(r), info)
+    result.typ = rrGetType(r, decodeVInt(r.s, r.pos), info)
   decodeLineInfo(r, result.info)
   if r.s[r.pos] == '*': 
     inc(r.pos)
-    result.owner = rrGetSym(r, decodeInt(r), result.info)
+    result.owner = rrGetSym(r, decodeVInt(r.s, r.pos), result.info)
   if r.s[r.pos] == '$': 
     inc(r.pos)
-    result.flags = cast[TSymFlags](int32(decodeInt(r)))
+    result.flags = cast[TSymFlags](int32(decodeVInt(r.s, r.pos)))
   if r.s[r.pos] == '@': 
     inc(r.pos)
-    result.magic = TMagic(decodeInt(r))
+    result.magic = TMagic(decodeVInt(r.s, r.pos))
   if r.s[r.pos] == '(': result.ast = decodeNode(r, result.info)
   if r.s[r.pos] == '!': 
     inc(r.pos)
-    result.options = cast[TOptions](int32(decodeInt(r)))
+    result.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
   else: 
     result.options = r.options
   if r.s[r.pos] == '%': 
     inc(r.pos)
-    result.position = decodeInt(r)
+    result.position = decodeVInt(r.s, r.pos)
   else: 
     result.position = 0       
     # BUGFIX: this may have been misused as reader index!
   if r.s[r.pos] == '`': 
     inc(r.pos)
-    result.offset = decodeInt(r)
+    result.offset = decodeVInt(r.s, r.pos)
   else: 
     result.offset = - 1
   decodeLoc(r, result.loc, result.info)
   result.annex = decodeLib(r, info)
 
-proc decodeInt(r: PRodReader): int = 
-  # base 190 numbers
-  var i = r.pos
-  var sign = - 1
-  assert(r.s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
-  if r.s[i] == '-': 
-    inc(i)
-    sign = 1
-  result = 0
-  while true: 
-    case r.s[i]
-    of '0'..'9': result = result * 190 - (ord(r.s[i]) - ord('0'))
-    of 'a'..'z': result = result * 190 - (ord(r.s[i]) - ord('a') + 10)
-    of 'A'..'Z': result = result * 190 - (ord(r.s[i]) - ord('A') + 36)
-    of '\x80'..'\xFF': result = result * 190 - (ord(r.s[i]) - 128 + 62)
-    else: break 
-    inc(i)
-  result = result * sign
-  r.pos = i
-
-proc decodeBInt(r: PRodReader): biggestInt = 
-  var i = r.pos
-  var sign: biggestInt = - 1
-  assert(r.s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
-  if r.s[i] == '-': 
-    inc(i)
-    sign = 1
-  result = 0
-  while true: 
-    case r.s[i]
-    of '0'..'9': result = result * 190 - (ord(r.s[i]) - ord('0'))
-    of 'a'..'z': result = result * 190 - (ord(r.s[i]) - ord('a') + 10)
-    of 'A'..'Z': result = result * 190 - (ord(r.s[i]) - ord('A') + 36)
-    of '\x80'..'\xFF': result = result * 190 - (ord(r.s[i]) - 128 + 62)
-    else: break 
-    inc(i)
-  result = result * sign
-  r.pos = i
-
-proc hexChar(c: char, xi: var int) = 
-  case c
-  of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
-  of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
-  of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
-  else: nil
-
-proc decode(r: PRodReader): string = 
-  var i = r.pos
-  result = ""
-  while true: 
-    case r.s[i]
-    of '\\': 
-      inc(i, 3)
-      var xi = 0
-      hexChar(r.s[i-2], xi)
-      hexChar(r.s[i-1], xi)
-      add(result, chr(xi))
-    of 'a'..'z', 'A'..'Z', '0'..'9', '_': 
-      add(result, r.s[i])
-      inc(i)
-    else: break 
-  r.pos = i
-
 proc skipSection(r: PRodReader) = 
   if r.s[r.pos] == ':': 
     while r.s[r.pos] > '\x0A': inc(r.pos)
@@ -514,9 +417,9 @@ proc processInterf(r: PRodReader, module: PSym) =
   if r.interfIdx == 0: InternalError("processInterf")
   r.pos = r.interfIdx
   while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): 
-    var w = decode(r)
+    var w = decodeStr(r.s, r.pos)
     inc(r.pos)
-    var key = decodeInt(r)
+    var key = decodeVInt(r.s, r.pos)
     inc(r.pos)                # #10
     var s = newStub(r, w, key)
     s.owner = module
@@ -527,9 +430,9 @@ proc processCompilerProcs(r: PRodReader, module: PSym) =
   if r.compilerProcsIdx == 0: InternalError("processCompilerProcs")
   r.pos = r.compilerProcsIdx
   while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): 
-    var w = decode(r)
+    var w = decodeStr(r.s, r.pos)
     inc(r.pos)
-    var key = decodeInt(r)
+    var key = decodeVInt(r.s, r.pos)
     inc(r.pos)                # #10
     var s = PSym(IdTableGet(r.syms, key))
     if s == nil: 
@@ -543,11 +446,11 @@ proc processIndex(r: PRodReader, idx: var TIndex) =
   inc(r.pos, 2)               # skip "(\10"
   inc(r.line)
   while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): 
-    tmp = decodeInt(r)
+    tmp = decodeVInt(r.s, r.pos)
     if r.s[r.pos] == ' ': 
       inc(r.pos)
       key = idx.lastIdxKey + tmp
-      val = decodeInt(r) + idx.lastIdxVal
+      val = decodeVInt(r.s, r.pos) + idx.lastIdxVal
     else: 
       key = idx.lastIdxKey + 1
       val = tmp + idx.lastIdxVal
@@ -571,20 +474,20 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
     case section 
     of "CRC": 
       inc(r.pos)              # skip ':'
-      if int(crc) != decodeInt(r): r.reason = rrCrcChange
+      if int(crc) != decodeVInt(r.s, r.pos): r.reason = rrCrcChange
     of "ID": 
       inc(r.pos)              # skip ':'
-      r.moduleID = decodeInt(r)
+      r.moduleID = decodeVInt(r.s, r.pos)
       setID(r.moduleID)
     of "OPTIONS": 
       inc(r.pos)              # skip ':'
-      r.options = cast[TOptions](int32(decodeInt(r)))
+      r.options = cast[TOptions](int32(decodeVInt(r.s, r.pos)))
       if options.gOptions != r.options: r.reason = rrOptions
     of "DEFINES": 
       inc(r.pos)              # skip ':'
       d = 0
       while r.s[r.pos] > '\x0A': 
-        w = decode(r)
+        w = decodeStr(r.s, r.pos)
         inc(d)
         if not condsyms.isDefined(getIdent(w)): 
           r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
@@ -596,7 +499,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
       L = 0
       while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
         setlen(r.files, L + 1)
-        r.files[L] = decode(r)
+        r.files[L] = decodeStr(r.s, r.pos)
         inc(r.pos)            # skip #10
         inc(r.line)
         inc(L)
@@ -605,9 +508,9 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
       inc(r.pos, 2)           # skip "(\10"
       inc(r.line)
       while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
-        w = r.files[decodeInt(r)]
+        w = r.files[decodeVInt(r.s, r.pos)]
         inc(r.pos)            # skip ' '
-        inclCrc = decodeInt(r)
+        inclCrc = decodeVInt(r.s, r.pos)
         if r.reason == rrNone: 
           if not ExistsFile(w) or (inclCrc != int(crcFromFile(w))): 
             r.reason = rrInclDeps
@@ -620,7 +523,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
       L = 0
       while r.s[r.pos] > '\x0A': 
         setlen(r.modDeps, L + 1)
-        r.modDeps[L] = r.files[decodeInt(r)]
+        r.modDeps[L] = r.files[decodeVInt(r.s, r.pos)]
         inc(L)
         if r.s[r.pos] == ' ': inc(r.pos)
     of "INTERF": 
@@ -723,8 +626,9 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
     if d == invalidKey: 
       var moduleID = IiTableGet(r.imports.tab, id)
       if moduleID < 0: 
-        InternalError(info, 
-                      "missing from both indexes: +" & ropeToStr(encodeInt(id))) 
+        var x = ""
+        encodeVInt(id, x)
+        InternalError(info, "missing from both indexes: +" & x) 
       # find the reader with the correct moduleID:
       for i in countup(0, high(gMods)): 
         var rd = gMods[i].rd
@@ -734,10 +638,11 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
             if d != invalidKey: 
               result = decodeSymSafePos(rd, d, info)
               break 
-            else: 
-              InternalError(info, "rrGetSym: no reader found: +" &
-                  ropeToStr(encodeInt(id)))
-          else: 
+            else:
+              var x = ""
+              encodeVInt(id, x)
+              InternalError(info, "rrGetSym: no reader found: +" & x)
+          else:
             #if IiTableGet(rd.index.tab, id) <> invalidKey then
             # XXX expensive check!
             #InternalError(info,
@@ -753,7 +658,7 @@ proc loadInitSection(r: PRodReader): PNode =
   r.pos = r.initIdx
   result = newNode(nkStmtList)
   while r.s[r.pos] > '\x0A' and r.s[r.pos] != ')': 
-    var d = decodeInt(r)
+    var d = decodeVInt(r.s, r.pos)
     inc(r.pos)                # #10
     var p = r.pos
     r.pos = d + r.dataIdx
@@ -767,7 +672,7 @@ proc loadConverters(r: PRodReader) =
     InternalError("importConverters")
   r.pos = r.convertersIdx
   while (r.s[r.pos] > '\x0A'): 
-    var d = decodeInt(r)
+    var d = decodeVInt(r.s, r.pos)
     discard rrGetSym(r, d, UnknownLineInfo())
     if r.s[r.pos] == ' ': inc(r.pos)
   
@@ -818,9 +723,11 @@ proc checkDep(filename: string): TReasonForRecompile =
   gMods[idx].reason = result  # now we know better
   
 proc handleSymbolFile(module: PSym, filename: string): PRodReader = 
-  if not (optSymbolFiles in gGlobalOptions): 
+  if optSymbolFiles notin gGlobalOptions: 
     module.id = getID()
     return nil
+  idgen.loadMaxIds(options.projectPath / options.projectName)
+
   discard checkDep(filename)
   var idx = getModuleIdx(filename)
   if gMods[idx].reason == rrEmpty: InternalError("handleSymbolFile")
diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim
index dad5d679f..037bf450d 100755
--- a/compiler/rodutils.nim
+++ b/compiler/rodutils.nim
@@ -7,8 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-## Utilities for the compiler. Aim is to reduce the coupling between 
-## the compiler and the evolving stdlib.
+## Serialization utilities for the compiler.
+import strutils
 
 proc c_sprintf(buf, frmt: cstring) {.importc: "sprintf", nodecl, varargs.}
 
@@ -25,3 +25,97 @@ proc ToStrMaxPrecision*(f: BiggestFloat): string =
     c_sprintf(buf, "%#.16e", f) 
     result = $buf
 
+proc encodeStr*(s: string, result: var string) =
+  for i in countup(0, len(s) - 1): 
+    case s[i]
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': add(result, s[i])
+    else: add(result, '\\' & toHex(ord(s[i]), 2))
+
+proc hexChar(c: char, xi: var int) = 
+  case c
+  of '0'..'9': xi = (xi shl 4) or (ord(c) - ord('0'))
+  of 'a'..'f': xi = (xi shl 4) or (ord(c) - ord('a') + 10)
+  of 'A'..'F': xi = (xi shl 4) or (ord(c) - ord('A') + 10)
+  else: nil
+
+proc decodeStr*(s: cstring, pos: var int): string =
+  var i = pos
+  result = ""
+  while true: 
+    case s[i]
+    of '\\': 
+      inc(i, 3)
+      var xi = 0
+      hexChar(s[i-2], xi)
+      hexChar(s[i-1], xi)
+      add(result, chr(xi))
+    of 'a'..'z', 'A'..'Z', '0'..'9', '_': 
+      add(result, s[i])
+      inc(i)
+    else: break 
+  pos = i
+
+const
+  chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+template encodeIntImpl(self: expr) =
+  var d: char
+  var v = x
+  var rem = v mod 190
+  if rem < 0: 
+    add(result, '-')
+    v = - (v div 190)
+    rem = - rem
+  else: 
+    v = v div 190
+  var idx = int(rem)
+  if idx < 62: d = chars[idx]
+  else: d = chr(idx - 62 + 128)
+  if v != 0: self(v, result)
+  add(result, d)
+
+proc encodeVBiggestInt*(x: BiggestInt, result: var string) =
+  ## encode a biggest int as a variable length base 190 int.
+  encodeIntImpl(encodeVBiggestInt)
+  
+proc encodeVInt*(x: int, result: var string) = 
+  ## encode an int as a variable length base 190 int.
+  encodeIntImpl(encodeVInt)
+
+template decodeIntImpl() =
+  var i = pos
+  var sign = - 1
+  assert(s[i] in {'a'..'z', 'A'..'Z', '0'..'9', '-', '\x80'..'\xFF'})
+  if s[i] == '-': 
+    inc(i)
+    sign = 1
+  result = 0
+  while true: 
+    case s[i]
+    of '0'..'9': result = result * 190 - (ord(s[i]) - ord('0'))
+    of 'a'..'z': result = result * 190 - (ord(s[i]) - ord('a') + 10)
+    of 'A'..'Z': result = result * 190 - (ord(s[i]) - ord('A') + 36)
+    of '\x80'..'\xFF': result = result * 190 - (ord(s[i]) - 128 + 62)
+    else: break
+    inc(i)
+  result = result * sign
+  pos = i
+
+proc decodeVInt*(s: cstring, pos: var int): int = 
+  decodeIntImpl()
+
+proc decodeVBiggestInt*(s: cstring, pos: var int): biggestInt =
+  decodeIntImpl()
+
+iterator decodeVIntArray*(s: cstring): int =
+  var i = 0
+  while s[i] != '\0':
+    yield decodeVInt(s, i)
+    if s[i] == ' ': inc i
+
+iterator decodeStrArray*(s: cstring): string =
+  var i = 0
+  while s[i] != '\0':
+    yield decodeStr(s, i)
+    if s[i] == ' ': inc i
+
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 0bc73d6f1..247b92ebe 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -13,29 +13,29 @@
 
 import 
   intsets, os, options, strutils, nversion, ast, astalgo, msgs, platform,
-  condsyms, ropes, idents, crc, rodread, passes, importer
+  condsyms, ropes, idents, crc, rodread, passes, importer, idgen, rodutils
 
 proc rodwritePass*(): TPass
 # implementation
 
 type 
   TRodWriter = object of TPassContext
-    module*: PSym
-    crc*: TCrc32
-    options*: TOptions
-    defines*: PRope
-    inclDeps*: PRope
-    modDeps*: PRope
-    interf*: PRope
-    compilerProcs*: PRope
-    index*, imports*: TIndex
-    converters*: PRope
-    init*: PRope
-    data*: PRope
-    filename*: string
-    sstack*: TSymSeq          # a stack of symbols to process
-    tstack*: TTypeSeq         # a stack of types to process
-    files*: TStringSeq
+    module: PSym
+    crc: TCrc32
+    options: TOptions
+    defines: string
+    inclDeps: string
+    modDeps: string
+    interf: string
+    compilerProcs: string
+    index, imports: TIndex
+    converters: string
+    init: string
+    data: string
+    filename: string
+    sstack: TSymSeq          # a stack of symbols to process
+    tstack: TTypeSeq         # a stack of types to process
+    files: TStringSeq
 
   PRodWriter = ref TRodWriter
 
@@ -45,19 +45,17 @@ proc addInclDep(w: PRodWriter, dep: string)
 proc addInterfaceSym(w: PRodWriter, s: PSym)
 proc addStmt(w: PRodWriter, n: PNode)
 proc writeRod(w: PRodWriter)
-proc encodeStr(w: PRodWriter, s: string): PRope = 
-  result = encode(s)
 
 proc processStacks(w: PRodWriter)
 
-proc getDefines(): PRope = 
+proc getDefines(): string = 
   var it: TTabIter
   var s = InitTabIter(it, gSymbols)
-  result = nil
+  result = ""
   while s != nil: 
     if s.position == 1: 
-      if result != nil: app(result, " ")
-      app(result, s.name.s)
+      if result.len != 0: add(result, " ")
+      add(result, s.name.s)
     s = nextIter(it, gSymbols)
 
 proc fileIdx(w: PRodWriter, filename: string): int = 
@@ -74,205 +72,279 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
   result.tstack = @[]
   InitIITable(result.index.tab)
   InitIITable(result.imports.tab)
+  result.index.r = ""
+  result.imports.r = ""
   result.filename = modfilename
   result.crc = crc
   result.module = module
   result.defines = getDefines()
   result.options = options.gOptions
   result.files = @[]
-
+  result.inclDeps = ""
+  result.modDeps = ""
+  result.interf = newStringOfCap(2_000)
+  result.compilerProcs = ""
+  result.converters = ""
+  result.init = ""
+  result.data = newStringOfCap(12_000)
+  
 proc addModDep(w: PRodWriter, dep: string) = 
-  if w.modDeps != nil: app(w.modDeps, " ")
-  app(w.modDeps, encodeInt(fileIdx(w, dep)))
+  if w.modDeps.len != 0: add(w.modDeps, ' ')
+  encodeVInt(fileIdx(w, dep), w.modDeps)
 
 const 
   rodNL = "\x0A"
 
 proc addInclDep(w: PRodWriter, dep: string) = 
-  app(w.inclDeps, encodeInt(fileIdx(w, dep)))
-  app(w.inclDeps, " ")
-  app(w.inclDeps, encodeInt(crcFromFile(dep)))
-  app(w.inclDeps, rodNL)
+  encodeVInt(fileIdx(w, dep), w.inclDeps)
+  add(w.inclDeps, " ")
+  encodeVInt(crcFromFile(dep), w.inclDeps)
+  add(w.inclDeps, rodNL)
 
-proc pushType(w: PRodWriter, t: PType) = 
+proc pushType(w: PRodWriter, t: PType) =
   # check so that the stack does not grow too large:
-  if IiTableGet(w.index.tab, t.id) == invalidKey: 
-    var L = len(w.tstack)
-    setlen(w.tstack, L + 1)
-    w.tstack[L] = t
+  if IiTableGet(w.index.tab, t.id) == invalidKey:
+    w.tstack.add(t)
 
-proc pushSym(w: PRodWriter, s: PSym) = 
+proc pushSym(w: PRodWriter, s: PSym) =
   # check so that the stack does not grow too large:
-  if IiTableGet(w.index.tab, s.id) == invalidKey: 
-    var L = len(w.sstack)
-    setlen(w.sstack, L + 1)
-    w.sstack[L] = s
+  if IiTableGet(w.index.tab, s.id) == invalidKey:
+    w.sstack.add(s)
 
-proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode): PRope = 
+proc encodeNode(w: PRodWriter, fInfo: TLineInfo, n: PNode, 
+                result: var string) = 
   if n == nil: 
     # nil nodes have to be stored too:
-    return toRope("()")
-  result = toRope("(")
-  app(result, encodeInt(ord(n.kind))) 
+    result.add("()")
+    return
+  result.add('(')
+  encodeVInt(ord(n.kind), result) 
   # we do not write comments for now
   # Line information takes easily 20% or more of the filesize! Therefore we
   # omit line information if it is the same as the father's line information:
   if finfo.fileIndex != n.info.fileIndex: 
-    appf(result, "?$1,$2,$3", [encodeInt(n.info.col), encodeInt(n.info.line), 
-                               encodeInt(fileIdx(w, toFilename(n.info)))])
+    result.add('?')
+    encodeVInt(n.info.col, result)
+    result.add(',')
+    encodeVInt(n.info.line, result)
+    result.add(',')
+    encodeVInt(fileIdx(w, toFilename(n.info)), result)
   elif finfo.line != n.info.line:
-    appf(result, "?$1,$2", [encodeInt(n.info.col), encodeInt(n.info.line)])
+    result.add('?')
+    encodeVInt(n.info.col, result)
+    result.add(',')
+    encodeVInt(n.info.line, result)
   elif finfo.col != n.info.col:
-    appf(result, "?$1", [encodeInt(n.info.col)]) 
+    result.add('?')
+    encodeVInt(n.info.col, result)
   # No need to output the file index, as this is the serialization of one
   # file.
   var f = n.flags * PersistentNodeFlags
-  if f != {}: appf(result, "$$$1", [encodeInt(cast[int32](f))])
-  if n.typ != nil: 
-    appf(result, "^$1", [encodeInt(n.typ.id)])
+  if f != {}: 
+    result.add('$')
+    encodeVInt(cast[int32](f), result)
+  if n.typ != nil:
+    result.add('^')
+    encodeVInt(n.typ.id, result)
     pushType(w, n.typ)
   case n.kind
   of nkCharLit..nkInt64Lit: 
-    if n.intVal != 0: appf(result, "!$1", [encodeInt(n.intVal)])
+    if n.intVal != 0:
+      result.add('!')
+      encodeVBiggestInt(n.intVal, result)
   of nkFloatLit..nkFloat64Lit: 
-    if n.floatVal != 0.0: appf(result, "!$1", [encodeStr(w, $n.floatVal)])
-  of nkStrLit..nkTripleStrLit: 
-    if n.strVal != "": appf(result, "!$1", [encodeStr(w, n.strVal)])
-  of nkIdent: 
-    appf(result, "!$1", [encodeStr(w, n.ident.s)])
-  of nkSym: 
-    appf(result, "!$1", [encodeInt(n.sym.id)])
+    if n.floatVal != 0.0: 
+      result.add('!')
+      encodeStr($n.floatVal, result)
+  of nkStrLit..nkTripleStrLit:
+    if n.strVal != "": 
+      result.add('!')
+      encodeStr(n.strVal, result)
+  of nkIdent:
+    result.add('!')
+    encodeStr(n.ident.s, result)
+  of nkSym:
+    result.add('!')
+    encodeVInt(n.sym.id, result)
     pushSym(w, n.sym)
-  else: 
+  else:
     for i in countup(0, sonsLen(n) - 1): 
-      app(result, encodeNode(w, n.info, n.sons[i]))
-  app(result, ")")
-
-proc encodeLoc(w: PRodWriter, loc: TLoc): PRope = 
-  result = nil
-  if loc.k != low(loc.k): app(result, encodeInt(ord(loc.k)))
-  if loc.s != low(loc.s): appf(result, "*$1", [encodeInt(ord(loc.s))])
-  if loc.flags != {}: appf(result, "$$$1", [encodeInt(cast[int32](loc.flags))])
-  if loc.t != nil: 
-    appf(result, "^$1", [encodeInt(loc.t.id)])
+      encodeNode(w, n.info, n.sons[i], result)
+  add(result, ')')
+
+proc encodeLoc(w: PRodWriter, loc: TLoc, result: var string) = 
+  var oldLen = result.len
+  result.add('<')
+  if loc.k != low(loc.k): encodeVInt(ord(loc.k), result)
+  if loc.s != low(loc.s): 
+    add(result, '*')
+    encodeVInt(ord(loc.s), result)
+  if loc.flags != {}: 
+    add(result, '$')
+    encodeVInt(cast[int32](loc.flags), result)
+  if loc.t != nil:
+    add(result, '^')
+    encodeVInt(cast[int32](loc.t.id), result)
     pushType(w, loc.t)
-  if loc.r != nil: appf(result, "!$1", [encodeStr(w, ropeToStr(loc.r))])
-  if loc.a != 0: appf(result, "?$1", [encodeInt(loc.a)])
-  if result != nil: result = ropef("<$1>", [result])
+  if loc.r != nil: 
+    add(result, '!')
+    encodeStr(ropeToStr(loc.r), result)
+  if loc.a != 0: 
+    add(result, '?')
+    encodeVInt(loc.a, result)
+  if oldlen + 1 == result.len:
+    # no data was necessary, so remove the '<' again:
+    setLen(result, oldLen)
+  else:
+    add(result, '>')
   
-proc encodeType(w: PRodWriter, t: PType): PRope = 
+proc encodeType(w: PRodWriter, t: PType, result: var string) = 
   if t == nil: 
     # nil nodes have to be stored too:
-    return toRope("[]")
-  result = nil
+    result.add("[]")
+    return
+  # we need no surrounding [] here because the type is in a line of its own
   if t.kind == tyForward: InternalError("encodeType: tyForward")
-  app(result, encodeInt(ord(t.kind)))
-  appf(result, "+$1", [encodeInt(t.id)])
-  if t.n != nil: app(result, encodeNode(w, UnknownLineInfo(), t.n))
-  if t.flags != {}: appf(result, "$$$1", [encodeInt(cast[int32](t.flags))])
+  encodeVInt(ord(t.kind), result)
+  add(result, '+')
+  encodeVInt(t.id, result)
+  if t.n != nil: 
+    encodeNode(w, UnknownLineInfo(), t.n, result)
+  if t.flags != {}: 
+    add(result, '$')
+    encodeVInt(cast[int32](t.flags), result)
   if t.callConv != low(t.callConv): 
-    appf(result, "?$1", [encodeInt(ord(t.callConv))])
+    add(result, '?')
+    encodeVInt(ord(t.callConv), result)
   if t.owner != nil: 
-    appf(result, "*$1", [encodeInt(t.owner.id)])
+    add(result, '*')
+    encodeVInt(t.owner.id, result)
     pushSym(w, t.owner)
   if t.sym != nil: 
-    appf(result, "&$1", [encodeInt(t.sym.id)])
+    add(result, '&')
+    encodeVInt(t.sym.id, result)
     pushSym(w, t.sym)
-  if t.size != - 1: appf(result, "/$1", [encodeInt(t.size)])
-  if t.align != 2: appf(result, "=$1", [encodeInt(t.align)])
-  if t.containerID != 0: appf(result, "@$1", [encodeInt(t.containerID)])
-  app(result, encodeLoc(w, t.loc))
+  if t.size != - 1: 
+    add(result, '/')
+    encodeVBiggestInt(t.size, result)
+  if t.align != 2: 
+    add(result, '=')
+    encodeVInt(t.align, result)
+  if t.containerID != 0: 
+    add(result, '@')
+    encodeVInt(t.containerID, result)
+  encodeLoc(w, t.loc, result)
   for i in countup(0, sonsLen(t) - 1): 
     if t.sons[i] == nil: 
-      app(result, "^()")
+      add(result, "^()")
     else: 
-      appf(result, "^$1", [encodeInt(t.sons[i].id)])
+      add(result, '^') 
+      encodeVInt(t.sons[i].id, result)
       pushType(w, t.sons[i])
 
-proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo): PRope = 
-  result = nil
-  appf(result, "|$1", [encodeInt(ord(lib.kind))])
-  appf(result, "|$1", [encodeStr(w, ropeToStr(lib.name))])
-  appf(result, "|$1", [encodeNode(w, info, lib.path)])
-
-proc encodeSym(w: PRodWriter, s: PSym): PRope = 
-  var 
-    codeAst: PNode
-    col, line: PRope
-  codeAst = nil
-  if s == nil: 
+proc encodeLib(w: PRodWriter, lib: PLib, info: TLineInfo, result: var string) = 
+  add(result, '|')
+  encodeVInt(ord(lib.kind), result)
+  add(result, '|')
+  encodeStr(ropeToStr(lib.name), result)
+  add(result, '|')
+  encodeNode(w, info, lib.path, result)
+
+proc encodeSym(w: PRodWriter, s: PSym, result: var string) =
+  if s == nil:
     # nil nodes have to be stored too:
-    return toRope("{}")
-  result = nil
-  app(result, encodeInt(ord(s.kind)))
-  appf(result, "+$1", [encodeInt(s.id)])
-  appf(result, "&$1", [encodeStr(w, s.name.s)])
-  if s.typ != nil: 
-    appf(result, "^$1", [encodeInt(s.typ.id)])
+    result.add("{}")
+    return
+  # we need no surrounding {} here because the symbol is in a line of its own
+  encodeVInt(ord(s.kind), result)
+  result.add('+')
+  encodeVInt(s.id, result)
+  result.add('&')
+  encodeStr(s.name.s, result)
+  if s.typ != nil:
+    result.add('^')
+    encodeVInt(s.typ.id, result)
     pushType(w, s.typ)
-  if s.info.col == int16(- 1): col = nil
-  else: col = encodeInt(s.info.col)
-  if s.info.line == int16(- 1): line = nil
-  else: line = encodeInt(s.info.line)
-  appf(result, "?$1,$2,$3", 
-       [col, line, encodeInt(fileIdx(w, toFilename(s.info)))])
-  if s.owner != nil: 
-    appf(result, "*$1", [encodeInt(s.owner.id)])
+  result.add('?')
+  if s.info.col != -1'i16: encodeVInt(s.info.col, result)
+  result.add(',')
+  if s.info.line != -1'i16: encodeVInt(s.info.line, result)
+  result.add(',')
+  encodeVInt(fileIdx(w, toFilename(s.info)), result)
+  if s.owner != nil:
+    result.add('*')
+    encodeVInt(s.owner.id, result)
     pushSym(w, s.owner)
-  if s.flags != {}: appf(result, "$$$1", [encodeInt(cast[int32](s.flags))])
-  if s.magic != mNone: appf(result, "@$1", [encodeInt(ord(s.magic))])
-  if (s.ast != nil): 
-    if not astNeeded(s): 
+  if s.flags != {}:
+    result.add('$')
+    encodeVInt(cast[int32](s.flags), result)
+  if s.magic != mNone:
+    result.add('@')
+    encodeVInt(ord(s.magic), result)
+  if s.ast != nil: 
+    var codeAst: PNode = nil
+    if not astNeeded(s):
       codeAst = s.ast.sons[codePos]
+      # ugly hack to not store the AST:
       s.ast.sons[codePos] = nil
-    app(result, encodeNode(w, s.info, s.ast))
-    if codeAst != nil: 
+    encodeNode(w, s.info, s.ast, result)
+    if codeAst != nil:
+      # resore the AST:
       s.ast.sons[codePos] = codeAst
   if s.options != w.options: 
-    appf(result, "!$1", [encodeInt(cast[int32](s.options))])
-  if s.position != 0: appf(result, "%$1", [encodeInt(s.position)])
-  if s.offset != - 1: appf(result, "`$1", [encodeInt(s.offset)])
-  app(result, encodeLoc(w, s.loc))
-  if s.annex != nil: app(result, encodeLib(w, s.annex, s.info))
+    result.add('!')
+    encodeVInt(cast[int32](s.options), result)
+  if s.position != 0: 
+    result.add('%')
+    encodeVInt(s.position, result)
+  if s.offset != - 1:
+    result.add('`')
+    encodeVInt(s.offset, result)
+  encodeLoc(w, s.loc, result)
+  if s.annex != nil: encodeLib(w, s.annex, s.info, result)
   
-proc addToIndex(w: var TIndex, key, val: int) = 
-  if key - w.lastIdxKey == 1: 
+proc addToIndex(w: var TIndex, key, val: int) =
+  if key - w.lastIdxKey == 1:
     # we do not store a key-diff of 1 to safe space
-    app(w.r, encodeInt(val - w.lastIdxVal))
-    app(w.r, rodNL)
-  else: 
-    appf(w.r, "$1 $2" & rodNL, 
-         [encodeInt(key - w.lastIdxKey), encodeInt(val - w.lastIdxVal)])
+    encodeVInt(val - w.lastIdxVal, w.r)
+  else:
+    encodeVInt(key - w.lastIdxKey, w.r)
+    add(w.r, ' ')
+    encodeVInt(val - w.lastIdxVal, w.r)
+  add(w.r, rodNL)
   w.lastIdxKey = key
   w.lastIdxVal = val
   IiTablePut(w.tab, key, val)
 
 var debugWritten: TIntSet
 
-proc symStack(w: PRodWriter) = 
-  var 
-    i, L: int
-    s, m: PSym
-  i = 0
+proc symStack(w: PRodWriter) =
+  var i = 0
   while i < len(w.sstack): 
-    s = w.sstack[i]
+    var s = w.sstack[i]
     if IiTableGet(w.index.tab, s.id) == invalidKey: 
-      m = getModule(s)
+      var m = getModule(s)
       if m == nil: InternalError("symStack: module nil: " & s.name.s)
       if (m.id == w.module.id) or (sfFromGeneric in s.flags): 
         # put definition in here
-        L = ropeLen(w.data)
-        addToIndex(w.index, s.id, L) #intSetIncl(debugWritten, s.id);
-        app(w.data, encodeSym(w, s))
-        app(w.data, rodNL)
+        var L = w.data.len
+        addToIndex(w.index, s.id, L) 
+        #intSetIncl(debugWritten, s.id)
+        encodeSym(w, s, w.data)
+        add(w.data, rodNL)
         if sfExported in s.flags: 
-          appf(w.interf, "$1 $2" & rodNL, [encode(s.name.s), encodeInt(s.id)])
-        if sfCompilerProc in s.flags: 
-          appf(w.compilerProcs, "$1 $2" & rodNL, 
-               [encode(s.name.s), encodeInt(s.id)])
+          encodeStr(s.name.s, w.interf)
+          add(w.interf, ' ')
+          encodeVInt(s.id, w.interf)
+          add(w.interf, rodNL)
+        if sfCompilerProc in s.flags:
+          encodeStr(s.name.s, w.compilerProcs)
+          add(w.compilerProcs, ' ')
+          encodeVInt(s.id, w.compilerProcs)
+          add(w.compilerProcs, rodNL)
         if s.kind == skConverter: 
-          if w.converters != nil: app(w.converters, " ")
-          app(w.converters, encodeInt(s.id))
+          if w.converters.len != 0: add(w.converters, ' ')
+          encodeVInt(s.id, w.converters)
       elif IiTableGet(w.imports.tab, s.id) == invalidKey: 
         addToIndex(w.imports, s.id, m.id) #if not Contains(debugWritten, s.id):
                                           #  MessageOut(w.filename);
@@ -287,10 +359,10 @@ proc typeStack(w: PRodWriter) =
   var i = 0
   while i < len(w.tstack): 
     if IiTableGet(w.index.tab, w.tstack[i].id) == invalidKey: 
-      var L = ropeLen(w.data)
+      var L = w.data.len
       addToIndex(w.index, w.tstack[i].id, L)
-      app(w.data, encodeType(w, w.tstack[i]))
-      app(w.data, rodNL)
+      encodeType(w, w.tstack[i], w.data)
+      add(w.data, rodNL)
     inc(i)
   setlen(w.tstack, 0)
 
@@ -309,66 +381,88 @@ proc addInterfaceSym(w: PRodWriter, s: PSym) =
     rawAddInterfaceSym(w, s)
 
 proc addStmt(w: PRodWriter, n: PNode) = 
-  app(w.init, encodeInt(ropeLen(w.data)))
-  app(w.init, rodNL)
-  app(w.data, encodeNode(w, UnknownLineInfo(), n))
-  app(w.data, rodNL)
+  encodeVInt(w.data.len, w.init)
+  add(w.init, rodNL)
+  encodeNode(w, UnknownLineInfo(), n, w.data)
+  add(w.data, rodNL)
   processStacks(w)
 
 proc writeRod(w: PRodWriter) = 
-  processStacks(w)            # write header:
-  var content = toRope("NIM:")
-  app(content, toRope(FileVersion))
-  app(content, rodNL)
-  app(content, toRope("ID:"))
-  app(content, encodeInt(w.module.id))
-  app(content, rodNL)
-  app(content, toRope("CRC:"))
-  app(content, encodeInt(w.crc))
-  app(content, rodNL)
-  app(content, toRope("OPTIONS:"))
-  app(content, encodeInt(cast[int32](w.options)))
-  app(content, rodNL)
-  app(content, toRope("DEFINES:"))
-  app(content, w.defines)
-  app(content, rodNL)
-  app(content, toRope("FILES(" & rodNL))
+  processStacks(w)
+  var f: TFile
+  if not open(f, completeGeneratedFilePath(changeFileExt(w.filename, "rod")),
+              fmWrite):
+    return
+  # write header:
+  f.write("NIM:")
+  f.write(FileVersion)
+  f.write(rodNL)
+  var id = "ID:"
+  encodeVInt(w.module.id, id)
+  f.write(id)
+  f.write(rodNL)
+  
+  var crc = "CRC:"
+  encodeVInt(w.crc, crc)
+  f.write(crc)
+  f.write(rodNL)
+  
+  var options = "OPTIONS:"
+  encodeVInt(cast[int32](w.options), options)
+  f.write(options)
+  f.write(rodNL)
+  
+  f.write("DEFINES:")
+  f.write(w.defines)
+  f.write(rodNL)
+  
+  var files = "FILES(" & rodNL
   for i in countup(0, high(w.files)): 
-    app(content, encode(w.files[i]))
-    app(content, rodNL)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("INCLUDES(" & rodNL))
-  app(content, w.inclDeps)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("DEPS:"))
-  app(content, w.modDeps)
-  app(content, rodNL)
-  app(content, toRope("INTERF(" & rodNL))
-  app(content, w.interf)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("COMPILERPROCS(" & rodNL))
-  app(content, w.compilerProcs)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("INDEX(" & rodNL))
-  app(content, w.index.r)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("IMPORTS(" & rodNL))
-  app(content, w.imports.r)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("CONVERTERS:"))
-  app(content, w.converters)
-  app(content, toRope(rodNL))
-  app(content, toRope("INIT(" & rodNL))
-  app(content, w.init)
-  app(content, toRope(')' & rodNL))
-  app(content, toRope("DATA(" & rodNL))
-  app(content, w.data)
-  app(content, toRope(')' & rodNL)) 
-  #MessageOut('interf ' + ToString(ropeLen(w.interf)));
-  #MessageOut('index ' + ToString(ropeLen(w.indexRope)));
-  #MessageOut('init ' + ToString(ropeLen(w.init)));
-  #MessageOut('data ' + ToString(ropeLen(w.data)));
-  writeRope(content, completeGeneratedFilePath(changeFileExt(w.filename, "rod")))
+    encodeStr(w.files[i], files)
+    files.add(rodNL)
+  f.write(files)
+  f.write(')' & rodNL)
+  
+  f.write("INCLUDES(" & rodNL)
+  f.write(w.inclDeps)
+  f.write(')' & rodNL)
+  
+  f.write("DEPS:")
+  f.write(w.modDeps)
+  f.write(rodNL)
+  
+  f.write("INTERF(" & rodNL)
+  f.write(w.interf)
+  f.write(')' & rodNL)
+  
+  f.write("COMPILERPROCS(" & rodNL)
+  f.write(w.compilerProcs)
+  f.write(')' & rodNL)
+
+  f.write("INDEX(" & rodNL)
+  f.write(w.index.r)
+  f.write(')' & rodNL)
+  
+  f.write("IMPORTS(" & rodNL)
+  f.write(w.imports.r)
+  f.write(')' & rodNL)
+  
+  f.write("CONVERTERS:")
+  f.write(w.converters)
+  f.write(rodNL)
+  
+  f.write("INIT(" & rodNL)
+  f.write(w.init)
+  f.write(')' & rodNL)
+  
+  f.write("DATA(" & rodNL)
+  f.write(w.data)
+  f.write(')' & rodNL)
+  f.close()
+  #MessageOut('interf ' + ToString(ropeLen(w.interf)))
+  #MessageOut('index ' + ToString(ropeLen(w.indexRope)))
+  #MessageOut('init ' + ToString(ropeLen(w.init)))
+  #MessageOut('data ' + ToString(ropeLen(w.data)))
 
 proc process(c: PPassContext, n: PNode): PNode = 
   result = n
@@ -438,6 +532,7 @@ proc myClose(c: PPassContext, n: PNode): PNode =
   var w = PRodWriter(c)
   writeRod(w)
   result = n
+  idgen.saveMaxIds(options.projectPath / options.projectName)
 
 proc rodwritePass(): TPass = 
   initPass(result)
@@ -446,4 +541,4 @@ proc rodwritePass(): TPass =
     result.close = myClose
     result.process = process
 
-debugWritten= initIntSet()
+debugWritten = initIntSet()
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 7b9f7c4e1..1cb0e3b68 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -14,7 +14,7 @@ import
   wordrecg, ropes, msgs, os, condsyms, idents, renderer, types, platform, math,
   magicsys, parser, nversion, semdata, nimsets, semfold, importer,
   procfind, lookups, rodread, pragmas, passes, semtypinst, sigmatch, suggest,
-  semthreads, intsets, transf, evals
+  semthreads, intsets, transf, evals, idgen
 
 proc semPass*(): TPass
 # implementation
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 1a8182437..d98d60224 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -158,7 +158,7 @@ proc SemReturn(c: PContext, n: PNode): PNode =
     globalError(n.info, errXNotAllowedHere, "\'return\'")
   if n.sons[0].kind != nkEmpty:
     # transform ``return expr`` to ``result = expr; return``
-    if c.p.resultSym == nil: InternalError(n.info, "semReturn")
+    if c.p.resultSym == nil: globalError(n.info, errNoReturnTypeDeclared)
     var a = newNodeI(nkAsgn, n.sons[0].info)
     addSon(a, newSymNode(c.p.resultSym))
     addSon(a, n.sons[0])
diff --git a/compiler/treetab.nim b/compiler/treetab.nim
index e8fc39be9..d13e4587f 100755
--- a/compiler/treetab.nim
+++ b/compiler/treetab.nim
@@ -7,7 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-# Implements a table from trees to trees. Does structural equavilent checking.
+# Implements a table from trees to trees. Does structural equivalence checking.
 
 import 
   hashes, ast, astalgo, types
diff --git a/lib/impure/db_sqlite.nim b/lib/impure/db_sqlite.nim
index 8c2de0dc7..d09051cd4 100755
--- a/lib/impure/db_sqlite.nim
+++ b/lib/impure/db_sqlite.nim
@@ -118,8 +118,7 @@ proc GetValue*(db: TDbConn, query: TSqlQuery,
   ## of the first row. Returns "" if the dataset contains no rows.
   var stmt = setupQuery(db, query, args)
   if step(stmt) == SQLITE_ROW: 
-    result = newString(column_bytes(stmt, 0))
-    setLen(result, 0)
+    result = newStringOfCap(column_bytes(stmt, 0))
     add(result, column_text(stmt, 0))
     if finalize(stmt) != SQLITE_OK: dbError(db)
   else:
diff --git a/todo.txt b/todo.txt
index 233504fd6..5d54a6386 100755
--- a/todo.txt
+++ b/todo.txt
@@ -9,6 +9,7 @@ Version 0.8.14
 - optional indentation for 'case' statement
 - document & test splicing; don't forget to test negative indexes
 - thread local vs. global raiseHook()
+- incremental compilation (!)
 
 
 version 0.9.0
@@ -105,41 +106,6 @@ Low priority
 - timeout for locks
 
 
-Super operators
-===============
-
-macro (pattern) [T](arg: array[T]) =
-  
-  
-
-Patterns
---------
-
-Patterns are PEGs over the Nimrod AST. Patterns consist of:
-
-  type
-    TPatternKind = enum
-      pkAny,              ## any node (.)
-      pkNodeClass,        ## set of node kinds
-      pkTerminal,         ## 'xyz'
-      pkNonTerminal,      ## a
-      pkSequence,         ## a b c
-      pkOrderedChoice,    ## a / b / c
-      pkGreedyRep,        ## a*
-                          ## a+     --> (a a*)
-      pkOption,           ## a?
-      pkAndPredicate,     ## &a
-      pkNotPredicate,     ## !a
-      pkCapture,          ## {a}
-      pkBackRef,          ## $i
-      pkSearch,           ## @a
-      pkCapturedSearch,   ## {@} a
-      pkRule,             ## a <- b
-      pkGrammar,          ## list of rules
-  
-Choice operator requires capture.
-
-
 Version 2
 =========