summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xkoch.nim2
-rwxr-xr-xlib/pure/hashes.nim38
-rwxr-xr-xlib/pure/htmlparser.nim4
-rwxr-xr-xlib/system.nim27
-rwxr-xr-xlib/system/gc.nim5
-rwxr-xr-xrod/astalgo.nim119
-rwxr-xr-xrod/lookups.nim58
-rwxr-xr-xrod/sem.nim20
-rwxr-xr-xrod/semdata.nim15
-rwxr-xr-xrod/semgnrc.nim45
-rwxr-xr-xrod/seminst.nim9
-rwxr-xr-xrod/semstmts.nim54
-rwxr-xr-xrod/semtypes.nim2
-rw-r--r--tests/accept/run/tkoeniglookup.nim4
-rwxr-xr-xtests/reject/ttypenoval.nim2
-rwxr-xr-xtodo.txt2
-rwxr-xr-xweb/news.txt3
17 files changed, 217 insertions, 192 deletions
diff --git a/koch.nim b/koch.nim
index 4eddb06e4..0f9b42bec 100755
--- a/koch.nim
+++ b/koch.nim
@@ -180,7 +180,7 @@ proc cleanAux(dir: string) =
       of "nimcache": 
         echo "removing dir: ", path
         removeDir(path)
-      of "dist", ".bzr":
+      of "dist", ".git":
         nil
       else:
         cleanAux(path)
diff --git a/lib/pure/hashes.nim b/lib/pure/hashes.nim
index 1593119bd..87d672ae7 100755
--- a/lib/pure/hashes.nim
+++ b/lib/pure/hashes.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -30,14 +30,10 @@ proc finishHash(h: THash): THash {.inline.} =
 
 proc hashData*(Data: Pointer, Size: int): THash = 
   ## hashes an array of bytes of size `size`
-  var 
-    h: THash
-    p: cstring
-    i, s: int
-  h = 0
-  p = cast[cstring](Data)
-  i = 0
-  s = size
+  var h: THash = 0
+  var p = cast[cstring](Data)
+  var i = 0
+  var s = size
   while s > 0: 
     h = concHash(h, ord(p[i]))
     Inc(i)
@@ -62,20 +58,16 @@ proc hash*(x: char): THash {.inline.} =
 
 proc hash*(x: string): THash = 
   ## efficient hashing of strings
-  var h: THash
-  h = 0
+  var h: THash = 0
   for i in 0..x.len-1: 
     h = concHash(h, ord(x[i]))
   result = finishHash(h)
   
 proc hashIgnoreStyle*(x: string): THash = 
   ## efficient hashing of strings; style is ignored
-  var 
-    h: THash
-    c: Char
-  h = 0
+  var h: THash = 0
   for i in 0..x.len-1: 
-    c = x[i]
+    var c = x[i]
     if c == '_': 
       continue                # skip _
     if c in {'A'..'Z'}: 
@@ -85,13 +77,17 @@ proc hashIgnoreStyle*(x: string): THash =
 
 proc hashIgnoreCase*(x: string): THash = 
   ## efficient hashing of strings; case is ignored
-  var 
-    h: THash
-    c: Char
-  h = 0
+  var h: THash = 0
   for i in 0..x.len-1: 
-    c = x[i]
+    var c = x[i]
     if c in {'A'..'Z'}: 
       c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
     h = concHash(h, ord(c))
   result = finishHash(h)
+  
+proc hash*[T: tuple](x: T): THash = 
+  ## efficient hashing of tuples.
+  for f in fields(x):
+    result = concHash(result, hash(f))
+  result = finishHash(result)
+
diff --git a/lib/pure/htmlparser.nim b/lib/pure/htmlparser.nim
index d84688be6..4136ecf57 100755
--- a/lib/pure/htmlparser.nim
+++ b/lib/pure/htmlparser.nim
@@ -333,11 +333,11 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
   of xmlElementOpen: 
     result = newElement(x.elementName.toLower)
     next(x)
-    result.attr = newStringTable()
+    result.attrs = newStringTable()
     while true: 
       case x.kind
       of xmlAttribute:
-        result.attr[x.attrKey] = x.attrValue
+        result.attrs[x.attrKey] = x.attrValue
         next(x)
       of xmlElementClose:
         next(x)
