summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim7
-rwxr-xr-xcompiler/ccgexprs.nim2
-rwxr-xr-xcompiler/ccgstmts.nim2
-rwxr-xr-xcompiler/cgen.nim2
-rwxr-xr-xcompiler/cgmeth.nim4
-rwxr-xr-xcompiler/ecmasgen.nim4
-rwxr-xr-xcompiler/evals.nim14
-rwxr-xr-xcompiler/nversion.nim2
-rwxr-xr-xcompiler/passaux.nim2
-rwxr-xr-xcompiler/renderer.nim2
-rwxr-xr-xcompiler/rodread.nim60
-rwxr-xr-xcompiler/rodwrite.nim4
-rwxr-xr-xcompiler/sem.nim2
-rwxr-xr-xcompiler/semgnrc.nim5
-rwxr-xr-xcompiler/seminst.nim11
-rwxr-xr-xcompiler/semstmts.nim30
-rwxr-xr-xcompiler/semtempl.nim10
-rwxr-xr-xcompiler/semthreads.nim8
-rwxr-xr-xcompiler/transf.nim19
-rwxr-xr-xtests/tester.nim35
-rwxr-xr-xtodo.txt10
21 files changed, 152 insertions, 83 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 550bda122..eca51f704 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -333,6 +333,11 @@ type
                           # mean: never)
   TSymKinds* = set[TSymKind]
 
+const
+  routineKinds* = {skProc, skMethod, skIterator, skConverter,
+    skMacro, skTemplate}
+
+type
   TMagic* = enum # symbols that require compiler magic:
     mNone, mDefined, mDefinedInScope, mLow, mHigh, mSizeOf, mIs, mOf,
     mEcho, mShallowCopy, mSlurp,
@@ -579,7 +584,7 @@ const
   genericParamsPos* = 1
   paramsPos* = 2
   pragmasPos* = 3
-  codePos* = 4
+  bodyPos* = 4       # position of body; use rodread.getBody() instead!
   resultPos* = 5
   dispatcherPos* = 6 # caution: if method has no 'result' it can be position 5!
 
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 5839db2be..c957e0aaa 100755
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -1734,7 +1734,7 @@ proc expr(p: BProc, e: PNode, d: var TLoc) =
     var sym = e.sym
     case sym.Kind
     of skMethod:
-      if sym.ast.sons[codePos].kind == nkEmpty:
+      if sym.getBody.kind == nkEmpty:
         # we cannot produce code for the dispatcher yet:
         fillProcLoc(sym)
         genProcPrototype(p.module, sym)
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 346f86737..567240302 100755
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -702,7 +702,7 @@ proc genStmts(p: BProc, t: PNode) =
           (sfExportc in prc.flags and lfExportLib in prc.loc.flags) or
           (prc.kind == skMethod): 
         # we have not only the header: 
-        if t.sons[codePos].kind != nkEmpty or lfDynamicLib in prc.loc.flags: 
+        if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: 
           genProc(p.module, prc)
   else: internalError(t.info, "genStmts(" & $t.kind & ')')
   
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 7e16042f8..671fdd05f 100755
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -544,7 +544,7 @@ proc genProcAux(m: BModule, prc: PSym) =
   for i in countup(1, sonsLen(prc.typ.n) - 1): 
     var param = prc.typ.n.sons[i].sym
     assignParam(p, param)
-  genStmts(p, prc.ast.sons[codePos]) # modifies p.locals, p.init, etc.
+  genStmts(p, prc.getBody) # modifies p.locals, p.init, etc.
   var generatedProc: PRope
   if sfPure in prc.flags: 
     generatedProc = ropeff("$1 {$n$2$3$4}$n", "define $1 {$n$2$3$4}$n",
diff --git a/compiler/cgmeth.nim b/compiler/cgmeth.nim
index e2c3c009c..ccd750445 100755
--- a/compiler/cgmeth.nim
+++ b/compiler/cgmeth.nim
@@ -95,7 +95,7 @@ proc methodDef*(s: PSym, fromCache: bool) =
     # we can't inline the dispatcher itself (for now):
     if disp.typ.callConv == ccInline: disp.typ.callConv = ccDefault
     disp.ast = copyTree(s.ast)
-    disp.ast.sons[codePos] = ast.emptyNode
+    disp.ast.sons[bodyPos] = ast.emptyNode
     if s.typ.sons[0] != nil: 
       disp.ast.sons[resultPos].sym = copySym(s.ast.sons[resultPos].sym)
     attachDispatcher(s, newSymNode(disp))
@@ -183,7 +183,7 @@ proc genDispatcher(methods: TSymSeq, relevantCols: TIntSet): PSym =
       addSon(disp, a)
     else:
       disp = ret
-  result.ast.sons[codePos] = disp
+  result.ast.sons[bodyPos] = disp
 
 proc generateMethodDispatchers*(): PNode = 
   result = newNode(nkStmtList)
diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim
index cafe9b2a3..d7af07e60 100755
--- a/compiler/ecmasgen.nim
+++ b/compiler/ecmasgen.nim
@@ -1309,7 +1309,7 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) =
     gen(p, prc.ast.sons[resultPos], a)
     if a.com != nil: appf(returnStmt, "$1;$n", [a.com])
     returnStmt = ropef("return $1;$n", [a.res])
-  genStmt(p, prc.ast.sons[codePos], r)
+  genStmt(p, prc.getBody, r)
   r.com = ropef("function $1($2) {$n$3$4$5}$n", 
                 [name, header, resultAsgn, genProcBody(p, prc, r), returnStmt])
   r.res = nil  
@@ -1360,7 +1360,7 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
   of nkProcDef, nkMethodDef, nkConverterDef: 
     if (n.sons[genericParamsPos].kind == nkEmpty): 
       var prc = n.sons[namePos].sym
-      if (prc.ast.sons[codePos].kind != nkEmpty) and not (lfNoDecl in prc.loc.flags): 
+      if lfNoDecl notin prc.loc.flags and prc.getBody.kind != nkEmpty:
         genProc(p, prc, r)
       else:
         discard mangleName(prc)
diff --git a/compiler/evals.nim b/compiler/evals.nim
index a332490d1..68a99a0a1 100755
--- a/compiler/evals.nim
+++ b/compiler/evals.nim
@@ -16,7 +16,7 @@
 import 
   strutils, magicsys, lists, options, ast, astalgo, trees, treetab, nimsets, 
   msgs, os, condsyms, idents, renderer, types, passes, semfold, transf, 
-  parser, ropes
+  parser, ropes, rodread
 
 type 
   PStackFrame* = ref TStackFrame
@@ -448,7 +448,8 @@ proc evalSwap(c: PEvalContext, n: PNode): PNode =
 proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = 
   var s = n.sym
   case s.kind
-  of skProc, skConverter, skMacro: result = s.ast.sons[codePos]
+  of skProc, skConverter, skMacro: 
+    result = s.getBody
   of skVar, skForVar, skTemp, skResult:
     if sfGlobal notin s.flags:
       result = evalVariable(c.tos, s, flags)
@@ -621,15 +622,16 @@ proc evalReturn(c: PEvalContext, n: PNode): PNode =
 
 proc evalProc(c: PEvalContext, n: PNode): PNode = 
   if n.sons[genericParamsPos].kind == nkEmpty: 
+    var s = n.sons[namePos].sym
     if (resultPos < sonsLen(n)) and (n.sons[resultPos].kind != nkEmpty): 
       var v = n.sons[resultPos].sym
       result = getNullValue(v.typ, n.info)
       IdNodeTablePut(c.tos.mapping, v, result)
-      result = evalAux(c, n.sons[codePos], {})
+      result = evalAux(c, s.getBody, {})
       if result.kind == nkReturnToken: 
         result = IdNodeTableGet(c.tos.mapping, v)
     else:
-      result = evalAux(c, n.sons[codePos], {})
+      result = evalAux(c, s.getBody, {})
       if result.kind == nkReturnToken: 
         result = emptyNode
   else: 
@@ -852,7 +854,7 @@ proc evalTemplate(n: PNode, sym: PSym): PNode =
 
   # replace each param by the corresponding node:
   var args = evalTemplateArgs(n, sym)
-  result = evalTemplateAux(sym.ast.sons[codePos], args, sym)
+  result = evalTemplateAux(sym.getBody, args, sym)
 
   dec(evalTemplateCounter)
   
@@ -1273,7 +1275,7 @@ proc evalMacroCall*(c: PEvalContext, n: PNode, sym: PSym): PNode =
   s.params[0] = newNodeIT(nkNilLit, n.info, sym.typ.sons[0])
   s.params[1] = n
   pushStackFrame(c, s)
-  discard eval(c, sym.ast.sons[codePos])
+  discard eval(c, sym.getBody)
   result = s.params[0]
   popStackFrame(c)
   if cyclicTree(result): GlobalError(n.info, errCyclicTree)