diff --git a/lib/system.nim b/lib/system.nim
index daf0c5423..c786e8355 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1213,14 +1213,14 @@ iterator fieldPairs*(x, y: tuple[]): tuple[a, b: expr] {.
   ## in the loop body.
 
 proc `==`*[T: tuple](x, y: T): bool = 
-  ## generic ``==`` operator that is lifted from the components
+  ## generic ``==`` operator for tuples that is lifted from the components
   ## of `x` and `y`.
   for a, b in fields(x, y):
     if a != b: return false
   return true
 
 proc `<=`*[T: tuple](x, y: T): bool = 
-  ## generic ``<=`` operator that is lifted from the components
+  ## generic ``<=`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
     var c = cmp(a, b)
@@ -1229,7 +1229,7 @@ proc `<=`*[T: tuple](x, y: T): bool =
   return true
 
 proc `<`*[T: tuple](x, y: T): bool = 
-  ## generic ``<`` operator that is lifted from the components
+  ## generic ``<`` operator for tuples that is lifted from the components
   ## of `x` and `y`. This implementation uses `cmp`.
   for a, b in fields(x, y):
     var c = cmp(a, b)
@@ -1238,7 +1238,8 @@ proc `<`*[T: tuple](x, y: T): bool =
   return false
 
 proc `$`*[T: tuple](x: T): string = 
-  ## generic ``$`` operator that is lifted from the components of `x`.
+  ## generic ``$`` operator for tuples that is lifted from the components
+  ## of `x`.
   result = "("
   for name, value in fieldPairs(x):
     if result.len > 1: result.add(", ")
@@ -1476,15 +1477,22 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     ## Opens a file named `filename` with given `mode`.
     ##
     ## Default mode is readonly. Returns true iff the file could be opened.
-    ## This throws no exception if the file could not be opened. The reason is
-    ## that the programmer needs to provide an appropriate error message 
-    ## anyway.
+    ## This throws no exception if the file could not be opened.
 
   proc Open*(f: var TFile, filehandle: TFileHandle,
              mode: TFileMode = fmRead): Bool
     ## Creates a ``TFile`` from a `filehandle` with given `mode`.
     ##
     ## Default mode is readonly. Returns true iff the file could be opened.
+    
+  proc Open*(filename: string,
+             mode: TFileMode = fmRead, bufSize: int = -1): TFile = 
+    ## Opens a file named `filename` with given `mode`.
+    ##
+    ## Default mode is readonly. Raises an ``IO`` exception if the file
+    ## could not be opened.
+    if not open(result, filename, mode, bufSize):
+      raise newException(EIO, "cannot open: " & filename)
 
   proc reopen*(f: TFile, filename: string, mode: TFileMode = fmRead): bool
     ## reopens the file `f` with given `filename` and `mode`. This 
@@ -1581,10 +1589,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
   iterator lines*(filename: string): string =
     ## Iterate over any line in the file named `filename`.
     ## If the file does not exist `EIO` is raised.
-    var
-      f: TFile
-    if not open(f, filename):
-      raise newException(EIO, "cannot open: " & filename)
+    var f = open(filename)
     var res = ""
     while not endOfFile(f):
       rawReadLine(f, res)
diff --git a/lib/system/gc.nim b/lib/system/gc.nim
index 5288316f2..882825f5e 100755
--- a/lib/system/gc.nim
+++ b/lib/system/gc.nim
@@ -265,7 +265,10 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
   # reference is in the stack or not (this can happen for var parameters).
   if not IsOnStack(dest):
     if src != nil: incRef(usrToCell(src))
-    if dest^ != nil: decRef(usrToCell(dest^))
+    # XXX finally use assembler for the stack checking instead!
+    # the test for '!= nil' is correct, but I got tired of the segfaults
+    # resulting from the crappy stack checking:
+    if cast[int](dest^) >=% PageSize: decRef(usrToCell(dest^))
   dest^ = src
 
 proc initGC() =
diff --git a/rod/astalgo.nim b/rod/astalgo.nim
index bb5a6cf56..2bd04618d 100755
--- a/rod/astalgo.nim
+++ b/rod/astalgo.nim
@@ -64,8 +64,8 @@ proc NextIter*(ti: var TTabIter, tab: TStrTable): PSym
   #
 
 type 
-  TIdentIter*{.final.} = object # iterator over all syms with the same identifier
-    h*: THash                 # current hash
+  TIdentIter*{.final.} = object # iterator over all syms with same identifier
+    h*: THash                   # current hash
     name*: PIdent
 
 
@@ -123,7 +123,7 @@ proc getSymFromList*(list: PNode, ident: PIdent, start: int = 0): PSym
 proc lookupInRecord*(n: PNode, field: PIdent): PSym
 proc getModule*(s: PSym): PSym
 proc mustRehash*(length, counter: int): bool
-proc nextTry*(h, maxHash: THash): THash
+proc nextTry*(h, maxHash: THash): THash {.inline.}
 
 # ------------- table[int, int] ---------------------------------------------
 const 
@@ -193,19 +193,17 @@ proc toYamlChar(c: Char): string =
   case c
   of '\0'..'\x1F', '\x80'..'\xFF': result = "\\u" & strutils.toHex(ord(c), 4)
   of '\'', '\"', '\\': result = '\\' & c
-  else: result = c & ""
+  else: result = $c
   
 proc makeYamlString*(s: string): PRope = 
   # We have to split long strings into many ropes. Otherwise
   # this could trigger InternalError(111). See the ropes module for
   # further information.
-  const 
-    MaxLineLength = 64
-  var res: string
+  const MaxLineLength = 64
   result = nil
-  res = "\""
-  for i in countup(0, len(s) + 0 - 1): 
-    if (i - 0 + 1) mod MaxLineLength == 0: 
+  var res = "\""
+  for i in countup(0, len(s) - 1): 
+    if (i + 1) mod MaxLineLength == 0: 
       add(res, '\"')
       add(res, "\n")
       app(result, toRope(res))
@@ -229,17 +227,17 @@ proc lineInfoToStr(info: TLineInfo): PRope =
                                   toRope(toLinenumber(info)), 
                                   toRope(toColumn(info))])
 
-proc treeToYamlAux(n: PNode, marker: var TIntSet, indent, maxRecDepth: int): PRope
-proc symToYamlAux(n: PSym, marker: var TIntSet, indent, maxRecDepth: int): PRope
-proc typeToYamlAux(n: PType, marker: var TIntSet, indent, maxRecDepth: int): PRope
+proc treeToYamlAux(n: PNode, marker: var TIntSet, 
+                   indent, maxRecDepth: int): PRope
+proc symToYamlAux(n: PSym, marker: var TIntSet, 
+                  indent, maxRecDepth: int): PRope
+proc typeToYamlAux(n: PType, marker: var TIntSet, 
+                   indent, maxRecDepth: int): PRope
 proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int, 
                     maxRecDepth: int): PRope = 
-  var 
-    istr: PRope
-    mycount: int
-  istr = spaces(indent + 2)
+  var istr = spaces(indent + 2)
   result = toRope("[")
-  mycount = 0
+  var mycount = 0
   for i in countup(0, high(n.data)): 
     if n.data[i] != nil: 
       if mycount > 0: app(result, ",")
@@ -252,12 +250,9 @@ proc strTableToYaml(n: TStrTable, marker: var TIntSet, indent: int,
 
 proc ropeConstr(indent: int, c: openarray[PRope]): PRope = 
   # array of (name, value) pairs
-  var 
-    istr: PRope
-    i: int
-  istr = spaces(indent + 2)
+  var istr = spaces(indent + 2)
   result = toRope("{")
-  i = 0
+  var i = 0
   while i <= high(c): 
     if i > 0: app(result, ",")
     appf(result, "$n$1\"$2\": $3", [istr, c[i], c[i + 1]])
@@ -315,13 +310,11 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int,
 
 proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, 
                    maxRecDepth: int): PRope = 
-  var istr: PRope
   if n == nil: 
     result = toRope("null")
   else: 
-    istr = spaces(indent + 2)
-    result = ropef("{$n$1\"kind\": $2", 
-                   [istr, makeYamlString($n.kind)])
+    var istr = spaces(indent + 2)
+    result = ropef("{$n$1\"kind\": $2", [istr, makeYamlString($n.kind)])
     if maxRecDepth != 0: 
       appf(result, ",$n$1\"info\": $2", [istr, lineInfoToStr(n.info)])
       case n.kind
@@ -386,11 +379,10 @@ proc debugType(n: PType): PRope =
       app(result, ")")
 
 proc debugTree(n: PNode, indent: int, maxRecDepth: int): PRope = 
-  var istr: PRope
   if n == nil: 
     result = toRope("null")
   else: 
-    istr = spaces(indent + 2)
+    var istr = spaces(indent + 2)
     result = ropef("{$n$1\"kind\": $2", 
                    [istr, makeYamlString($n.kind)])
     if maxRecDepth != 0: 
@@ -443,8 +435,7 @@ proc nextTry(h, maxHash: THash): THash =
   
 proc objectSetContains(t: TObjectSet, obj: PObject): bool = 
   # returns true whether n is in t
-  var h: THash
-  h = hashNode(obj) and high(t.data) # start with real hash value
+  var h: THash = hashNode(obj) and high(t.data) # start with real hash value
   while t.data[h] != nil: 
     if (t.data[h] == obj): 
       return true
@@ -452,8 +443,7 @@ proc objectSetContains(t: TObjectSet, obj: PObject): bool =
   result = false
 
 proc objectSetRawInsert(data: var TObjectSeq, obj: PObject) = 
-  var h: THash
-  h = HashNode(obj) and high(data)
+  var h: THash = HashNode(obj) and high(data)
   while data[h] != nil: 
     assert(data[h] != obj)
     h = nextTry(h, high(data))
@@ -474,12 +464,9 @@ proc objectSetIncl(t: var TObjectSet, obj: PObject) =
 
 proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool = 
   # returns true if obj is already in the string table:
-  var 
-    h: THash
-    it: PObject
-  h = HashNode(obj) and high(t.data)
+  var h: THash = HashNode(obj) and high(t.data)
   while true: 
-    it = t.data[h]
+    var it = t.data[h]
     if it == nil: break 
     if it == obj: 
       return true             # found it
@@ -494,20 +481,18 @@ proc objectSetContainsOrIncl(t: var TObjectSet, obj: PObject): bool =
   result = false
 
 proc TableRawGet(t: TTable, key: PObject): int = 
-  var h: THash
-  h = hashNode(key) and high(t.data) # start with real hash value
+  var h: THash = hashNode(key) and high(t.data) # start with real hash value
   while t.data[h].key != nil: 
-    if (t.data[h].key == key): 
+    if t.data[h].key == key: 
       return h
     h = nextTry(h, high(t.data))
-  result = - 1
+  result = -1
 
 proc TableSearch(t: TTable, key, closure: PObject, 
                  comparator: TCmpProc): PObject = 
-  var h: THash
-  h = hashNode(key) and high(t.data) # start with real hash value
+  var h: THash = hashNode(key) and high(t.data) # start with real hash value
   while t.data[h].key != nil: 
-    if (t.data[h].key == key): 
+    if t.data[h].key == key: 
       if comparator(t.data[h].val, closure): 
         # BUGFIX 1
         return t.data[h].val
@@ -520,8 +505,7 @@ proc TableGet(t: TTable, key: PObject): PObject =
   else: result = nil
   
 proc TableRawInsert(data: var TPairSeq, key, val: PObject) = 
-  var h: THash
-  h = HashNode(key) and high(data)
+  var h: THash = HashNode(key) and high(data)
   while data[h].key != nil: 
     assert(data[h].key != key)
     h = nextTry(h, high(data))
@@ -546,8 +530,7 @@ proc TablePut(t: var TTable, key, val: PObject) =
     inc(t.counter)
 
 proc StrTableContains(t: TStrTable, n: PSym): bool = 
-  var h: THash
-  h = n.name.h and high(t.data) # start with real hash value
+  var h: THash = n.name.h and high(t.data) # start with real hash value
   while t.data[h] != nil: 
     if (t.data[h] == n): 
       return true
@@ -555,8 +538,7 @@ proc StrTableContains(t: TStrTable, n: PSym): bool =
   result = false
 
 proc StrTableRawInsert(data: var TSymSeq, n: PSym) = 
-  var h: THash
-  h = n.name.h and high(data)
+  var h: THash = n.name.h and high(data)
   while data[h] != nil: 
     if data[h] == n: InternalError(n.info, "StrTableRawInsert: " & n.name.s)
     h = nextTry(h, high(data))
@@ -579,12 +561,9 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool =
   # returns true if n is already in the string table:
   # It is essential that `n` is written nevertheless!
   # This way the newest redefinition is picked by the semantic analyses!
-  var 
-    h: THash
-    it: PSym
-  h = n.name.h and high(t.data)
+  var h: THash = n.name.h and high(t.data)
   while true: 