diff --git a/compiler/nversion.nim b/compiler/nversion.nim
index 1038a8ea6..a91307300 100755
--- a/compiler/nversion.nim
+++ b/compiler/nversion.nim
@@ -18,5 +18,5 @@ const
   VersionPatch* = 13
   VersionAsString* = $VersionMajor & "." & $VersionMinor & "." & $VersionPatch
 
-  RodFileVersion* = "1030"       # modify this if the rod-format changes!
+  RodFileVersion* = "1031"       # modify this if the rod-format changes!
 
diff --git a/compiler/passaux.nim b/compiler/passaux.nim
index 659a9a346..3197e0b8c 100755
--- a/compiler/passaux.nim
+++ b/compiler/passaux.nim
@@ -42,7 +42,7 @@ proc cleanUp(c: PPassContext, n: PNode): PNode =
     if n.sons[namePos].kind == nkSym: 
       var s = n.sons[namePos].sym
       if sfDeadCodeElim notin getModule(s).flags and not astNeeded(s): 
-        s.ast.sons[codePos] = ast.emptyNode # free the memory
+        s.ast.sons[bodyPos] = ast.emptyNode # free the memory
   else: 
     nil
 
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 316e1f42f..a38fba907 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -780,7 +780,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsub(g, n.sons[pragmasPos])
     put(g, tkSpaces, Space)
     putWithSpace(g, tkEquals, "=")
-    gsub(g, n.sons[codePos])
+    gsub(g, n.sons[bodyPos])
   of nkConstDef, nkIdentDefs: 
     gcomma(g, n, 0, - 3)
     var L = sonsLen(n)
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index 08721fd4a..0cc91140d 100755
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -169,7 +169,22 @@ proc decodeLineInfo(r: PRodReader, info: var TLineInfo) =
         inc(r.pos)
         info = newLineInfo(r.files[decodeVInt(r.s, r.pos)], info.line, info.col)
 
-proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = 
+proc skipNode(r: PRodReader) =
+  assert r.s[r.pos] == '('
+  var par = 0
+  var pos = r.pos+1
+  while true:
+    case r.s[pos]
+    of ')':
+      if par == 0: break
+      dec par
+    of '(': inc par
+    else: nil
+    inc pos
+  r.pos = pos+1 # skip ')'
+
+proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo, 
+                        belongsTo: PSym): PNode = 
   result = nil
   if r.s[r.pos] == '(': 
     inc(r.pos)
@@ -216,12 +231,22 @@ proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
       else: 
         internalError(result.info, "decodeNode: nkSym")
     else:
+      var i = 0
       while r.s[r.pos] != ')': 
-        addSonNilAllowed(result, decodeNode(r, result.info))
+        if belongsTo != nil and i == bodyPos:
+          addSonNilAllowed(result, nil)
+          belongsTo.offset = r.pos
+          skipNode(r)
+        else:
+          addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil))
+        inc i
     if r.s[r.pos] == ')': inc(r.pos)
     else: internalError(result.info, "decodeNode")
   else: 
-    InternalError(result.info, "decodeNode " & r.s[r.pos])
+    InternalError(fInfo, "decodeNode " & r.s[r.pos])
+
+proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
+  result = decodeNodeLazyBody(r, fInfo, nil)
   
 proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) = 
   if r.s[r.pos] == '<': 
@@ -381,9 +406,10 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
   if r.s[r.pos] == '%': 
     inc(r.pos)
     result.position = decodeVInt(r.s, r.pos)
-  else: 
-    result.position = 0       
-    # BUGFIX: this may have been misused as reader index!
+  elif result.kind notin routineKinds:
+    result.position = 0
+    # BUGFIX: this may have been misused as reader index! But we still
+    # need it for routines as the body is loaded lazily.
   if r.s[r.pos] == '`': 
     inc(r.pos)
     result.offset = decodeVInt(r.s, r.pos)
@@ -391,7 +417,11 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
     result.offset = - 1
   decodeLoc(r, result.loc, result.info)
   result.annex = decodeLib(r, info)
-  if r.s[r.pos] == '(': result.ast = decodeNode(r, result.info)
+  if r.s[r.pos] == '(':
+    if result.kind in routineKinds:
+      result.ast = decodeNodeLazyBody(r, result.info, result)
+    else:
+      result.ast = decodeNode(r, result.info)
   #echo "decoded: ", ident.s, "}"
 
 proc skipSection(r: PRodReader) = 
@@ -815,5 +845,21 @@ proc loadStub(s: PSym) =
     InternalError(rs.info, "loadStub: wrong ID") 
   #MessageOut('loaded stub: ' + s.name.s);
   