-    it = t.data[h]
+    var it = t.data[h]
     if it == nil: break 
     if it.name.id == n.name.id: 
       t.data[h] = n           # overwrite it with newer definition!
@@ -600,8 +579,7 @@ proc StrTableIncl*(t: var TStrTable, n: PSym): bool =
   result = false
 
 proc StrTableGet(t: TStrTable, name: PIdent): PSym = 
-  var h: THash
-  h = name.h and high(t.data)
+  var h: THash = name.h and high(t.data)
   while true: 
     result = t.data[h]
     if result == nil: break 
@@ -619,7 +597,7 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
   h = ti.h and high(tab.data)
   start = h
   result = tab.data[h]
-  while (result != nil): 
+  while result != nil: 
     if result.Name.id == ti.name.id: break 
     h = nextTry(h, high(tab.data))
     if h == start: 
@@ -627,6 +605,29 @@ proc NextIdentIter(ti: var TIdentIter, tab: TStrTable): PSym =
       break 
     result = tab.data[h]
   ti.h = nextTry(h, high(tab.data))
+  
+proc NextIdentExcluding*(ti: var TIdentIter, tab: TStrTable, 
+                         excluding: TIntSet): PSym =
+  var h: THash = ti.h and high(tab.data)
+  var start = h
+  result = tab.data[h]
+  while result != nil: 
+    if result.Name.id == ti.name.id and 
+        not IntSetContains(excluding, result.id): break
+    h = nextTry(h, high(tab.data))
+    if h == start: 
+      result = nil
+      break 
+    result = tab.data[h]
+  ti.h = nextTry(h, high(tab.data))
+  if result != nil and IntSetContains(excluding, result.id): result = nil
+
+proc FirstIdentExcluding*(ti: var TIdentIter, tab: TStrTable, s: PIdent,
+                          excluding: TIntSet): PSym = 
+  ti.h = s.h
+  ti.name = s
+  if tab.Counter == 0: result = nil
+  else: result = NextIdentExcluding(ti, tab, excluding)
 
 proc InitTabIter(ti: var TTabIter, tab: TStrTable): PSym = 
   ti.h = 0                    # we start by zero ...
diff --git a/rod/lookups.nim b/rod/lookups.nim
index 160f9635b..f65fe24b7 100755
--- a/rod/lookups.nim
+++ b/rod/lookups.nim
@@ -14,12 +14,14 @@ import
 
 type 
   TOverloadIterMode* = enum 
-    oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice
+    oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice,
+    oimSymChoiceLocalLookup
   TOverloadIter*{.final.} = object 
     stackPtr*: int
     it*: TIdentIter
     m*: PSym
     mode*: TOverloadIterMode
+    inSymChoice: TIntSet
 
 proc getSymRepr*(s: PSym): string = 
   case s.kind
@@ -27,12 +29,10 @@ proc getSymRepr*(s: PSym): string =
   else: result = s.name.s
   
 proc CloseScope*(tab: var TSymTab) = 
-  var 
-    it: TTabIter
-    s: PSym
   # check if all symbols have been used and defined:
   if (tab.tos > len(tab.stack)): InternalError("CloseScope")
-  s = InitTabIter(it, tab.stack[tab.tos - 1])
+  var it: TTabIter
+  var s = InitTabIter(it, tab.stack[tab.tos-1])
   while s != nil: 
     if sfForward in s.flags: 
       LocalError(s.info, errImplOfXexpected, getSymRepr(s))
@@ -40,7 +40,7 @@ proc CloseScope*(tab: var TSymTab) =
         (optHints in s.options): # BUGFIX: check options in s!
       if not (s.kind in {skForVar, skParam, skMethod, skUnknown}): 
         Message(s.info, hintXDeclaredButNotUsed, getSymRepr(s))
-    s = NextIter(it, tab.stack[tab.tos - 1])
+    s = NextIter(it, tab.stack[tab.tos-1])
   astalgo.rawCloseScope(tab)
 
 proc AddSym*(t: var TStrTable, n: PSym) = 
@@ -144,12 +144,11 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
   if (result != nil) and (result.kind == skStub): loadStub(result)
   
 proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = 
-  result = nil
   case n.kind
   of nkIdent: 
     o.stackPtr = c.tab.tos
     o.mode = oimNoQualifier
-    while (result == nil): 
+    while result == nil: 
       dec(o.stackPtr)
       if o.stackPtr < 0: break 
       result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], n.ident)
@@ -159,12 +158,12 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   of nkDotExpr: 
     o.mode = oimOtherModule
     o.m = qualifiedLookUp(c, n.sons[0])
-    if (o.m != nil) and (o.m.kind == skModule): 
+    if o.m != nil and o.m.kind == skModule:
       var ident: PIdent = nil
-      if (n.sons[1].kind == nkIdent): 
+      if n.sons[1].kind == nkIdent: 
         ident = n.sons[1].ident
-      elif (n.sons[1].kind == nkAccQuoted) and
-          (n.sons[1].sons[0].kind == nkIdent): 
+      elif n.sons[1].kind == nkAccQuoted and
+          n.sons[1].sons[0].kind == nkIdent: 
         ident = n.sons[1].sons[0].ident
       if ident != nil: 
         if o.m == c.module: 
@@ -182,9 +181,10 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
     o.mode = oimSymChoice
     result = n.sons[0].sym
     o.stackPtr = 1
-  else: 
-    nil
-  if (result != nil) and (result.kind == skStub): loadStub(result)
+    IntSetInit(o.inSymChoice)
+    IntSetIncl(o.inSymChoice, result.id)
+  else: nil
+  if result != nil and result.kind == skStub: loadStub(result)
   
 proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = 
   case o.mode
@@ -192,10 +192,10 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
     result = nil
   of oimNoQualifier: 
     if n.kind == nkAccQuoted: 
-      result = nextOverloadIter(o, c, n.sons[0]) # BUGFIX
+      result = nextOverloadIter(o, c, n.sons[0])
     elif o.stackPtr >= 0: 
       result = nextIdentIter(o.it, c.tab.stack[o.stackPtr])
-      while (result == nil): 
+      while result == nil: 
         dec(o.stackPtr)
         if o.stackPtr < 0: break 
         result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], o.it.name) 
@@ -209,8 +209,26 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   of oimSymChoice: 
     if o.stackPtr < sonsLen(n): 
       result = n.sons[o.stackPtr].sym
+      IntSetIncl(o.inSymChoice, result.id)
       inc(o.stackPtr)
-    else: 
-      result = nil
-  if (result != nil) and (result.kind == skStub): loadStub(result)
+    else:
+      # try 'local' symbols too for Koenig's lookup:
+      o.mode = oimSymChoiceLocalLookup
+      o.stackPtr = c.tab.tos-1
+      result = FirstIdentExcluding(o.it, c.tab.stack[o.stackPtr], 
+                                   n.sons[0].sym.name, o.inSymChoice)
+      while result == nil:
+        dec(o.stackPtr)
+        if o.stackPtr < 0: break 
+        result = FirstIdentExcluding(o.it, c.tab.stack[o.stackPtr], 
+                                     n.sons[0].sym.name, o.inSymChoice)
+  of oimSymChoiceLocalLookup:
+    result = nextIdentExcluding(o.it, c.tab.stack[o.stackPtr], o.inSymChoice)
+    while result == nil:
+      dec(o.stackPtr)
+      if o.stackPtr < 0: break 
+      result = FirstIdentExcluding(o.it, c.tab.stack[o.stackPtr], 
+                                   n.sons[0].sym.name, o.inSymChoice)
+  
+  if result != nil and result.kind == skStub: loadStub(result)
   
diff --git a/rod/sem.nim b/rod/sem.nim
index 1ede5f7f8..bb948ffc9 100755
--- a/rod/sem.nim
+++ b/rod/sem.nim
@@ -29,9 +29,7 @@ proc considerAcc(n: PNode): PIdent =
     result = nil
 
 proc isTopLevel(c: PContext): bool {.inline.} = 
-  # if we encountered an error, we treat as top-level so that
-  # cascading errors are not that strange:
-  result = c.tab.tos <= 2 or msgs.gErrorCounter > 0
+  result = c.tab.tos <= 2
 
 proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym = 
   result = newSym(kind, considerAcc(n), getCurrOwner())
@@ -166,7 +164,7 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   if (c.p != nil): InternalError(module.info, "sem.myOpen")
   c.semConstExpr = semConstExpr
   c.semExpr = semExprNoFlags
-  c.p = newProcCon(module)
+  pushProcCon(c, module)
   pushOwner(c.module)
   openScope(c.tab)            # scope for imported symbols
   SymTabAdd(c.tab, module)    # a module knows itself
@@ -179,7 +177,8 @@ proc myOpen(module: PSym, filename: string): PPassContext =
   openScope(c.tab)            # scope for the module's symbols  
   result = c
 
-proc myOpenCached(module: PSym, filename: string, rd: PRodReader): PPassContext = 
+proc myOpenCached(module: PSym, filename: string, 
+                  rd: PRodReader): PPassContext = 
   var c = PContext(myOpen(module, filename))
   c.fromCache = true
   result = c
@@ -195,6 +194,14 @@ proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
       if result.kind != nkEmpty: addSon(a, result)
       result = a
 
+proc RecoverContext(c: PContext) = 
+  # clean up in case of a semantic error: We clean up the stacks, etc. This is
+  # faster than wrapping every stack operation in a 'try finally' block and 
+  # requires far less code.
+  while c.tab.tos-1 > ModuleTablePos: rawCloseScope(c.tab)
+  while getCurrOwner().kind != skModule: popOwner()
+  while c.p != nil and c.p.owner.kind != skModule: c.p = c.p.next
+
 proc myProcess(context: PPassContext, n: PNode): PNode = 
   var c = PContext(context)    
   # no need for an expensive 'try' if we stop after the first error anyway:
@@ -204,6 +211,7 @@ proc myProcess(context: PPassContext, n: PNode): PNode =
     try:
       result = SemStmtAndGenerateGenerics(c, n)
     except ERecoverableError:
+      RecoverContext(c)
       result = ast.emptyNode
   
 proc myClose(context: PPassContext, n: PNode): PNode = 
@@ -216,7 +224,7 @@ proc myClose(context: PPassContext, n: PNode): PNode =
     InternalError(n.info, "n is not nil") #result := n;
   addCodeForGenerics(c, result)
   popOwner()
-  c.p = nil
+  popProcCon(c)
 
 proc semPass(): TPass = 
   initPass(result)
diff --git a/rod/semdata.nim b/rod/semdata.nim
index 702e00059..e052a0baf 100755
--- a/rod/semdata.nim
+++ b/rod/semdata.nim
@@ -23,14 +23,15 @@ type
     Notes*: TNoteKinds
 
   POptionEntry* = ref TOptionEntry
+  PProcCon* = ref TProcCon
   TProcCon*{.final.} = object # procedure context; also used for top-level
                               # statements
     owner*: PSym              # the symbol this context belongs to
     resultSym*: PSym          # the result symbol (if we are in a proc)
     nestedLoopCounter*: int   # whether we are in a loop or not
     nestedBlockCounter*: int  # whether we are in a block or not
+    next*: PProcCon           # used for stacking procedure contexts
   
-  PProcCon* = ref TProcCon
   PContext* = ref TContext
   TContext* = object of TPassContext # a context represents a module
     module*: PSym             # the module sym belonging to the context