+proc getBody*(s: PSym): PNode =
+  ## retrieves the AST's body of `s`. If `s` has been loaded from a rod-file
+  ## it may perform an expensive reload operation. Otherwise it's a simple
+  ## accessor.
+  assert s.kind in routineKinds
+  result = s.ast.sons[bodyPos]
+  if result == nil:
+    assert s.offset != 0
+    var r = gMods[s.position].rd
+    var oldPos = r.pos
+    r.pos = s.offset
+    result = decodeNode(r, s.info)
+    r.pos = oldPos
+    s.ast.sons[bodyPos] = result
+    s.offset = 0
+  
 InitIdTable(gTypeTable)
 InitStrTable(rodCompilerProcs)
diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim
index 6df1fbffd..d217d1740 100755
--- a/compiler/rodwrite.nim
+++ b/compiler/rodwrite.nim
@@ -526,7 +526,9 @@ proc process(c: PPassContext, n: PNode): PNode =
   of nkProcDef, nkMethodDef, nkIteratorDef, nkConverterDef: 
     var s = n.sons[namePos].sym
     if s == nil: InternalError(n.info, "rodwrite.process")
-    if n.sons[codePos].kind != nkEmpty or s.magic != mNone or
+    if n.sons[bodyPos] == nil:
+      InternalError(n.info, "rodwrite.process: body is nil")
+    if n.sons[bodyPos].kind != nkEmpty or s.magic != mNone or
         sfForward notin s.flags:
       addInterfaceSym(w, s)
   of nkVarSection:
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 47d89436b..78f7df940 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -130,7 +130,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
   for i in countup(c.generics.lastGenericIdx, Len(c.generics.generics) - 1):
     var prc = c.generics.generics[i].instSym
     if prc.kind in {skProc, skMethod, skConverter} and prc.magic == mNone: 