@@ -58,7 +59,6 @@ var gInstTypes*: TIdTable # map PType to PType
 
 proc newContext*(module: PSym, nimfile: string): PContext
 
-proc newProcCon*(owner: PSym): PProcCon
 proc lastOptionEntry*(c: PContext): POptionEntry
 proc newOptionEntry*(): POptionEntry
 proc addConverter*(c: PContext, conv: PSym)
@@ -97,10 +97,15 @@ proc PopOwner() =
 proc lastOptionEntry(c: PContext): POptionEntry = 
   result = POptionEntry(c.optionStack.tail)
 
-proc newProcCon(owner: PSym): PProcCon = 
+proc pushProcCon*(c: PContext, owner: PSym) {.inline.} = 
   if owner == nil: InternalError("owner is nil")
-  new(result)
-  result.owner = owner
+  var x: PProcCon
+  new(x)
+  x.owner = owner
+  x.next = c.p
+  c.p = x
+
+proc popProcCon*(c: PContext) {.inline.} = c.p = c.p.next
 
 proc newOptionEntry(): POptionEntry = 
   new(result)
diff --git a/rod/semgnrc.nim b/rod/semgnrc.nim
index 633994942..4894843f8 100755
--- a/rod/semgnrc.nim
+++ b/rod/semgnrc.nim
@@ -64,10 +64,8 @@ proc getIdentNode(n: PNode): PNode =
 #    if withinBind in flags: result = symChoice(c, n, s)
 #    else: result = semGenericStmtSymbol(c, n, s)
 
-proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode = 
-  var 
-    L: int
-    a: PNode
+proc semGenericStmt(c: PContext, n: PNode, 
+                    flags: TSemGenericFlags = {}): PNode = 
   result = n
   if gCmd == cmdIdeTools: suggestStmt(c, n)
   case n.kind
@@ -124,14 +122,14 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
     openScope(c.tab)
     n.sons[0] = semGenericStmt(c, n.sons[0])
     for i in countup(1, sonsLen(n)-1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       checkMinSonsLen(a, 1)
-      L = sonsLen(a)
+      var L = sonsLen(a)
       for j in countup(0, L - 2): a.sons[j] = semGenericStmt(c, a.sons[j])
       a.sons[L - 1] = semGenericStmtScope(c, a.sons[L - 1])
     closeScope(c.tab)
   of nkForStmt: 
-    L = sonsLen(n)
+    var L = sonsLen(n)
     openScope(c.tab)
     n.sons[L - 2] = semGenericStmt(c, n.sons[L - 2])
     for i in countup(0, L - 3): addDecl(c, newSymS(skUnknown, n.sons[i], c))
@@ -147,36 +145,36 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
     checkMinSonsLen(n, 2)
     n.sons[0] = semGenericStmtScope(c, n.sons[0])
     for i in countup(1, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       checkMinSonsLen(a, 1)
-      L = sonsLen(a)
+      var L = sonsLen(a)
       for j in countup(0, L - 2): 
         a.sons[j] = semGenericStmt(c, a.sons[j], {withinTypeDesc})
       a.sons[L - 1] = semGenericStmtScope(c, a.sons[L - 1])
   of nkVarSection: 
     for i in countup(0, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
       if (a.kind != nkIdentDefs) and (a.kind != nkVarTuple): IllFormedAst(a)
       checkMinSonsLen(a, 3)
-      L = sonsLen(a)
-      a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc})
-      a.sons[L - 1] = semGenericStmt(c, a.sons[L - 1])
-      for j in countup(0, L - 3): 
+      var L = sonsLen(a)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc})
+      a.sons[L-1] = semGenericStmt(c, a.sons[L-1])
+      for j in countup(0, L-3):
         addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
   of nkGenericParams: 
     for i in countup(0, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       if (a.kind != nkIdentDefs): IllFormedAst(a)
       checkMinSonsLen(a, 3)
-      L = sonsLen(a)
-      a.sons[L - 2] = semGenericStmt(c, a.sons[L - 2], {withinTypeDesc}) 
+      var L = sonsLen(a)
+      a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc}) 
       # do not perform symbol lookup for default expressions 