-      if prc.ast == nil or prc.ast.sons[codePos] == nil: 
+      if prc.ast == nil or prc.ast.sons[bodyPos] == nil: 
         InternalError(prc.info, "no code for " & prc.name.s)
       addSon(n, prc.ast)
   c.generics.lastGenericIdx = Len(c.generics.generics)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index d8f16e559..3d6be4f13 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -243,7 +243,7 @@ proc semGenericStmt(c: PContext, n: PNode,
         addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
   of nkProcDef, nkMethodDef, nkConverterDef, nkMacroDef, nkTemplateDef, 
      nkIteratorDef, nkLambda: 
-    checkSonsLen(n, codePos + 1)
+    checkSonsLen(n, bodyPos + 1)
     addDecl(c, newSymS(skUnknown, getIdentNode(n.sons[0]), c))
     openScope(c.tab)
     n.sons[genericParamsPos] = semGenericStmt(c, n.sons[genericParamsPos], 
@@ -253,7 +253,8 @@ proc semGenericStmt(c: PContext, n: PNode,
         addDecl(c, newSym(skUnknown, getIdent("result"), nil))
       n.sons[paramsPos] = semGenericStmt(c, n.sons[paramsPos], flags, toBind)
     n.sons[pragmasPos] = semGenericStmt(c, n.sons[pragmasPos], flags, toBind)
-    n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], flags, toBind)
+    var s = n.sons[namePos].sym
+    n.sons[bodyPos] = semGenericStmtScope(c, s.getBody, flags, toBind)
     closeScope(c.tab)
   else: 
     for i in countup(0, sonsLen(n) - 1): 
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index f66a90ecf..130e00134 100755
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -70,17 +70,17 @@ proc removeDefaultParamValues(n: PNode) =
         a.sons[L-1] = ast.emptyNode
 
 proc instantiateBody(c: PContext, n: PNode, result: PSym) =
-  if n.sons[codePos].kind != nkEmpty:
+  if n.sons[bodyPos].kind != nkEmpty:
     # add it here, so that recursive generic procs are possible:
     addDecl(c, result)
     pushProcCon(c, result)
     if result.kind in {skProc, skMethod, skConverter}: 
       addResult(c, result.typ.sons[0], n.info)
       addResultNode(c, n)
-    n.sons[codePos] = semStmtScope(c, n.sons[codePos])
+    n.sons[bodyPos] = semStmtScope(c, n.sons[bodyPos])
     if result.kind == skIterator:
       # XXX Bad hack for tests/titer2:
-      n.sons[codePos] = transform(c.module, n.sons[codePos])
+      n.sons[bodyPos] = transform(c.module, n.sons[bodyPos])
     #echo "code instantiated ", result.name.s
     excl(result.flags, sfForward)
     popProcCon(c)
@@ -92,7 +92,7 @@ proc fixupInstantiatedSymbols(c: PContext, s: PSym) =
       pushInfoContext(oldPrc.info)
       openScope(c.tab)
       var n = oldPrc.ast
-      n.sons[codePos] = copyTree(s.ast.sons[codePos])
+      n.sons[bodyPos] = copyTree(s.getBody)
       if n.sons[paramsPos].kind != nkEmpty: addParams(c, oldPrc.typ.n)
       instantiateBody(c, n, oldPrc)
       closeScope(c.tab)
@@ -118,6 +118,7 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   result = copySym(fn, false)
   incl(result.flags, sfFromGeneric)
   result.owner = getCurrOwner().owner
+  # careful! we copy the whole AST including the possibly nil body!
   var n = copyTree(fn.ast)
   result.ast = n
   pushOwner(result)
@@ -146,6 +147,8 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     c.generics.generics.add(entry)
     if n.sons[pragmasPos].kind != nkEmpty:
       pragma(c, result, n.sons[pragmasPos], allRoutinePragmas)
+    if isNil(n.sons[bodyPos]):
+      n.sons[bodyPos] = copyTree(fn.getBody)
     instantiateBody(c, n, result)
     sideEffectsCheck(c, result)
   else:
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index d6ccad5a4..444f55883 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -576,7 +576,7 @@ proc semBorrow(c: PContext, n: PNode, s: PSym) =
   var b = SearchForBorrowProc(c, s, c.tab.tos - 2)
   if b != nil: 
     # store the alias:
-    n.sons[codePos] = newSymNode(b)
+    n.sons[bodyPos] = newSymNode(b)
   else:
     LocalError(n.info, errNoSymbolToBorrowFromFound) 
   
@@ -594,7 +594,7 @@ proc addResultNode(c: PContext, n: PNode) =
   
 proc semLambda(c: PContext, n: PNode): PNode = 
   result = n
-  checkSonsLen(n, codePos + 1)
+  checkSonsLen(n, bodyPos + 1)
   var s = newSym(skProc, getIdent":anonymous", getCurrOwner())
   s.info = n.info
   s.ast = n
@@ -615,12 +615,12 @@ proc semLambda(c: PContext, n: PNode): PNode =
   if n.sons[pragmasPos].kind != nkEmpty:
     pragma(c, s, n.sons[pragmasPos], lambdaPragmas)
   s.options = gOptions
-  if n.sons[codePos].kind != nkEmpty: 
+  if n.sons[bodyPos].kind != nkEmpty: 
     if sfImportc in s.flags: 
-      LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
+      LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
     pushProcCon(c, s)
     addResult(c, s.typ.sons[0], n.info)
-    n.sons[codePos] = semStmtScope(c, n.sons[codePos])
+    n.sons[bodyPos] = semStmtScope(c, n.sons[bodyPos])
     addResultNode(c, n)
     popProcCon(c)
   else: 
@@ -633,7 +633,7 @@ proc semLambda(c: PContext, n: PNode): PNode =
 proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 
                 validPragmas: TSpecialWords): PNode = 
   result = n
-  checkSonsLen(n, codePos + 1)
+  checkSonsLen(n, bodyPos + 1)
   var s = semIdentDef(c, n.sons[0], kind)
   n.sons[namePos] = newSymNode(s)
   s.ast = n
@@ -695,10 +695,10 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     popOwner()
     pushOwner(s)
   s.options = gOptions
-  if n.sons[codePos].kind != nkEmpty: 
+  if n.sons[bodyPos].kind != nkEmpty: 
     # for DLL generation it is annoying to check for sfImportc!
     if sfBorrow in s.flags: 
-      LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
+      LocalError(n.sons[bodyPos].info, errImplOfXNotAllowed, s.name.s)
     if n.sons[genericParamsPos].kind == nkEmpty: 
       ParamsTypeCheck(c, s.typ)
       pushProcCon(c, s)
@@ -706,18 +706,18 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
         addResult(c, s.typ.sons[0], n.info)
       if sfImportc notin s.flags: 
         # no semantic checking for importc:
-        n.sons[codePos] = semStmtScope(c, n.sons[codePos])
+        n.sons[bodyPos] = semStmtScope(c, n.sons[bodyPos])
       if s.typ.sons[0] != nil and kind != skIterator: addResultNode(c, n)
       popProcCon(c)
     else: 
       if s.typ.sons[0] != nil and kind != skIterator:
         addDecl(c, newSym(skUnknown, getIdent"result", nil))
       var toBind = initIntSet()