-      for j in countup(0, L - 3): 
+      for j in countup(0, L-3): 
         addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[j]), c))
   of nkConstSection: 
     for i in countup(0, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
       if (a.kind != nkConstDef): IllFormedAst(a)
       checkSonsLen(a, 3)
@@ -185,13 +183,13 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
       a.sons[2] = semGenericStmt(c, a.sons[2])
   of nkTypeSection: 
     for i in countup(0, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
       if (a.kind != nkTypeDef): IllFormedAst(a)
       checkSonsLen(a, 3)
       addDecl(c, newSymS(skUnknown, getIdentNode(a.sons[0]), c))
     for i in countup(0, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       if a.kind == nkCommentStmt: continue 
       if (a.kind != nkTypeDef): IllFormedAst(a)
       checkSonsLen(a, 3)
@@ -207,6 +205,7 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
     if n.sons[0].kind != nkEmpty: 
       n.sons[0] = semGenericStmt(c, n.sons[0], {withinTypeDesc})
     for i in countup(1, sonsLen(n) - 1): 
+      var a: PNode
       case n.sons[i].kind
       of nkEnumFieldDef: a = n.sons[i].sons[0]
       of nkIdent: a = n.sons[i]
@@ -219,10 +218,10 @@ proc semGenericStmt(c: PContext, n: PNode, flags: TSemGenericFlags = {}): PNode
     if n.sons[0].kind != nkEmpty: 
       n.sons[0] = semGenericStmt(c, n.sons[0], {withinTypeDesc})
     for i in countup(1, sonsLen(n) - 1): 
-      a = n.sons[i]
+      var a = n.sons[i]
       if (a.kind != nkIdentDefs): IllFormedAst(a)
       checkMinSonsLen(a, 3)
-      L = sonsLen(a)
+      var L = sonsLen(a)
       a.sons[L-2] = semGenericStmt(c, a.sons[L-2], {withinTypeDesc})
       a.sons[L-1] = semGenericStmt(c, a.sons[L-1])
       for j in countup(0, L-3): 
diff --git a/rod/seminst.nim b/rod/seminst.nim
index 99fd1fb87..e37c6e0fc 100755
--- a/rod/seminst.nim
+++ b/rod/seminst.nim
@@ -68,13 +68,12 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
   # generates an instantiated proc
   var 
     oldPrc, oldMod: PSym
-    oldP: PProcCon
     n: PNode
   if c.InstCounter > 1000: InternalError(fn.ast.info, "nesting too deep")
   inc(c.InstCounter)
-  oldP = c.p # restore later
   # NOTE: for access of private fields within generics from a different module
   # and other identifiers we fake the current module temporarily!
+  # XXX bad hack!
   oldMod = c.module
   c.module = getModule(fn)
   result = copySym(fn, false)
@@ -105,17 +104,17 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     GenericCacheAdd(c, fn, result)
     addDecl(c, result)
     if n.sons[codePos].kind != nkEmpty: 
-      c.p = newProcCon(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])
-  else: 
+      popProcCon(c)
+  else:
     result = oldPrc
   popInfoContext()
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.p = oldP                  # restore
   c.module = oldMod
   dec(c.InstCounter)
   
diff --git a/rod/semstmts.nim b/rod/semstmts.nim
index b2fae3f31..71d523540 100755
--- a/rod/semstmts.nim
+++ b/rod/semstmts.nim
@@ -85,7 +85,7 @@ proc semBreakOrContinue(c: PContext, n: PNode): PNode =
     of nkIdent: s = lookUp(c, n.sons[0])
     of nkSym: s = n.sons[0].sym
     else: illFormedAst(n)
-    if (s.kind == skLabel) and (s.owner.id == c.p.owner.id): 
+    if s.kind == skLabel and s.owner.id == c.p.owner.id: 
       var x = newSymNode(s)
       x.info = n.info
       incl(s.flags, sfUsed)
@@ -266,6 +266,13 @@ proc fitRemoveHiddenConv(c: PContext, typ: Ptype, n: PNode): PNode =
   elif not sameType(result.typ, typ): 
     changeType(result, typ)
   
+proc semIdentDef(c: PContext, n: PNode, kind: TSymKind): PSym =
+  if isTopLevel(c): 
+    result = semIdentWithPragma(c, kind, n, {sfStar, sfMinus})
+    incl(result.flags, sfGlobal)
+  else: 
+    result = semIdentWithPragma(c, kind, n, {})
+  
 proc semVar(c: PContext, n: PNode): PNode = 
   var b: PNode
   result = copyNode(n)
@@ -304,13 +311,8 @@ proc semVar(c: PContext, n: PNode): PNode =
       b.sons[length - 2] = ast.emptyNode # no type desc
       b.sons[length - 1] = def
       addSon(result, b)
-    for j in countup(0, length - 3): 
-      var v: PSym
-      if (c.p.owner.kind == skModule): 
-        v = semIdentWithPragma(c, skVar, a.sons[j], {sfStar, sfMinus})
-        incl(v.flags, sfGlobal)
-      else: 
-        v = semIdentWithPragma(c, skVar, a.sons[j], {})
+    for j in countup(0, length-3): 
+      var v = semIdentDef(c, a.sons[j], skVar)
       if v.flags * {sfStar, sfMinus} != {}: incl(v.flags, sfInInterface)
       addInterfaceDecl(c, v)
       if a.kind != nkVarTuple: 
@@ -332,12 +334,7 @@ proc semConst(c: PContext, n: PNode): PNode =
     if a.kind == nkCommentStmt: continue 
     if (a.kind != nkConstDef): IllFormedAst(a)
     checkSonsLen(a, 3)
-    var v: PSym
-    if (c.p.owner.kind == skModule): 
-      v = semIdentWithPragma(c, skConst, a.sons[0], {sfStar, sfMinus})
-      incl(v.flags, sfGlobal)
-    else: 
-      v = semIdentWithPragma(c, skConst, a.sons[0], {})
+    var v = semIdentDef(c, a.sons[0], skConst)
     var typ: PType = nil
     if a.sons[1].kind != nkEmpty: typ = semTypeNode(c, a.sons[1], nil)
     var def = semAndEvalConstExpr(c, a.sons[2]) 
@@ -524,12 +521,7 @@ proc typeSectionLeftSidePass(c: PContext, n: PNode) =
     if a.kind == nkCommentStmt: continue 
     if a.kind != nkTypeDef: IllFormedAst(a)
     checkSonsLen(a, 3)
-    var s: PSym
-    if c.p.owner.kind == skModule: 
-      s = semIdentWithPragma(c, skType, a.sons[0], {sfStar, sfMinus})
-      incl(s.flags, sfGlobal)
-    else: 
-      s = semIdentWithPragma(c, skType, a.sons[0], {})
+    var s = semIdentDef(c, a.sons[0], skType)
     if s.flags * {sfStar, sfMinus} != {}: incl(s.flags, sfInInterface)
     s.typ = newTypeS(tyForward, c)
     s.typ.sym = s             # process pragmas:
@@ -547,7 +539,7 @@ proc typeSectionRightSidePass(c: PContext, n: PNode) =
     checkSonsLen(a, 3)
     if (a.sons[0].kind != nkSym): IllFormedAst(a)
     var s = a.sons[0].sym
-    if (s.magic == mNone) and (a.sons[2].kind == nkEmpty): 
+    if s.magic == mNone and a.sons[2].kind == nkEmpty: 
       GlobalError(a.info, errImplOfXexpected, s.name.s)
     if s.magic != mNone: processMagicType(c, s)
     if a.sons[1].kind != nkEmpty: 
@@ -646,7 +638,6 @@ proc semLambda(c: PContext, n: PNode): PNode =
   checkSonsLen(n, codePos + 1)
   var s = newSym(skProc, getIdent(":anonymous"), getCurrOwner())
   s.info = n.info
-  var oldP = c.p                  # restore later
   s.ast = n
   n.sons[namePos] = newSymNode(s)
   pushOwner(s)
@@ -666,31 +657,26 @@ proc semLambda(c: PContext, n: PNode): PNode =
   if n.sons[codePos].kind != nkEmpty: 
     if sfImportc in s.flags: 
       LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
-    c.p = newProcCon(s)
+    pushProcCon(c, s)
     addResult(c, s.typ.sons[0], n.info)
     n.sons[codePos] = semStmtScope(c, n.sons[codePos])
     addResultNode(c, n)
+    popProcCon(c)
   else: 
     LocalError(n.info, errImplOfXexpected, s.name.s)
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.p = oldP                  # restore
   result.typ = s.typ
 
 proc semProcAux(c: PContext, n: PNode, kind: TSymKind, 
                 validPragmas: TSpecialWords): PNode = 
   var 
-    s, proto: PSym
+    proto: PSym
     gp: PNode
   result = n
   checkSonsLen(n, codePos + 1)
-  if c.p.owner.kind == skModule: 
-    s = semIdentVis(c, kind, n.sons[0], {sfStar})
-    incl(s.flags, sfGlobal)
-  else: 
-    s = semIdentVis(c, kind, n.sons[0], {})
+  var s = semIdentDef(c, n.sons[0], kind)
   n.sons[namePos] = newSymNode(s)
-  var oldP = c.p                  # restore later
   if sfStar in s.flags: incl(s.flags, sfInInterface)
   s.ast = n
   pushOwner(s)
@@ -716,7 +702,7 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   proto = SearchForProc(c, s, c.tab.tos - 2) # -2 because we have a scope open
                                              # for parameters
   if proto == nil: 
-    if oldP.owner.kind != skModule: 
+    if c.p.owner.kind != skModule: 
       s.typ.callConv = ccClosure
     else: 
       s.typ.callConv = lastOptionEntry(c).defaultCC 
@@ -755,13 +741,14 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
     if sfBorrow in s.flags: 
       LocalError(n.sons[codePos].info, errImplOfXNotAllowed, s.name.s)
     if n.sons[genericParamsPos].kind == nkEmpty: 
-      c.p = newProcCon(s)
+      pushProcCon(c, s)
       if (s.typ.sons[0] != nil) and (kind != skIterator): 
         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])
       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))
@@ -776,7 +763,6 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind,
   sideEffectsCheck(c, s)
   closeScope(c.tab)           # close scope for parameters
   popOwner()
-  c.p = oldP                  # restore
   
 proc semIterator(c: PContext, n: PNode): PNode = 
   result = semProcAux(c, n, skIterator, iteratorPragmas)
diff --git a/rod/semtypes.nim b/rod/semtypes.nim
index 79511b716..38f1ffc71 100755
--- a/rod/semtypes.nim
+++ b/rod/semtypes.nim
@@ -694,6 +694,8 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
     if a.sons[L-2].kind != nkEmpty: 
       typ = newTypeS(tyGenericParam, c)
       semGenericConstraints(c, a.sons[L-2], typ)
+      if sonsLen(typ) == 1 and typ.sons[0].kind == tyTypeDesc:
+        typ = typ.sons[0]
     elif def.kind != nkEmpty: typ = newTypeS(tyExpr, c)
     else: typ = nil
     for j in countup(0, L-3): 
diff --git a/tests/accept/run/tkoeniglookup.nim b/tests/accept/run/tkoeniglookup.nim
index 07c5b46be..e6f5c0112 100644
--- a/tests/accept/run/tkoeniglookup.nim
+++ b/tests/accept/run/tkoeniglookup.nim
@@ -9,8 +9,8 @@ type
   TMyObj = object
     x, y: int
 
-proc `$`*(a: TMyObj): bool = 
-  result = "x: " & a.x & " y: " & a.y
+proc `$`*(a: TMyObj): string = 
+  result = "x: " & $a.x & " y: " & $a.y
 
 var a: TMyObj
 echo toString(a)
diff --git a/tests/reject/ttypenoval.nim b/tests/reject/ttypenoval.nim
index ed91b05e2..44b3db879 100755
--- a/tests/reject/ttypenoval.nim
+++ b/tests/reject/ttypenoval.nim
@@ -1,5 +1,5 @@
 discard """
-  file: "tambsym.nim"
+  file: "ttypenoval.nim"
   line: 36
   errormsg: "a type has no value"
 """
diff --git a/todo.txt b/todo.txt
index 09a9117dd..4dc4e17f2 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,3 +1,5 @@
+- clean up the tests!
+- GC: marker procs for native Nimrod GC and Boehm GC
 - thread support: threadvar on Windows seems broken; 
   add --deadlock_prevention:on|off switch
 - built-in serialization
diff --git a/web/news.txt b/web/news.txt
index 9b1979056..c28eef94e 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -67,7 +67,8 @@ Additions
 - The *interactive mode* (REPL) has been improved and documented for the 
   first time.
 - Added the ``linearScanEnd``, ``unroll``, ``shallow`` pragmas.
-- Added ``system.reset``.
+- Added ``system.reset`` and a version of ``system.open`` that 
+  returns a ``TFile`` and raises an exception in case of an error.
 - The compiler now might use a hashing for string case statements depending
   on the number of string literals in the case statement.