-      n.sons[codePos] = semGenericStmtScope(c, n.sons[codePos], {}, toBind)
+      n.sons[bodyPos] = semGenericStmtScope(c, n.sons[bodyPos], {}, toBind)
       fixupInstantiatedSymbols(c, s)
     if sfImportc in s.flags: 
       # so we just ignore the body after semantic checking for importc:
-      n.sons[codePos] = ast.emptyNode
+      n.sons[bodyPos] = ast.emptyNode
   else: 
     if proto != nil: LocalError(n.info, errImplOfXexpected, proto.name.s)
     if {sfImportc, sfBorrow} * s.flags == {}: incl(s.flags, sfForward)
@@ -732,7 +732,7 @@ proc semIterator(c: PContext, n: PNode): PNode =
   var t = s.typ
   if t.sons[0] == nil: 
     LocalError(n.info, errXNeedsReturnType, "iterator")
-  if n.sons[codePos].kind == nkEmpty and s.magic == mNone: 
+  if n.sons[bodyPos].kind == nkEmpty and s.magic == mNone: 
     LocalError(n.info, errImplOfXexpected, s.name.s)
   
 proc semProc(c: PContext, n: PNode): PNode = 
@@ -758,7 +758,7 @@ proc semMethod(c: PContext, n: PNode): PNode =
 
 proc semConverterDef(c: PContext, n: PNode): PNode = 
   if not isTopLevel(c): LocalError(n.info, errXOnlyAtModuleScope, "converter")
-  checkSonsLen(n, codePos + 1)
+  checkSonsLen(n, bodyPos + 1)
   if n.sons[genericParamsPos].kind != nkEmpty: 
     LocalError(n.info, errNoGenericParamsAllowedForX, "converter")
   result = semProcAux(c, n, skConverter, converterPragmas)
@@ -769,7 +769,7 @@ proc semConverterDef(c: PContext, n: PNode): PNode =
   addConverter(c, s)
 
 proc semMacroDef(c: PContext, n: PNode): PNode = 
-  checkSonsLen(n, codePos + 1)
+  checkSonsLen(n, bodyPos + 1)
   if n.sons[genericParamsPos].kind != nkEmpty: 
     LocalError(n.info, errNoGenericParamsAllowedForX, "macro")
   result = semProcAux(c, n, skMacro, macroPragmas)
@@ -777,7 +777,7 @@ proc semMacroDef(c: PContext, n: PNode): PNode =
   var t = s.typ
   if t.sons[0] == nil: LocalError(n.info, errXNeedsReturnType, "macro")
   if sonsLen(t) != 2: LocalError(n.info, errXRequiresOneArgument, "macro")
-  if n.sons[codePos].kind == nkEmpty:
+  if n.sons[bodyPos].kind == nkEmpty:
     LocalError(n.info, errImplOfXexpected, s.name.s)
   
 proc evalInclude(c: PContext, n: PNode): PNode = 
diff --git a/compiler/semtempl.nim b/compiler/semtempl.nim
index 24395073d..80d6036c6 100755
--- a/compiler/semtempl.nim
+++ b/compiler/semtempl.nim
@@ -67,7 +67,7 @@ proc evalTemplate*(c: PContext, n: PNode, sym: PSym): PNode =
   if evalTemplateCounter <= 100: 
     # replace each param by the corresponding node:
     args = evalTemplateArgs(c, n, sym)
-    result = evalTemplateAux(sym.ast.sons[codePos], args, sym)
+    result = evalTemplateAux(sym.getBody, args, sym)
     dec(evalTemplateCounter)
   else:
     GlobalError(n.info, errTemplateInstantiationTooNested)
@@ -186,15 +186,15 @@ proc semTemplateDef(c: PContext, n: PNode): PNode =
       s.typ.n.sons[0] = newNodeIT(nkType, n.info, s.typ.sons[0])
   addParams(c, s.typ.n)       # resolve parameters:
   var toBind = initIntSet()
-  n.sons[codePos] = resolveTemplateParams(c, n.sons[codePos], false, toBind)
-  if not (s.typ.sons[0].kind in {tyStmt, tyTypeDesc}): 
-    n.sons[codePos] = transformToExpr(n.sons[codePos]) 
+  n.sons[bodyPos] = resolveTemplateParams(c, n.sons[bodyPos], false, toBind)
+  if s.typ.sons[0].kind notin {tyStmt, tyTypeDesc}:
+    n.sons[bodyPos] = transformToExpr(n.sons[bodyPos]) 
     # only parameters are resolved, no type checking is performed
   closeScope(c.tab)
   popOwner()
   s.ast = n
   result = n
-  if n.sons[codePos].kind == nkEmpty: 
+  if n.sons[bodyPos].kind == nkEmpty: 
     LocalError(n.info, errImplOfXexpected, s.name.s)
   # add identifier of template as a last step to not allow recursive templates:
   addInterfaceDecl(c, s)
diff --git a/compiler/semthreads.nim b/compiler/semthreads.nim
index 16c9f2738..dcb38ff90 100755
--- a/compiler/semthreads.nim
+++ b/compiler/semthreads.nim
@@ -59,7 +59,7 @@
 
 import
   ast, astalgo, strutils, hashes, options, msgs, idents, types, os,
-  renderer, tables
+  renderer, tables, rodread
 
 type
   TThreadOwner = enum
@@ -188,8 +188,8 @@ proc analyseCall(c: PProcCtx, n: PNode): TThreadOwner =
       var formal = skipTypes(prc.typ, abstractInst).n.sons[i].sym 
       newCtx.mapping[formal.id] = call.args[i-1]
     pushInfoContext(n.info)
-    result = analyse(newCtx, prc.ast.sons[codePos])
-    if prc.ast.sons[codePos].kind == nkEmpty and 
+    result = analyse(newCtx, prc.getBody)
+    if prc.ast.sons[bodyPos].kind == nkEmpty and 
        {sfNoSideEffect, sfThread, sfImportc} * prc.flags == {}:
       Message(n.info, warnAnalysisLoophole, renderTree(n))
       if result == toUndefined: result = toNil
@@ -372,7 +372,7 @@ proc analyseThreadProc*(prc: PSym) =
   for i in 1 .. formals.len-1:
     var formal = formals.sons[i].sym 
     c.mapping[formal.id] = toTheirs # thread receives foreign data!
-  discard analyse(c, prc.ast.sons[codePos])
+  discard analyse(c, prc.getBody)
 
 proc needsGlobalAnalysis*: bool =
   result = gGlobalOptions * {optThreads, optThreadAnalysis} == 
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 81c25ecb2..c6b48454c 100755
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -164,7 +164,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
   var tc = c.transCon
   if sfBorrow in n.sym.flags: 
     # simply exchange the symbol:
-    b = n.sym.ast.sons[codePos]
+    b = n.sym.getBody
     if b.kind != nkSym: internalError(n.info, "wrong AST for borrowed symbol")
     b = newSymNode(b.sym)
     b.info = n.info
@@ -493,7 +493,7 @@ proc transformFor(c: PTransf, n: PNode): PTransNode =
       assert(skipTypes(formal.typ, abstractInst).kind == tyVar)
       IdNodeTablePut(newC.mapping, formal, arg)
       # XXX BUG still not correct if the arg has a side effect!
-  var body = newC.owner.ast.sons[codePos]
+  var body = newC.owner.getBody
   pushInfoContext(n.info)
   inc(c.inlining)
   add(result, transform(c, body))
@@ -551,8 +551,9 @@ proc transformLambda(c: PTransf, n: PNode): PNode =
   result = n
   if n.sons[namePos].kind != nkSym: InternalError(n.info, "transformLambda")
   var s = n.sons[namePos].sym
-  var closure = newNodeI(nkRecList, n.sons[codePos].info)
-  gatherVars(c, n.sons[codePos], marked, s, closure) 
+  var closure = newNodeI(nkRecList, n.info)
+  var body = s.getBody
+  gatherVars(c, body, marked, s, closure) 
   # add closure type to the param list (even if closure is empty!):
   var cl = newType(tyObject, s)
   cl.n = closure
@@ -570,7 +571,7 @@ proc transformLambda(c: PTransf, n: PNode): PNode =
       IdNodeTablePut(newC.mapping, closure.sons[i].sym, 
                      indirectAccess(param, closure.sons[i].sym))
     pushTransCon(c, newC)
-    n.sons[codePos] = transform(c, n.sons[codePos]).pnode
+    n.sons[bodyPos] = transform(c, body).pnode
     popTransCon(c)
 
 proc transformCase(c: PTransf, n: PNode): PTransNode = 
@@ -666,7 +667,8 @@ proc transform(c: PTransf, n: PNode): PTransNode =
   of nkBracketExpr: 
     result = transformArrayAccess(c, n)
   of nkLambda: 
-    n.sons[codePos] = PNode(transform(c, n.sons[codePos]))
+    var s = n.sons[namePos].sym
+    n.sons[bodyPos] = PNode(transform(c, s.getBody))
     result = PTransNode(n)
     when false: result = transformLambda(c, n)
   of nkForStmt: 
@@ -675,8 +677,9 @@ proc transform(c: PTransf, n: PNode): PTransNode =
     result = transformCase(c, n)
   of nkProcDef, nkMethodDef, nkIteratorDef, nkMacroDef, nkConverterDef: 
     if n.sons[genericParamsPos].kind == nkEmpty: 
-      n.sons[codePos] = PNode(transform(c, n.sons[codePos]))
-      if n.kind == nkMethodDef: methodDef(n.sons[namePos].sym, false)
+      var s = n.sons[namePos].sym
+      n.sons[bodyPos] = PNode(transform(c, s.getBody))
+      if n.kind == nkMethodDef: methodDef(s, false)
     result = PTransNode(n)
   of nkContinueStmt:
     result = PTransNode(newNode(nkBreakStmt))
diff --git a/tests/tester.nim b/tests/tester.nim
index f0e48c4e6..5d596bc55 100755
--- a/tests/tester.nim
+++ b/tests/tester.nim
@@ -272,42 +272,53 @@ proc run(r: var TResults, dir, options: string) =
 const
   rodfilesDir = "tests/rodfiles"
 
-proc delNimCache() = removeDir(rodfilesDir / "nimcache")
+proc delNimCache() =
+  try:
+    removeDir(rodfilesDir / "nimcache")
+  except EOS:
+    nil
+    
 proc plusCache(options: string): string = return options & " --symbolFiles:on"
 
 proc runRodFiles(r: var TResults, options: string) =
+  template test(filename: expr): stmt =
+    runSingleTest(r, rodfilesDir / filename, options)
+  
   var options = options.plusCache
   delNimCache()
   
   # test basic recompilation scheme:
-  runSingleTest(r, rodfilesDir / "hallo", options)
-  runSingleTest(r, rodfilesDir / "hallo", options)
+  test "hallo"
+  test "hallo"
   # test incremental type information:
-  runSingleTest(r, rodfilesDir / "hallo2", options)
+  test "hallo2"
   delNimCache()
   
   # test type converters:
-  runSingleTest(r, rodfilesDir / "aconv", options)
-  runSingleTest(r, rodfilesDir / "bconv", options)
+  test "aconv"
+  test "bconv"
   delNimCache()
   
   # test G, A, B example from the documentation; test init sections:
-  runSingleTest(r, rodfilesDir / "deada", options)
-  runSingleTest(r, rodfilesDir / "deada2", options)
+  test "deada"
+  test "deada2"
   delNimCache()
   
   # test method generation:
-  runSingleTest(r, rodfilesDir / "bmethods", options)
-  runSingleTest(r, rodfilesDir / "bmethods2", options)
+  test "bmethods"
+  test "bmethods2"
   delNimCache()
   
 
 proc compileRodFiles(r: var TResults, options: string) =
+  template test(filename: expr): stmt =
+    compileSingleTest(r, rodfilesDir / filename, options)
+    
   var options = options.plusCache
   delNimCache()
   # test DLL interfacing:
-  compileSingleTest(r, rodfilesDir / "gtkex1", options)
-  compileSingleTest(r, rodfilesDir / "gtkex2", options)
+  test "gtkex1"
+  test "gtkex2"
   delNimCache()
 
 # -----------------------------------------------------------------------------
diff --git a/todo.txt b/todo.txt
index 7f24b99a8..c62ebea85 100755
--- a/todo.txt
+++ b/todo.txt
@@ -4,13 +4,6 @@ Version 0.8.14
 - optimize unused constants away (affected by HLO)
 - fix actors.nim; test with different thread var implementations
 - dead code elim for JS backend
-
-
-incremental compilation
------------------------
-
-- the loading has to be MUCH lazier! --> next version: We should re-load
-  symbol.ast.sons[codePos] lazily
 - implement lib/pure/memfiles properly
 
 
@@ -38,6 +31,8 @@ version 0.9.0
 
 Bugs
 ----
+- bug: s[1..n] = @[] produces wrong C code
+- bug: template t(f_no_Type): stmt = ... crashes the compiler
 - bug: generic assign still buggy
   - Optimization: If we use a temporary for the result anyway the code gen
     should make use of this fact to generate better code...
@@ -54,6 +49,7 @@ Bugs
 - bug: stress testing basic method example (eval example) 
   without ``-d:release`` leaks memory; good way to figure out how a 
   fixed amount of stack can hold an arbitrary number of GC roots!
+- bug: osproc.execProcess() should raise an exception if the exit code is not 0
 
 
 version 0.9.XX