summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xcompiler/ast.nim2
-rwxr-xr-xcompiler/ccgtypes.nim30
-rwxr-xr-xcompiler/docgen.nim13
-rwxr-xr-xcompiler/extccomp.nim6
-rwxr-xr-xcompiler/lookups.nim74
-rwxr-xr-xcompiler/nimrod.ini22
-rwxr-xr-xcompiler/parser.nim44
-rwxr-xr-xcompiler/renderer.nim9
-rwxr-xr-xcompiler/sem.nim22
-rwxr-xr-xcompiler/semexprs.nim32
-rwxr-xr-xcompiler/semgnrc.nim9
-rwxr-xr-xcompiler/semstmts.nim2
-rwxr-xr-xcompiler/semtypes.nim6
-rwxr-xr-xcompiler/types.nim6
-rwxr-xr-xdoc/manual.txt112
-rwxr-xr-xkoch.nim14
-rw-r--r--lib/pure/collections/hashtables.nim153
-rwxr-xr-xlib/pure/strtabs.nim25
-rwxr-xr-xlib/system.nim2
-rwxr-xr-xlib/system/hti.nim4
-rwxr-xr-xlib/system/repr.nim14
-rw-r--r--tests/accept/compile/tcan_alias_specialised_generic.nim4
-rwxr-xr-xtests/accept/compile/tconsteval.nim4
-rwxr-xr-xtests/accept/compile/tdictdestruct.nim3
-rw-r--r--tests/accept/compile/tgenericmatcher.nim3
-rw-r--r--tests/accept/compile/tgenericrefs.nim4
-rwxr-xr-xtests/accept/compile/tlexer.nim4
-rwxr-xr-xtests/accept/compile/tmodulealias.nim4
-rwxr-xr-xtests/accept/compile/toop.nim3
-rwxr-xr-xtests/accept/compile/trectuple.nim4
-rwxr-xr-xtests/accept/compile/tsortdev.nim3
-rwxr-xr-xtests/accept/compile/tstrtabs.nim2
-rwxr-xr-xtests/accept/compile/ttempl3.nim16
-rwxr-xr-xtests/accept/run/tassert.nim34
-rwxr-xr-xtests/accept/run/tcgbug.nim4
-rwxr-xr-xtests/accept/run/tclosure.nim1
-rwxr-xr-xtests/accept/run/tcontinuexc.nim2
-rwxr-xr-xtests/accept/run/texcsub.nim1
-rwxr-xr-xtests/accept/run/texplicitgeneric2.nim1
-rwxr-xr-xtests/accept/run/tfloat1.nim2
-rwxr-xr-xtests/accept/run/tfloat2.nim2
-rwxr-xr-xtests/accept/run/tgenerics1.nim2
-rwxr-xr-xtests/accept/run/tmatrix.nim22
-rwxr-xr-xtests/accept/run/toverflw2.nim2
-rwxr-xr-xtests/accept/run/treraise.nim2
-rwxr-xr-xtests/accept/run/tunhandledexc.nim2
-rwxr-xr-xtests/accept/run/twrongexc.nim2
-rwxr-xr-xtests/reject/tnot.nim1
-rwxr-xr-xtests/reject/trectype.nim2
-rwxr-xr-xtests/reject/ttypelessemptyset.nim5
-rwxr-xr-xtests/tester.nim32
-rwxr-xr-xtodo.txt4
52 files changed, 459 insertions, 319 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index e1d389b63..fa7880c30 100755
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -273,7 +273,7 @@ type
     tfNoSideEffect,   # procedure type does not allow side effects
     tfFinal,          # is the object final?
     tfAcyclic,        # type is acyclic (for GC optimization)
-    tfEnumHasWholes,  # enum cannot be mapped into a range
+    tfEnumHasHoles,   # enum cannot be mapped into a range
     tfShallow         # type can be shallow copied on assignment
 
   TTypeFlags* = set[TTypeFlag]
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 840200444..84e1850ad 100755
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -669,37 +669,34 @@ proc genTupleInfo(m: BModule, typ: PType, name: PRope) =
          [expr, toRope(length)])
   appf(m.s[cfsTypeInit3], "$1->node = &$2;$n", [name, tmp])
 
-proc genEnumInfo(m: BModule, typ: PType, name: PRope) = 
-  var 
-    nodePtrs, elemNode, enumNames, enumArray, counter, specialCases: PRope
-    length, firstNimNode: int
-    field: PSym
+proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
   # Type information for enumerations is quite heavy, so we do some
   # optimizations here: The ``typ`` field is never set, as it is redundant
   # anyway. We generate a cstring array and a loop over it. Exceptional
   # positions will be reset after the loop.
   genTypeInfoAux(m, typ, name)
-  nodePtrs = getTempName()
-  length = sonsLen(typ.n)
+  var nodePtrs = getTempName()
+  var length = sonsLen(typ.n)
   appf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", 
        [nodePtrs, toRope(length)])
-  enumNames = nil
-  specialCases = nil
-  firstNimNode = m.typeNodes
+  var enumNames, specialCases: PRope
+  var firstNimNode = m.typeNodes
+  var hasHoles = false
   for i in countup(0, length - 1): 
     assert(typ.n.sons[i].kind == nkSym)
-    field = typ.n.sons[i].sym
-    elemNode = getNimNode(m)
+    var field = typ.n.sons[i].sym
+    var elemNode = getNimNode(m)
     if field.ast == nil:
       # no explicit string literal for the enum field, so use field.name:
       app(enumNames, makeCString(field.name.s))
     else:
       app(enumNames, makeCString(field.ast.strVal))
     if i < length - 1: app(enumNames, ", " & tnl)
-    if field.position != i: 
+    if field.position != i or tfEnumHasHoles in typ.flags:
       appf(specialCases, "$1.offset = $2;$n", [elemNode, toRope(field.position)])
-  enumArray = getTempName()
-  counter = getTempName()
+      hasHoles = true
+  var enumArray = getTempName()
+  var counter = getTempName()
   appf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
   appf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n", 
        [enumArray, toRope(length), enumNames])
@@ -711,6 +708,9 @@ proc genEnumInfo(m: BModule, typ: PType, name: PRope) =
   appf(m.s[cfsTypeInit3], 
        "$1.len = $2; $1.kind = 2; $1.sons = &$3[0];$n$4->node = &$1;$n", 
        [getNimNode(m), toRope(length), nodePtrs, name])
+  if hasHoles:
+    # 1 << 2 is {ntfEnumHole}
+    appf(m.s[cfsTypeInit3], "$1->flags = 1<<2;$n", [name])
 
 proc genSetInfo(m: BModule, typ: PType, name: PRope) = 
   assert(typ.sons[0] != nil)
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 74316871d..eeb40f256 100755
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -297,8 +297,11 @@ proc getName(n: PNode, splitAfter: int = - 1): string =
   of nkPragmaExpr: result = getName(n.sons[0], splitAfter)
   of nkSym: result = esc(n.sym.name.s, splitAfter)
   of nkIdent: result = esc(n.ident.s, splitAfter)
-  of nkAccQuoted: result = esc("`") & getName(n.sons[0], splitAfter) & esc("`")
-  else: 
+  of nkAccQuoted: 
+    result = esc("`") 
+    for i in 0.. <n.len: result.add(getName(n[i], splitAfter))
+    result.add esc("`")
+  else:
     internalError(n.info, "getName()")
     result = ""
 
@@ -308,8 +311,10 @@ proc getRstName(n: PNode): PRstNode =
   of nkPragmaExpr: result = getRstName(n.sons[0])
   of nkSym: result = newRstNode(rnLeaf, n.sym.name.s)
   of nkIdent: result = newRstNode(rnLeaf, n.ident.s)
-  of nkAccQuoted: result = getRstName(n.sons[0])
-  else: 
+  of nkAccQuoted: 
+    result = getRstName(n.sons[0])
+    for i in 1 .. <n.len: result.text.add(getRstName(n[i]).text)
+  else:
     internalError(n.info, "getRstName()")
     result = nil
 
diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim
index a673c5ca0..8fa52b5d2 100755
--- a/compiler/extccomp.nim
+++ b/compiler/extccomp.nim
@@ -69,7 +69,8 @@ const
      linkerExe: "llvm-gcc", 
      linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles", 
      includeCmd: " -I", 
-     debug: "", pic: "-fPIC", 
+     debug: "", 
+     pic: "-fPIC", 
      asmStmtFrmt: "asm($1);$n", 
      props: {hasSwitchRange, hasComputedGoto, hasCpp}), 
     (name: "clang", 
@@ -83,7 +84,8 @@ const
      linkerExe: "clang", 
      linkTmpl: "$options $buildgui $builddll -o $exefile $objfiles", 
      includeCmd: " -I", 
-     debug: "", pic: "-fPIC", 
+     debug: "", 
+     pic: "-fPIC", 
      asmStmtFrmt: "asm($1);$n", 
      props: {hasSwitchRange, hasComputedGoto, hasCpp}), 
     (name: "lcc", 
diff --git a/compiler/lookups.nim b/compiler/lookups.nim
index 80a6cd17e..0aaff6bc5 100755
--- a/compiler/lookups.nim
+++ b/compiler/lookups.nim
@@ -12,6 +12,24 @@
 import 
   ast, astalgo, idents, semdata, types, msgs, options, rodread, renderer
 
+proc considerAcc*(n: PNode): PIdent = 
+  case n.kind
+  of nkIdent: result = n.ident
+  of nkSym: result = n.sym.name
+  of nkAccQuoted:
+    case n.len
+    of 0: GlobalError(n.info, errIdentifierExpected, renderTree(n))
+    of 1: result = considerAcc(n.sons[0])
+    else:
+      var id = ""
+      for i in 0.. <n.len:
+        if n.sons[i].kind != nkIdent:
+          GlobalError(n.info, errIdentifierExpected, renderTree(n))
+        id.add(n.sons[i].ident.s)
+      result = getIdent(id)
+  else:
+    GlobalError(n.info, errIdentifierExpected, renderTree(n))
+
 type 
   TOverloadIterMode* = enum 
     oimDone, oimNoQualifier, oimSelfModule, oimOtherModule, oimSymChoice,
@@ -87,13 +105,15 @@ proc addInterfaceOverloadableSymAt*(c: PContext, sym: PSym, at: int) =
 proc lookUp*(c: PContext, n: PNode): PSym = 
   # Looks up a symbol. Generates an error in case of nil.
   case n.kind
-  of nkAccQuoted: 
-    result = lookup(c, n.sons[0])
-  of nkSym: 
-    result = n.sym
-  of nkIdent: 
+  of nkIdent:
     result = SymtabGet(c.Tab, n.ident)
     if result == nil: GlobalError(n.info, errUndeclaredIdentifier, n.ident.s)
+  of nkSym:
+    result = n.sym
+  of nkAccQuoted:
+    var ident = considerAcc(n)
+    result = SymtabGet(c.Tab, ident)
+    if result == nil: GlobalError(n.info, errUndeclaredIdentifier, ident.s)
   else: InternalError(n.info, "lookUp")
   if IntSetContains(c.AmbiguousSymbols, result.id): 
     LocalError(n.info, errUseQualifier, result.name.s)
@@ -102,16 +122,17 @@ proc lookUp*(c: PContext, n: PNode): PSym =
 type 
   TLookupFlag* = enum 
     checkAmbiguity, checkUndeclared
-  
+
 proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym = 
   case n.kind
-  of nkIdent: 
-    result = SymtabGet(c.Tab, n.ident)
+  of nkIdent, nkAccQuoted:
+    var ident = considerAcc(n)
+    result = SymtabGet(c.Tab, ident)
     if result == nil and checkUndeclared in flags: 
-      GlobalError(n.info, errUndeclaredIdentifier, n.ident.s)
+      GlobalError(n.info, errUndeclaredIdentifier, ident.s)
     elif checkAmbiguity in flags and result != nil and 
         IntSetContains(c.AmbiguousSymbols, result.id): 
-      LocalError(n.info, errUseQualifier, n.ident.s)
+      LocalError(n.info, errUseQualifier, ident.s)
   of nkSym: 
     result = n.sym
     if checkAmbiguity in flags and IntSetContains(c.AmbiguousSymbols, 
@@ -122,11 +143,10 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
     var m = qualifiedLookUp(c, n.sons[0], flags*{checkUndeclared})
     if (m != nil) and (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): 
-        ident = n.sons[1].sons[0].ident
+      elif n.sons[1].kind == nkAccQuoted: 
+        ident = considerAcc(n.sons[1])
       if ident != nil: 
         if m == c.module: 
           result = StrTableGet(c.tab.stack[ModuleTablePos], ident)
@@ -137,21 +157,20 @@ proc QualifiedLookUp*(c: PContext, n: PNode, flags = {checkUndeclared}): PSym =
       elif checkUndeclared in flags: 
         GlobalError(n.sons[1].info, errIdentifierExpected, 
                     renderTree(n.sons[1]))
-  of nkAccQuoted: 
-    result = QualifiedLookup(c, n.sons[0], flags)
-  else: 
+  else:
     result = nil
-  if (result != nil) and (result.kind == skStub): loadStub(result)
+  if result != nil and result.kind == skStub: loadStub(result)
   
 proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym = 
   case n.kind
-  of nkIdent: 
+  of nkIdent, nkAccQuoted:
+    var ident = considerAcc(n)
     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)
+      if o.stackPtr < 0: break
+      result = InitIdentIter(o.it, c.tab.stack[o.stackPtr], ident)
   of nkSym: 
     result = n.sym
     o.mode = oimDone
@@ -162,9 +181,8 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       var ident: PIdent = nil
       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: 
-        ident = n.sons[1].sons[0].ident
+      elif n.sons[1].kind == nkAccQuoted:
+        ident = considerAcc(n.sons[1])
       if ident != nil: 
         if o.m == c.module: 
           # a module may access its private members:
@@ -175,8 +193,6 @@ proc InitOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
       else: 
         GlobalError(n.sons[1].info, errIdentifierExpected, 
                     renderTree(n.sons[1]))
-  of nkAccQuoted: 
-    result = InitOverloadIter(o, c, n.sons[0])
   of nkSymChoice: 
     o.mode = oimSymChoice
     result = n.sons[0].sym
@@ -191,9 +207,7 @@ proc nextOverloadIter*(o: var TOverloadIter, c: PContext, n: PNode): PSym =
   of oimDone: 
     result = nil
   of oimNoQualifier: 
-    if n.kind == nkAccQuoted: 
-      result = nextOverloadIter(o, c, n.sons[0])
-    elif o.stackPtr >= 0: 
+    if o.stackPtr >= 0: 
       result = nextIdentIter(o.it, c.tab.stack[o.stackPtr])
       while result == nil: 
         dec(o.stackPtr)
diff --git a/compiler/nimrod.ini b/compiler/nimrod.ini
index 3a88fd521..3cca80b51 100755
--- a/compiler/nimrod.ini
+++ b/compiler/nimrod.ini
@@ -73,33 +73,11 @@ Files: "lib/wrappers/x11/*.nim"
 Files: "lib/wrappers/zip/*.nim"
 Files: "lib/wrappers/zip/libzip_all.c"
 
-Files: "lib/oldwrappers/*.nim"
-
-Files: "lib/oldwrappers/cairo/*.nim"
-Files: "lib/oldwrappers/gtk/*.nim"
-Files: "lib/oldwrappers/lua/*.nim"
-Files: "lib/oldwrappers/opengl/*.nim"
-Files: "lib/oldwrappers/pcre/*.nim"
-Files: "lib/oldwrappers/pcre/pcre_all.c"
-Files: "lib/oldwrappers/sdl/*.nim"
-Files: "lib/oldwrappers/x11/*.nim"
-Files: "lib/oldwrappers/zip/*.nim"
-Files: "lib/oldwrappers/zip/libzip_all.c"
-
 Files: "lib/windows/*.nim"
 Files: "lib/posix/*.nim"
 Files: "lib/ecmas/*.nim"
 
 [Other]
-Files: "tests/*.nim"
-Files: "tests/*.html"
-Files: "tests/*.txt"
-Files: "tests/*.cfg"
-Files: "tests/*.tmpl"
-Files: "tests/accept/run/*.nim"
-Files: "tests/accept/compile/*.nim"
-Files: "tests/reject/*.nim"
-
 Files: "examples/*.nim"
 Files: "examples/*.html"
 Files: "examples/*.txt"
diff --git a/compiler/parser.nim b/compiler/parser.nim
index 1b8f2f259..181ae19a7 100755
--- a/compiler/parser.nim
+++ b/compiler/parser.nim
@@ -52,7 +52,6 @@ proc optInd*(p: var TParser, n: PNode)
 proc indAndComment*(p: var TParser, n: PNode)
 proc setBaseFlags*(n: PNode, base: TNumericalBase)
 proc parseSymbol*(p: var TParser): PNode
-proc accExpr*(p: var TParser): PNode
 # implementation
 
 proc initParser(p: var TParser) = 
@@ -173,60 +172,33 @@ proc parseSymbol(p: var TParser): PNode =
   of tkAccent: 
     result = newNodeP(nkAccQuoted, p)
     getTok(p)
-    var id = ""
     while true:
       case p.tok.tokType
       of tkBracketLe: 
-        id.add("[]")
+        add(result, newIdentNodeP(getIdent"[]", p))
         getTok(p)
         eat(p, tkBracketRi)
       of tkEquals:
-        id.add('=')
+        add(result, newIdentNodeP(getIdent"=", p))
         getTok(p)
-      of tkParLe: 
-        id.add("()")
+      of tkParLe:
+        add(result, newIdentNodeP(getIdent"()", p))
         getTok(p)
         eat(p, tkParRi)
       of tokKeywordLow..tokKeywordHigh, tkSymbol, tkOpr, tkDotDot:
-        id.add(p.tok.ident.s)
+        add(result, newIdentNodeP(p.tok.ident, p))
         getTok(p)
       of tkIntLit..tkCharLit:
-        id.add(tokToStr(p.tok))
+        add(result, newIdentNodeP(getIdent(tokToStr(p.tok)), p))
         getTok(p)
       else:
-        if id.len == 0: parMessage(p, errIdentifierExpected, tokToStr(p.tok))
+        if result.len == 0: parMessage(p, errIdentifierExpected, tokToStr(p.tok))
         break
-    add(result, newIdentNodeP(getIdent(id), p))
     eat(p, tkAccent)
   else: 
     parMessage(p, errIdentifierExpected, tokToStr(p.tok))
     result = ast.emptyNode
 
-proc accExpr(p: var TParser): PNode = 
-  result = newNodeP(nkAccQuoted, p)
-  getTok(p)                   # skip `
-  var x = ast.emptyNode
-  var y = ast.emptyNode
-  case p.tok.tokType
-  of tkSymbol, tkOpr, tokKeywordLow..tokKeywordHigh: 
-    x = newIdentNodeP(p.tok.ident, p)
-    getTok(p)
-  else: 
-    parMessage(p, errIdentifierExpected, tokToStr(p.tok))
-  if p.tok.tokType == tkDot: 
-    getTok(p)
-    case p.tok.tokType
-    of tkSymbol, tkOpr, tokKeywordLow..tokKeywordHigh: 
-      y = newNodeP(nkDotExpr, p)
-      addSon(y, x)
-      addSon(y, newIdentNodeP(p.tok.ident, p))
-      getTok(p)
-      x = y
-    else: 
-      parMessage(p, errIdentifierExpected, tokToStr(p.tok))
-  addSon(result, x)
-  eat(p, tkAccent)
-
 proc indexExpr(p: var TParser): PNode = 
   result = parseExpr(p)
 
@@ -379,7 +351,7 @@ proc identOrLiteral(p: var TParser): PNode =
     getTok(p)
     result = parseGStrLit(p, result)
   of tkAccent: 
-    result = accExpr(p)       # literals
+    result = parseSymbol(p)       # literals
   of tkIntLit: 
     result = newIntNodeP(nkIntLit, p.tok.iNumber, p)
     setBaseFlags(result, p.tok.base)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 476709f8d..2167c8e5d 100755
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -369,7 +369,7 @@ proc lsub(n: PNode): int =
   of nkPragmaExpr: result = lsub(n.sons[0]) + lcomma(n, 1)
   of nkRange: result = lsons(n) + 2
   of nkDerefExpr: result = lsub(n.sons[0]) + 2
-  of nkAccQuoted: result = lsub(n.sons[0]) + 2
+  of nkAccQuoted: result = lsons(n) + 2
   of nkIfExpr: 
     result = lsub(n.sons[0].sons[0]) + lsub(n.sons[0].sons[1]) + lsons(n, 1) +
         len("if_:_")
@@ -823,9 +823,12 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
     gsub(g, n.sons[0])
     putWithSpace(g, tkHat, "^") 
     # unfortunately this requires a space, because ^. would be only one operator
-  of nkAccQuoted: 
+  of nkAccQuoted:
     put(g, tkAccent, "`")
-    gsub(g, n.sons[0])
+    if n.len > 0: gsub(g, n.sons[0])
+    for i in 0 .. <n.len:
+      put(g, tkSpaces, Space)
+      gsub(g, n.sons[i])
     put(g, tkAccent, "`")
   of nkIfExpr: 
     putWithSpace(g, tkIf, "if")
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 2b2d9506b..2e63ea2ef 100755
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -18,16 +18,6 @@ import
 proc semPass*(): TPass
 # implementation
 
-proc considerAcc(n: PNode): PIdent = 
-  var x = n
-  if x.kind == nkAccQuoted: x = x.sons[0]
-  case x.kind
-  of nkIdent: result = x.ident
-  of nkSym: result = x.sym.name
-  else: 
-    GlobalError(n.info, errIdentifierExpected, renderTree(n))
-    result = nil
-
 proc isTopLevel(c: PContext): bool {.inline.} = 
   result = c.tab.tos <= 2
 
@@ -35,7 +25,8 @@ proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
   result = newSym(kind, considerAcc(n), getCurrOwner())
   result.info = n.info
   
-proc semIdentVis(c: PContext, kind: TSymKind, n: PNode, allowed: TSymFlags): PSym
+proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
+                 allowed: TSymFlags): PSym
   # identifier with visability
 proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode, 
                         allowed: TSymFlags): PSym
@@ -120,20 +111,13 @@ proc typeMismatch(n: PNode, formal, actual: PType) =
 
 proc fitNode(c: PContext, formal: PType, arg: PNode): PNode = 
   result = IndexTypesMatch(c, formal, arg.typ, arg)
-  if result == nil: 
+  if result == nil:
     #debug(arg)
     typeMismatch(arg, formal, arg.typ)
 
 proc forceBool(c: PContext, n: PNode): PNode = 
   result = fitNode(c, getSysType(tyBool), n)
   if result == nil: result = n
-  when false:
-    result = t
-    if (t.Typ == nil) or
-        (skipTypes(t.Typ, {tyGenericInst, tyVar, tyOrdinal}).kind != tyBool): 
-      var a = ConvertTo(c, getSysType(tyBool), t)
-      if a != nil: result = a
-      else: LocalError(t.Info, errExprMustBeBool)
 
 proc semConstBoolExpr(c: PContext, n: PNode): PNode = 
   result = fitNode(c, getSysType(tyBool), semExprWithType(c, n))
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 35fb793c4..a7b35f08b 100755
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -501,14 +501,17 @@ proc semEcho(c: PContext, n: PNode): PNode =
     n.sons[i] = semExpr(c, buildStringify(c, arg))
   result = n
 
+proc lookUpForDefined(c: PContext, i: PIdent, onlyCurrentScope: bool): PSym =
+  if onlyCurrentScope: 
+    result = SymtabLocalGet(c.tab, i)
+  else: 
+    result = SymtabGet(c.Tab, i) # no need for stub loading
+
 proc LookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym = 
   case n.kind
   of nkIdent: 
-    if onlyCurrentScope: 
-      result = SymtabLocalGet(c.tab, n.ident)
-    else: 
-      result = SymtabGet(c.Tab, n.ident) # no need for stub loading
-  of nkDotExpr: 
+    result = LookupForDefined(c, n.ident, onlyCurrentScope)
+  of nkDotExpr:
     result = nil
     if onlyCurrentScope: return 
     checkSonsLen(n, 2)
@@ -522,9 +525,8 @@ proc LookUpForDefined(c: PContext, n: PNode, onlyCurrentScope: bool): PSym =
           result = StrTableGet(m.tab, ident)
       else: 
         GlobalError(n.sons[1].info, errIdentifierExpected, "")
-  of nkAccQuoted: 
-    checkSonsLen(n, 1)
-    result = lookupForDefined(c, n.sons[0], onlyCurrentScope)
+  of nkAccQuoted:
+    result = lookupForDefined(c, considerAcc(n), onlyCurrentScope)
   else: 
     GlobalError(n.info, errIdentifierExpected, renderTree(n))
     result = nil
@@ -955,17 +957,16 @@ proc semMacroStmt(c: PContext, n: PNode, semCheck = true): PNode =
   else: 
     GlobalError(n.info, errInvalidExpressionX, 
                 renderTree(a, {renderNoComments}))
-  
+
 proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode = 
   result = n
-  if gCmd == cmdIdeTools: 
-    suggestExpr(c, n)
+  if gCmd == cmdIdeTools: suggestExpr(c, n)
   if nfSem in n.flags: return 
-  case n.kind                 # atoms:
-  of nkIdent: 
+  case n.kind
+  of nkIdent, nkAccQuoted:
     var s = lookUp(c, n)
     result = semSym(c, n, s, flags)
-  of nkSym: 
+  of nkSym:
     # because of the changed symbol binding, this does not mean that we
     # don't have to check the symbol for semantics here again!
     result = semSym(c, n, n.sym, flags)
@@ -1062,9 +1063,6 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     checkSonsLen(n, 1)
     n.sons[0] = semExpr(c, n.sons[0], flags)
   of nkCast: result = semCast(c, n)
-  of nkAccQuoted: 
-    checkSonsLen(n, 1)
-    result = semExpr(c, n.sons[0])
   of nkIfExpr: result = semIfExpr(c, n)
   of nkStmtListExpr: result = semStmtListExpr(c, n)
   of nkBlockExpr: result = semBlockExpr(c, n)
diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim
index 4894843f8..463fd72ca 100755
--- a/compiler/semgnrc.nim
+++ b/compiler/semgnrc.nim
@@ -53,17 +53,12 @@ proc semGenericStmtSymbol(c: PContext, n: PNode, s: PSym): PNode =
 proc getIdentNode(n: PNode): PNode = 
   case n.kind
   of nkPostfix: result = getIdentNode(n.sons[1])
-  of nkPragmaExpr, nkAccQuoted: result = getIdentNode(n.sons[0])
-  of nkIdent: result = n
+  of nkPragmaExpr: result = getIdentNode(n.sons[0])
+  of nkIdent, nkAccQuoted: result = n
   else: 
     illFormedAst(n)
     result = n
 
-#  of nkAccQuoted: 
-#    s = lookUp(c, n)
-#    if withinBind in flags: result = symChoice(c, n, s)
-#    else: result = semGenericStmtSymbol(c, n, s)
-
 proc semGenericStmt(c: PContext, n: PNode, 
                     flags: TSemGenericFlags = {}): PNode = 
   result = n
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 624b8f196..341434275 100755
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -127,7 +127,7 @@ proc semWhile(c: PContext, n: PNode): PNode =
 
 proc toCover(t: PType): biggestInt = 
   var t2 = skipTypes(t, abstractVarRange)
-  if t2.kind == tyEnum and enumHasWholes(t2): 
+  if t2.kind == tyEnum and enumHasHoles(t2): 
     result = sonsLen(t2.n)
   else:
     result = lengthOrd(skipTypes(t, abstractVar))
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index ed9b9f4d5..91a00de11 100755
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -51,7 +51,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       else:
         x = getOrdValue(v)
       if i != 1: 
-        if (x != counter): incl(result.flags, tfEnumHasWholes)
+        if (x != counter): incl(result.flags, tfEnumHasHoles)
         if x < counter: 
           GlobalError(n.sons[i].info, errInvalidOrderInEnumX, e.name.s)
       e.ast = strVal # might be nil
@@ -128,7 +128,7 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
   if not (a.typ.kind in
       {tyInt..tyInt64, tyEnum, tyBool, tyChar, tyFloat..tyFloat128}): 
     GlobalError(n.info, errOrdinalTypeExpected)
-  if enumHasWholes(a.typ): 
+  if enumHasHoles(a.typ): 
     GlobalError(n.info, errEnumXHasHoles, a.typ.sym.name.s)
   if not leValue(a, b): GlobalError(n.Info, errRangeIsEmpty)
   addSon(result.n, a)
@@ -155,7 +155,7 @@ proc semArray(c: PContext, n: PNode, prev: PType): PType =
     if indx.kind != tyGenericParam: 
       if not isOrdinalType(indx): 
         GlobalError(n.sons[1].info, errOrdinalTypeExpected)
-      if enumHasWholes(indx): 
+      if enumHasHoles(indx): 
         GlobalError(n.sons[1].info, errEnumXHasHoles, indx.sym.name.s)
     base = semTypeNode(c, n.sons[2], nil)
     addSon(result, base)
diff --git a/compiler/types.nim b/compiler/types.nim
index dcabbd3ee..953366deb 100755
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -48,7 +48,7 @@ type
 proc equalParams*(a, b: PNode): TParamsEquality
   # returns whether the parameter lists of the procs a, b are exactly the same
 proc isOrdinalType*(t: PType): bool
-proc enumHasWholes*(t: PType): bool
+proc enumHasHoles*(t: PType): bool
 const 
   abstractPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyDistinct, tyOrdinal}
   abstractVar* = {tyVar, tyGenericInst, tyDistinct, tyOrdinal}
@@ -193,10 +193,10 @@ proc isOrdinalType(t: PType): bool =
   result = (t.Kind in {tyChar, tyInt..tyInt64, tyBool, tyEnum}) or
       (t.Kind in {tyRange, tyOrdinal}) and isOrdinalType(t.sons[0])
 
-proc enumHasWholes(t: PType): bool = 
+proc enumHasHoles(t: PType): bool = 
   var b = t
   while b.kind == tyRange: b = b.sons[0]
-  result = (b.Kind == tyEnum) and (tfEnumHasWholes in b.flags)
+  result = b.Kind == tyEnum and tfEnumHasHoles in b.flags
 
 proc iterOverTypeAux(marker: var TIntSet, t: PType, iter: TTypeIter, 
                      closure: PObject): bool
diff --git a/doc/manual.txt b/doc/manual.txt
index 9067946ac..a284c6a0b 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -346,10 +346,10 @@ notation:
 ``0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64``

 is approximately 1.72826e35 according to the IEEE floating point standard.

 

-
-Operators
----------
-
+

+Operators

+---------

+

 In Nimrod one can define his own operators. An `operator`:idx: is any

 combination of the following characters::

 

@@ -358,14 +358,14 @@ combination of the following characters::
        !     ?     ^     .     :     \

 

 These keywords are also operators:

-``and or not xor shl shr div mod in notin is isnot``.
-
-`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they
-are used for other notational purposes. 
-
-``*:`` is as a special case the two tokens `*`:tok: and `:`:tok:
+``and or not xor shl shr div mod in notin is isnot``.

+

+`=`:tok:, `:`:tok:, `::`:tok: are not available as general operators; they

+are used for other notational purposes. 

+

+``*:`` is as a special case the two tokens `*`:tok: and `:`:tok:

 (to support ``var v*: T``).

-
+

 

 Other tokens

 ------------

@@ -373,10 +373,10 @@ Other tokens
 The following strings denote other tokens::

 

     `   (     )     {     }     [     ]     ,  ;   [.    .]  {.   .}  (.  .)

-
-
-The `slice`:idx: operator `..`:tok: takes precedence over other tokens that 
-contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: 
+

+

+The `slice`:idx: operator `..`:tok: takes precedence over other tokens that 

+contain a dot: `{..}`:tok: are the three tokens `{`:tok:, `..`:tok:, `}`:tok: 

 and not the two tokens `{.`:tok:, `.}`:tok:.

 

 

@@ -398,7 +398,7 @@ Precedence level    Operators                                     First characte
   9 (highest)                                                     ``$  ^``            OP9

   8               ``*    /    div   mod   shl  shr  %``           ``* % \  /``        OP8

   7               ``+    -``                                      ``+  ~  |``         OP7

-  6               ``&``                                           ``&``               OP6
+  6               ``&``                                           ``&``               OP6

   5               ``..``                                          ``.``               OP5

   4               ``==  <= < >= > !=  in not_in is isnot not``    ``= <  > !``        OP4

   3               ``and``                                                             OP3

@@ -1815,34 +1815,34 @@ Example:
 An if expression always results in a value, so the ``else`` part is

 required. ``Elif`` parts are also allowed (but unlikely to be good

 style).

-
-
-Table constructor
+

+

+Table constructor

 ~~~~~~~~~~~~~~~~~

-
-A `table constructor`:idx: is syntactic sugar for an array constructor:
-
-.. code-block:: nimrod
-  {"key1": "value1", "key2": "value2"}
-  
-  # is the same as:
-  [("key1", "value1"), ("key2", "value2")]
-
-
-The empty table can be written ``{:}`` (in contrast to the empty set 
-which is ``{}``) which is thus another way to write as the empty array
-constructor ``[]``. This slightly unusal way of supporting tables 
+

+A `table constructor`:idx: is syntactic sugar for an array constructor:

+

+.. code-block:: nimrod

+  {"key1": "value1", "key2": "value2"}

+  

+  # is the same as:

+  [("key1", "value1"), ("key2", "value2")]

+

+

+The empty table can be written ``{:}`` (in contrast to the empty set 

+which is ``{}``) which is thus another way to write as the empty array

+constructor ``[]``. This slightly unusal way of supporting tables 

 has lots of advantages:

-
-* The order of the (key,value)-pairs is preserved, thus it is easy to
-  support ordered dicts with for example ``{key: val}.newOrderedTable``.
-* A table literal can be put into a ``const`` section and the compiler
-  can easily put it into the executable's data section just like it can
-  for arrays and the generated data section requires a minimal amount
-  of memory.
-* Every table implementation is treated equal syntactically.
-* Apart from the minimal syntactic sugar the language core does not need to
-  know about tables.
+

+* The order of the (key,value)-pairs is preserved, thus it is easy to

+  support ordered dicts with for example ``{key: val}.newOrderedTable``.

+* A table literal can be put into a ``const`` section and the compiler

+  can easily put it into the executable's data section just like it can

+  for arrays and the generated data section requires a minimal amount

+  of memory.

+* Every table implementation is treated equal syntactically.

+* Apart from the minimal syntactic sugar the language core does not need to

+  know about tables.

 

 

 Type conversions

@@ -2248,7 +2248,7 @@ introduce type parameters or to instantiate a generic proc, iterator or type.
 

 

 Templates

-~~~~~~~~~

+---------

 

 A `template`:idx: is a simple form of a macro: It is a simple substitution

 mechanism that operates on Nimrod's abstract syntax trees. It is processed in

@@ -2372,6 +2372,24 @@ powerful programming construct that still suffices. So the "check list" is:
 (3) Else: Use a template, if possible.

 (4) Else: Use a macro.

 

+Identifier construction

+~~~~~~~~~~~~~~~~~~~~~~~

+

+In templates identifiers can be constructed with the backticks notation:

+

+.. code-block:: nimrod

+

+  template typedef(name: expr, typ: typeDesc) = 

+    type

+      `T name`* = typ

+      `P name`* = ref `T name`

+      

+  typedef(myint, int)

+  var x: PMyInt

+

+In the example ``name`` is instantiated with ``myint``, so \`T name\` becomes

+``Tmyint``.

+

 

 Macros

 ------

@@ -2986,10 +3004,10 @@ string expressions in general:
   proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}

 

 **Note**: Patterns like ``libtcl(|8.5|8.4).so`` are only supported in constant

-strings, because they are precompiled.
-
-**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime 
-because of order of initialization problems.
+strings, because they are precompiled.

+

+**Note**: Passing variables to the ``dynlib`` pragma will fail at runtime 

+because of order of initialization problems.

 

 

 Dynlib pragma for export

diff --git a/koch.nim b/koch.nim
index 4c4f107da..2200578ad 100755
--- a/koch.nim
+++ b/koch.nim
@@ -32,7 +32,8 @@ Possible Commands:
   web                      generates the website
   csource [options]        builds the C sources for installation
   zip                      builds the installation ZIP package
-  inno [options]           builds the Inno Setup installer
+  inno [options]           builds the Inno Setup installer (for Windows)
+  tests                    run the testsuite
 Boot options:
   -d:release               produce a release version of the compiler
   -d:tinyc                 include the Tiny C backend (not supported on Windows)
@@ -52,11 +53,11 @@ proc tryExec(cmd: string): bool =
   result = execShellCmd(cmd) == 0
 
 proc csource(args: string) = 
-  exec("nimrod cc $1 -r tools/niminst --var:version=$2 csource compiler/nimrod $1" %
+  exec("nimrod cc $1 -r tools/niminst --var:version=$2 csource compiler/nimrod.ini $1" %
        [args, NimrodVersion])
 
 proc zip(args: string) = 
-  exec("nimrod cc -r tools/niminst --var:version=$# zip compiler/nimrod" %
+  exec("nimrod cc -r tools/niminst --var:version=$# zip compiler/nimrod.ini" %
        NimrodVersion)
   
 proc buildTool(toolname, args: string) = 
@@ -172,6 +173,12 @@ proc clean(args: string) =
   removePattern("web/*.html")
   removePattern("doc/*.html")
   cleanAux(getCurrentDir())
+  for kind, path in walkDir(getCurrentDir() / "build"):
+    if kind == pcDir: RemoveDir(path)
+
+proc tests(args: string) =
+  exec("nimrod cc tests/tester")
+  exec("tests/tester")
 
 proc showHelp() = 
   quit(HelpText % [NimrodVersion & repeatChar(44-len(NimrodVersion)), 
@@ -190,6 +197,7 @@ of cmdArgument:
   of "zip": zip(op.cmdLineRest)
   of "inno": inno(op.cmdLineRest)
   of "install": install(op.cmdLineRest)
+  of "test", "tests": tests(op.cmdLineRest)
   else: showHelp()
 of cmdEnd: showHelp()
 
diff --git a/lib/pure/collections/hashtables.nim b/lib/pure/collections/hashtables.nim
index 9562d3a6a..29ba6bf6f 100644
--- a/lib/pure/collections/hashtables.nim
+++ b/lib/pure/collections/hashtables.nim
@@ -23,21 +23,21 @@ type
 
   PHashTable*[A, B] = ref THashTable[A, B] ## use this type to declare tables
 
-proc len*[A, B](t: PHashTable[A, B]): int =
+proc len*[A, B](t: THashTable[A, B]): int =
   ## returns the number of keys in `t`.
   result = t.counter
 
-iterator pairs*[A, B](t: PHashTable[A, B]): tuple[key: A, val: B] =
+iterator pairs*[A, B](t: THashTable[A, B]): tuple[key: A, val: B] =
   ## iterates over any (key, value) pair in the table `t`.
   for h in 0..high(t.data):
     if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
 
-iterator keys*[A, B](t: PHashTable[A, B]): A =
+iterator keys*[A, B](t: THashTable[A, B]): A =
   ## iterates over any key in the table `t`.
   for h in 0..high(t.data):
     if t.data[h].slot == seFilled: yield t.data[h].key
 
-iterator values*[A, B](t: PHashTable[A, B]): B =
+iterator values*[A, B](t: THashTable[A, B]): B =
   ## iterates over any value in the table `t`.
   for h in 0..high(t.data):
     if t.data[h].slot == seFilled: yield t.data[h].val
@@ -52,7 +52,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
 proc nextTry(h, maxHash: THash): THash {.inline.} =
   result = ((5 * h) + 1) and maxHash
 
-proc RawGet[A, B](t: PHashTable[A, B], key: A): int =
+template rawGetImpl() =
   var h: THash = hash(key) and high(t.data) # start with real hash value
   while t.data[h].slot != seEmpty:
     if t.data[h].key == key and t.data[h].slot == seFilled:
@@ -60,7 +60,18 @@ proc RawGet[A, B](t: PHashTable[A, B], key: A): int =
     h = nextTry(h, high(t.data))
   result = -1
 
-proc `[]`*[A, B](t: PHashTable[A, B], key: A): B =
+template rawInsertImpl() =
+  var h: THash = hash(key) and high(data)
+  while data[h].slot == seFilled:
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+  data[h].slot = seFilled
+
+proc RawGet[A, B](t: THashTable[A, B], key: A): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: THashTable[A, B], key: A): B =
   ## retrieves the value at ``t[key]``. If `key` is not in `t`,
   ## default empty value for the type `B` is returned
   ## and no exception is raised. One can check with ``hasKey`` whether the key
@@ -68,28 +79,22 @@ proc `[]`*[A, B](t: PHashTable[A, B], key: A): B =
   var index = RawGet(t, key)
   if index >= 0: result = t.data[index].val
 
-proc hasKey*[A, B](t: PHashTable[A, B], key: A): bool =
+proc hasKey*[A, B](t: THashTable[A, B], key: A): bool =
   ## returns true iff `key` is in the table `t`.
   result = rawGet(t, key) >= 0
 
-proc RawInsert[A, B](t: PHashTable[A, B], data: var TKeyValuePairSeq[A, B],
+proc RawInsert[A, B](t: var THashTable[A, B], data: var TKeyValuePairSeq[A, B],
                      key: A, val: B) =
-  var h: THash = hash(key) and high(data)
-  while data[h].slot == seFilled:
-    h = nextTry(h, high(data))
-  data[h].key = key
-  data[h].val = val
-  data[h].slot = seFilled
+  rawInsertImpl()
 
-proc Enlarge[A, B](t: PHashTable[A, B]) =
+proc Enlarge[A, B](t: var THashTable[A, B]) =
   var n: TKeyValuePairSeq[A, B]
   newSeq(n, len(t.data) * growthFactor)
   for i in countup(0, high(t.data)):
     if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
   swap(t.data, n)
 
-proc `[]=`*[A, B](t: PHashTable[A, B], key: A, val: B) =
-  ## puts a (key, value)-pair into `t`.
+template PutImpl() =
   var index = RawGet(t, key)
   if index >= 0:
     t.data[index].val = val
@@ -98,23 +103,25 @@ proc `[]=`*[A, B](t: PHashTable[A, B], key: A, val: B) =
     RawInsert(t, t.data, key, val)
     inc(t.counter)
 
-proc del*[A, B](t: PHashTable[A, B], key: A) =
+proc `[]=`*[A, B](t: var THashTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc del*[A, B](t: var THashTable[A, B], key: A) =
   ## deletes `key` from hash table `t`.
   var index = RawGet(t, key)
   if index >= 0:
     t.data[index].slot = seDeleted
     dec(t.counter)
 
-proc newHashTable*[A, B](initialSize = 64): PHashTable[A, B] =
+proc initHashTable*[A, B](initialSize = 64): THashTable[A, B] =
   ## creates a new string table that is empty. `initialSize` needs to be
   ## a power of two.
   assert isPowerOfTwo(initialSize)
-  new(result)
   result.counter = 0
   newSeq(result.data, initialSize)
 
-proc `$`*[A, B](t: PHashTable[A, B]): string =
-  ## The `$` operator for string tables.
+template dollarImpl(): stmt =
   if t.len == 0:
     result = "{:}"
   else:
@@ -126,6 +133,108 @@ proc `$`*[A, B](t: PHashTable[A, B]): string =
       result.add($val)
     result.add("}")
 
+proc `$`*[A, B](t: THashTable[A, B]): string =
+  ## The `$` operator for string tables.
+  dollarImpl()
+
+# ------------------------------ ordered table ------------------------------
+
+type
+  TOrderedKeyValuePair[A, B] = tuple[
+    slot: TSlotEnum, next: int, key: A, val: B]
+  TOrderedKeyValuePairSeq[A, B] = seq[TOrderedKeyValuePair[A, B]]
+  TOrderedHashTable*[A, B] {.final.} = object
+    data: TOrderedKeyValuePairSeq[A, B]
+    counter, first, last: int
+
+proc len*[A, B](t: TOrderedHashTable[A, B]): int {.inline.} =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+template forAllOrderedPairs(yieldStmt: stmt) =
+  var i = t.first
+  while i >= 0:
+    var nxt = t.data[i].next
+    if t.data[h].slot == seFilled: yieldStmt
+    i = nxt
+
+iterator pairs*[A, B](t: TOrderedHashTable[A, B]): tuple[key: A, val: B] =
+  ## iterates over any (key, value) pair in the table `t` in insertion
+  ## order.
+  forAllOrderedPairs:
+    yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: TOrderedHashTable[A, B]): A =
+  ## iterates over any key in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].key
+
+iterator values*[A, B](t: TOrderedHashTable[A, B]): B =
+  ## iterates over any value in the table `t` in insertion order.
+  forAllOrderedPairs:
+    yield t.data[h].val
+
+proc RawGet[A, B](t: TOrderedHashTable[A, B], key: A): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: TOrderedHashTable[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A, B](t: TOrderedHashTable[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc RawInsert[A, B](t: TOrderedHashTable[A, B], 
+                     data: var TOrderedKeyValuePairSeq[A, B],
+                     key: A, val: B) =
+  rawInsertImpl()
+  data[h].next = -1
+  if first < 0: first = h
+  if last >= 0: data[last].next = h
+  lastEntry = h
+
+proc Enlarge[A, B](t: TOrderedHashTable[A, B]) =
+  var n: TOrderedKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  forAllOrderedPairs:
+    RawInsert(t, n, t.data[h].key, t.data[h].val)
+  swap(t.data, n)
+
+proc `[]=`*[A, B](t: TOrderedHashTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  var index = RawGet(t, key)
+  if index >= 0:
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter): Enlarge(t)
+    RawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc del*[A, B](t: TOrderedHashTable[A, B], key: A) =
+  ## deletes `key` from hash table `t`.
+  var index = RawGet(t, key)
+  if index >= 0:
+    t.data[index].slot = seDeleted
+    dec(t.counter)
+
+proc initHashTable*[A, B](initialSize = 64): TOrderedHashTable[A, B] =
+  ## creates a new string table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  result.first = -1
+  result.last = -1
+  newSeq(result.data, initialSize)
+
+proc `$`*[A, B](t: TOrderedHashTable[A, B]): string =
+  ## The `$` operator for hash tables.
+  dollarImpl()
+
 # ------------------------------ count tables -------------------------------
 
 const
diff --git a/lib/pure/strtabs.nim b/lib/pure/strtabs.nim
index f88560304..78f489615 100755
--- a/lib/pure/strtabs.nim
+++ b/lib/pure/strtabs.nim
@@ -142,19 +142,18 @@ proc newStringTable*(mode: TStringTableMode): PStringTable {.
   result.counter = 0
   newSeq(result.data, startSize)
 
-when false:
-  proc newStringTable(keyValuePairs: openarray[string],
-                       mode = modeCaseSensitive): PStringTable {.
-    rtl, extern: "nst$1WithPairs".} =
-    ## creates a new string table with given key value pairs.
-    ## Example::
-    ##   var mytab = newStringTable("key1", "val1", "key2", "val2",
-    ##                              modeCaseInsensitive)
-    result = newStringTable(mode)
-    var i = 0
-    while i < high(keyValuePairs):
-      result[keyValuePairs[i]] = keyValuePairs[i + 1]
-      inc(i, 2)
+proc newStringTable*(keyValuePairs: openarray[string],
+                     mode: TStringTableMode): PStringTable {.
+  rtl, extern: "nst$1WithPairs".} =
+  ## creates a new string table with given key value pairs.
+  ## Example::
+  ##   var mytab = newStringTable("key1", "val1", "key2", "val2",
+  ##                              modeCaseInsensitive)
+  result = newStringTable(mode)
+  var i = 0
+  while i < high(keyValuePairs):
+    result[keyValuePairs[i]] = keyValuePairs[i + 1]
+    inc(i, 2)
 
 proc newStringTable*(keyValuePairs: openarray[tuple[key, val: string]],
                      mode: TStringTableMode = modeCaseSensitive): PStringTable {.
diff --git a/lib/system.nim b/lib/system.nim
index 815d14fa4..bacb4325a 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1349,7 +1349,7 @@ template accumulateResult*(iter: expr) =
 # we have to compute this here before turning it off in except.nim anyway ...
 const nimrodStackTrace = compileOption("stacktrace")
 
-{.push checks: off, line_dir: off, debugger: off.}  
+{.push checks: off, line_dir: off, debugger: off.}
 # obviously we cannot generate checking operations here :-)
 # because it would yield into an endless recursion
 # however, stack-traces are available for most parts
diff --git a/lib/system/hti.nim b/lib/system/hti.nim
index 3343000ae..d22109061 100755
--- a/lib/system/hti.nim
+++ b/lib/system/hti.nim
@@ -45,7 +45,9 @@ type # This should be he same as ast.TTypeKind
 
   TNimTypeFlag = enum 
     ntfNoRefs = 0,     # type contains no tyRef, tySequence, tyString
-    ntfAcyclic = 1     # type cannot form a cycle
+    ntfAcyclic = 1,    # type cannot form a cycle
+    ntfEnumHole = 2    # enum has holes and thus `$` for them needs the slow
+                       # version
   TNimType {.compilerproc, final.} = object
     size: int
     kind: TNimKind
diff --git a/lib/system/repr.nim b/lib/system/repr.nim
index a70989cad..87588421f 100755
--- a/lib/system/repr.nim
+++ b/lib/system/repr.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2010 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -53,10 +53,16 @@ proc reprChar(x: char): string {.compilerRtl.} =
   add result, "\'"
 
 proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
-  if e <% typ.node.len: # BUGFIX
-    result = $typ.node.sons[e].name
+  if ntfEnumHole notin typ.flags:
+    if e <% typ.node.len:
+      return $typ.node.sons[e].name
   else:
-    result = $e & " (invalid data!)"
+    # ugh we need a slow linear search:
+    var n = typ.node
+    var s = n.sons
+    for i in 0 .. n.len-1:
+      if s[i].offset == e: return $s[i].name
+  result = $e & " (invalid data!)"
 
 type
   pbyteArray = ptr array[0.. 0xffff, byte]
diff --git a/tests/accept/compile/tcan_alias_specialised_generic.nim b/tests/accept/compile/tcan_alias_specialised_generic.nim
index 9e93e7266..a8f1972c8 100644
--- a/tests/accept/compile/tcan_alias_specialised_generic.nim
+++ b/tests/accept/compile/tcan_alias_specialised_generic.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 ##
 ## can_alias_specialised_generic Nimrod Module
 ##
diff --git a/tests/accept/compile/tconsteval.nim b/tests/accept/compile/tconsteval.nim
index ce90d7c27..10af9ad35 100755
--- a/tests/accept/compile/tconsteval.nim
+++ b/tests/accept/compile/tconsteval.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 import strutils
 
 const
diff --git a/tests/accept/compile/tdictdestruct.nim b/tests/accept/compile/tdictdestruct.nim
index 8d828aaf7..9c1f27ed8 100755
--- a/tests/accept/compile/tdictdestruct.nim
+++ b/tests/accept/compile/tdictdestruct.nim
@@ -1,3 +1,6 @@
+discard """
+  disabled: true
+"""
 
 type
   TDict[TK, TV] = object
diff --git a/tests/accept/compile/tgenericmatcher.nim b/tests/accept/compile/tgenericmatcher.nim
index eaf3da67c..6ff0dd505 100644
--- a/tests/accept/compile/tgenericmatcher.nim
+++ b/tests/accept/compile/tgenericmatcher.nim
@@ -1,3 +1,6 @@
+discard """
+  disabled: true
+"""
 
 type
   TMatcherKind = enum
diff --git a/tests/accept/compile/tgenericrefs.nim b/tests/accept/compile/tgenericrefs.nim
index b0e77cef5..2a3de7edd 100644
--- a/tests/accept/compile/tgenericrefs.nim
+++ b/tests/accept/compile/tgenericrefs.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 # Compiles:
 
 type 
diff --git a/tests/accept/compile/tlexer.nim b/tests/accept/compile/tlexer.nim
index 968a10bdf..10a8ab51d 100755
--- a/tests/accept/compile/tlexer.nim
+++ b/tests/accept/compile/tlexer.nim
@@ -1,3 +1,7 @@
+discard """

+  disabled: true

+"""

+

 # We start with a comment

 # This is the same comment

 

diff --git a/tests/accept/compile/tmodulealias.nim b/tests/accept/compile/tmodulealias.nim
index 1154cb99d..a7d155e51 100755
--- a/tests/accept/compile/tmodulealias.nim
+++ b/tests/accept/compile/tmodulealias.nim
@@ -1,4 +1,6 @@
-
+discard """
+  disabled: true
+"""
 
 when defined(windows):
   import winlean
diff --git a/tests/accept/compile/toop.nim b/tests/accept/compile/toop.nim
index d103c6304..db6d9e595 100755
--- a/tests/accept/compile/toop.nim
+++ b/tests/accept/compile/toop.nim
@@ -1,3 +1,6 @@
+discard """
+  disabled: true
+"""
 
 type
   TA = object
diff --git a/tests/accept/compile/trectuple.nim b/tests/accept/compile/trectuple.nim
index c9ac45797..f60fe2841 100755
--- a/tests/accept/compile/trectuple.nim
+++ b/tests/accept/compile/trectuple.nim
@@ -1,3 +1,7 @@
+discard """
+  disabled: true
+"""
+
 type
     PNode = ref TNode
     TNode = tuple[self: PNode]
diff --git a/tests/accept/compile/tsortdev.nim b/tests/accept/compile/tsortdev.nim
index 1246d7581..c4e63fab4 100755
--- a/tests/accept/compile/tsortdev.nim
+++ b/tests/accept/compile/tsortdev.nim
@@ -1,3 +1,6 @@
+discard """
+  disabled: true
+"""
 
 import math, algorithm
 
diff --git a/tests/accept/compile/tstrtabs.nim b/tests/accept/compile/tstrtabs.nim
index 299db609d..251ec77ef 100755
--- a/tests/accept/compile/tstrtabs.nim
+++ b/tests/accept/compile/tstrtabs.nim
@@ -1,6 +1,6 @@
 import strtabs
 
-var tab = newStringTable(["key1", "val1", "key2", "val2"], 
+var tab = newStringTable({"key1": "val1", "key2": "val2"}, 
                          modeStyleInsensitive)
 for i in 0..80:
   tab["key_" & $i] = "value" & $i
diff --git a/tests/accept/compile/ttempl3.nim b/tests/accept/compile/ttempl3.nim
index 0c8fa9a94..7b2c70f79 100755
--- a/tests/accept/compile/ttempl3.nim
+++ b/tests/accept/compile/ttempl3.nim
@@ -24,3 +24,19 @@ var
 ha = 1  
 echo(ha)
 
+
+# Test identifier generation:
+template prefix(name: expr): expr = `"hu" name`
+
+var `hu "XYZ"` = "yay"
+
+echo prefix(XYZ)
+
+template typedef(name: expr, typ: typeDesc) = 
+  type
+    `T name`* = typ
+    `P name`* = ref `T name`
+    
+typedef(myint, int)
+var x: PMyInt
+
diff --git a/tests/accept/run/tassert.nim b/tests/accept/run/tassert.nim
index e32ee0a84..50793c3d6 100755
--- a/tests/accept/run/tassert.nim
+++ b/tests/accept/run/tassert.nim
@@ -1,22 +1,22 @@
 discard """
   file: "tassert.nim"
-  output: "assertion failure!this shall be always written"
+  outputsub: "assertion failure!this shall be always written"
 """
-# test assert and exception handling

-

-proc callB() = assert(False)

-proc callA() = callB()

-proc callC() = callA()

-

-try:

-  callC()

-except EAssertionFailed:

-  write(stdout, "assertion failure!")

-except:

-  write(stdout, "unknown exception!")

-finally:

-  system.write(stdout, "this shall be always written")

-

-assert(false) #OUT assertion failure!this shall be always written

+# test assert and exception handling
+
+proc callB() = assert(False)
+proc callA() = callB()
+proc callC() = callA()
+
+try:
+  callC()
+except EAssertionFailed:
+  write(stdout, "assertion failure!")
+except:
+  write(stdout, "unknown exception!")
+finally:
+  system.write(stdout, "this shall be always written")
+
+assert(false) #OUT assertion failure!this shall be always written
 
 
diff --git a/tests/accept/run/tcgbug.nim b/tests/accept/run/tcgbug.nim
index aa0f0fa6b..417b909ae 100755
--- a/tests/accept/run/tcgbug.nim
+++ b/tests/accept/run/tcgbug.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tcgbug.nim"
-  output: ""
+  output: "success"
 """
 
 type
@@ -19,5 +19,5 @@ var
 new(a)
 q(a)
 
-
+echo "success"
 
diff --git a/tests/accept/run/tclosure.nim b/tests/accept/run/tclosure.nim
index 28a51e1ac..d7c0ec0e3 100755
--- a/tests/accept/run/tclosure.nim
+++ b/tests/accept/run/tclosure.nim
@@ -1,6 +1,7 @@
 discard """
   file: "tclosure.nim"
   output: "2 4 6 8 10"
+  disabled: true
 """
 # Test the closure implementation
 
diff --git a/tests/accept/run/tcontinuexc.nim b/tests/accept/run/tcontinuexc.nim
index c43e68c93..82cce923e 100755
--- a/tests/accept/run/tcontinuexc.nim
+++ b/tests/accept/run/tcontinuexc.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tcontinuexc.nim"
-  output: "ECcaught"
+  outputsub: "ECcaught"
 """
 type
   ESomething = object of E_Base
diff --git a/tests/accept/run/texcsub.nim b/tests/accept/run/texcsub.nim
index 3dba357f9..e78da8df6 100755
--- a/tests/accept/run/texcsub.nim
+++ b/tests/accept/run/texcsub.nim
@@ -1,6 +1,7 @@
 discard """
   file: "texcsub.nim"
   output: "caught!"
+  disabled: true
 """
 # Test inheritance for exception matching:
 
diff --git a/tests/accept/run/texplicitgeneric2.nim b/tests/accept/run/texplicitgeneric2.nim
index f2e628223..95461d023 100755
--- a/tests/accept/run/texplicitgeneric2.nim
+++ b/tests/accept/run/texplicitgeneric2.nim
@@ -1,5 +1,6 @@
 discard """
   output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13"
+  disabled: true
 """
 
 # test explicit type instantiation
diff --git a/tests/accept/run/tfloat1.nim b/tests/accept/run/tfloat1.nim
index 3826bf1f5..7d6e0c6a3 100755
--- a/tests/accept/run/tfloat1.nim
+++ b/tests/accept/run/tfloat1.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tfloat1.nim"
-  output: "Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]"
+  outputsub: "Error: unhandled exception: FPU operation caused an overflow [EFloatOverflow]"
 """
 # Test new floating point exceptions
 
diff --git a/tests/accept/run/tfloat2.nim b/tests/accept/run/tfloat2.nim
index e7a9ce76f..b0df1e8b7 100755
--- a/tests/accept/run/tfloat2.nim
+++ b/tests/accept/run/tfloat2.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tfloat2.nim"
-  output: "Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]"
+  outputsub: "Error: unhandled exception: FPU operation caused a NaN result [EFloatInvalidOp]"
 """
 # Test new floating point exceptions
 
diff --git a/tests/accept/run/tgenerics1.nim b/tests/accept/run/tgenerics1.nim
index cb310f552..5d20a864b 100755
--- a/tests/accept/run/tgenerics1.nim
+++ b/tests/accept/run/tgenerics1.nim
@@ -41,7 +41,7 @@ proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
 
 proc print*[T](heap: PBinHeap[T]) =
   for i in countup(0, heap.last):
-    echo heap.heap[i].data
+    stdout.write($heap.heap[i].data, " ")
 
 var
   heap: PBinHeap[int]
diff --git a/tests/accept/run/tmatrix.nim b/tests/accept/run/tmatrix.nim
index 1dd09291b..90dfde959 100755
--- a/tests/accept/run/tmatrix.nim
+++ b/tests/accept/run/tmatrix.nim
@@ -19,30 +19,12 @@ proc createMatrix*(width, height: int): TMatrix =
 proc width*(m: TMatrix): int {.inline.} = return m.fWidth
 proc height*(m: TMatrix): int {.inline.} = return m.fHeight
 
-proc `[,]`*(m: TMatrix, x, y: int): float {.inline.} =
+proc `[]`*(m: TMatrix, x, y: int): float {.inline.} =
   result = m.data[x|y]
 
-proc `[,]=`*(m: var TMatrix, x, y: int, val: float) {.inline.} =
+proc `[]=`*(m: var TMatrix, x, y: int, val: float) {.inline.} =
   m.data[x|y] = val
   
-proc `[$ .. $, $ .. $]`*(m: TMatrix, a, b, c, d: int): TMatrix =
-  result = createMatrix(b-a+1, d-c+1)
-  for x in a..b:
-    for y in c..d:
-      result[x-a, y-c] = m[x, y]
-
-proc `[$ .. $, $ .. $]=`*(m: var TMatrix, a, b, c, d: int, val: float) =
-  for x in a..b:
-    for y in c..d:
-      m[x, y] = val
-
-proc `[$ .. $, $ .. $]=`*(m: var TMatrix, a, b, c, d: int, val: TMatrix) =
-  assert val.width == b-a+1
-  assert val.height == d-c+1
-  for x in a..b:
-    for y in c..d:
-      m[x, y] = val[x-a, y-c]
-
 proc `-|`*(m: TMatrix): TMatrix =
   ## transposes a matrix
   result = createMatrix(m.height, m.width)
diff --git a/tests/accept/run/toverflw2.nim b/tests/accept/run/toverflw2.nim
index 14a77ebad..075eae9e9 100755
--- a/tests/accept/run/toverflw2.nim
+++ b/tests/accept/run/toverflw2.nim
@@ -1,6 +1,6 @@
 discard """
   file: "toverflw2.nim"
-  output: "Error: unhandled exception: over- or underflow [EOverflow]"
+  outputsub: "Error: unhandled exception: over- or underflow [EOverflow]"
 """
 var a : int32 = 2147483647
 var b : int32 = 2147483647
diff --git a/tests/accept/run/treraise.nim b/tests/accept/run/treraise.nim
index 7e147c336..71736b512 100755
--- a/tests/accept/run/treraise.nim
+++ b/tests/accept/run/treraise.nim
@@ -1,6 +1,6 @@
 discard """
   file: "treraise.nim"
-  output: "Error: unhandled exception: bla [ESomeOtherErr]"
+  outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
 """
 type
   ESomething = object of E_Base
diff --git a/tests/accept/run/tunhandledexc.nim b/tests/accept/run/tunhandledexc.nim
index c60de2234..ae62b4ee5 100755
--- a/tests/accept/run/tunhandledexc.nim
+++ b/tests/accept/run/tunhandledexc.nim
@@ -1,6 +1,6 @@
 discard """
   file: "tunhandledexc.nim"
-  output: "Error: unhandled exception: bla [ESomeOtherErr]"
+  outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
 """
 type
   ESomething = object of E_Base
diff --git a/tests/accept/run/twrongexc.nim b/tests/accept/run/twrongexc.nim
index 592693769..81f4d5595 100755
--- a/tests/accept/run/twrongexc.nim
+++ b/tests/accept/run/twrongexc.nim
@@ -1,6 +1,6 @@
 discard """
   file: "twrongexc.nim"
-  output: "Error: unhandled exception [EInvalidValue]"
+  outputsub: "Error: unhandled exception [EInvalidValue]"
 """
 try:
   raise newException(EInvalidValue, "")
diff --git a/tests/reject/tnot.nim b/tests/reject/tnot.nim
index 8075a4768..1985ef666 100755
--- a/tests/reject/tnot.nim
+++ b/tests/reject/tnot.nim
@@ -1,6 +1,5 @@
 discard """
   file: "system.nim"
-  line: 599
   errormsg: "type mismatch"
 """
 # BUG: following compiles, but should not:
diff --git a/tests/reject/trectype.nim b/tests/reject/trectype.nim
index b8b23a806..7bb12a3b6 100755
--- a/tests/reject/trectype.nim
+++ b/tests/reject/trectype.nim
@@ -1,6 +1,4 @@
 discard """
-  file: "trectype.nim"
-  line: 25
   errormsg: "internal error: cannot generate C type for: PA"
 """
 # Test recursive type descriptions
diff --git a/tests/reject/ttypelessemptyset.nim b/tests/reject/ttypelessemptyset.nim
index 68bfb0249..3e171387b 100755
--- a/tests/reject/ttypelessemptyset.nim
+++ b/tests/reject/ttypelessemptyset.nim
@@ -1,11 +1,6 @@
 discard """
-  file: "ttypelessemptyset.nim"
-  line: 5
   errormsg: "internal error: invalid kind for last(tyEmpty)"
 """
 var q = false
 discard (if q: {} else: {})
 
-
-
-
diff --git a/tests/tester.nim b/tests/tester.nim
index 00fe7909a..9e5028567 100755
--- a/tests/tester.nim
+++ b/tests/tester.nim
@@ -27,6 +27,7 @@ type
     msg: string
     err: bool
     disabled: bool
+    substr: bool
   TResults {.pure.} = object
     total, passed, skipped: int
     data: string
@@ -53,7 +54,7 @@ proc extractSpec(filename: string): string =
   if a >= 0 and b > a: 
     result = x.copy(a+3, b-1).replace("'''", tripleQuote)
   else:
-    echo "warning: file does not contain spec: " & filename
+    #echo "warning: file does not contain spec: " & filename
     result = ""
 
 template parseSpecAux(fillResult: stmt) = 
@@ -87,6 +88,9 @@ proc parseSpec(filename: string): TSpec =
     of "file": result.file = e.value
     of "line": discard parseInt(e.value, result.line)
     of "output": result.outp = e.value
+    of "outputsub":
+      result.outp = e.value
+      result.substr = true
     of "errormsg", "msg": result.msg = e.value
     of "disabled": result.disabled = parseCfgBool(e.value)
     of "cmd": result.cmd = e.value
@@ -184,9 +188,10 @@ proc listResults(reject, compile, run: TResults) =
 proc cmpMsgs(r: var TResults, expected, given: TSpec, test: string) = 
   if strip(expected.msg) notin strip(given.msg):
     r.addResult(test, expected.msg, given.msg, reFailure)
-  elif extractFilename(expected.file) != extractFilename(given.file):
+  elif extractFilename(expected.file) != extractFilename(given.file) and
+      "internal error:" notin expected.msg:
     r.addResult(test, expected.file, given.file, reFailure)
-  elif expected.line != given.line: 
+  elif expected.line != given.line and expected.line != 0:
     r.addResult(test, $expected.line, $given.line, reFailure)
   else:
     r.addResult(test, expected.msg, given.msg, reSuccess)
@@ -206,7 +211,21 @@ proc reject(r: var TResults, dir, options: string) =
       var given = callCompiler(expected.cmd, test, options)
       cmpMsgs(r, expected, given, t)
   
-proc compile(r: var TResults, pattern, options: string) = 
+proc compile(r: var TResults, pattern, options: string) =
+  for test in os.walkFiles(pattern):
+    var t = extractFilename(test)
+    echo t
+    inc(r.total)
+    var expected = parseSpec(test)
+    if expected.disabled:
+      r.addResult(t, "", reIgnored)
+      inc(r.skipped)
+    else:
+      var given = callCompiler(expected.cmd, test, options)
+      r.addResult(t, given.msg, if given.err: reFailure else: reSuccess)
+      if not given.err: inc(r.passed)
+  
+proc compileExample(r: var TResults, pattern, options: string) = 
   for test in os.walkFiles(pattern): 
     var t = extractFilename(test)
     inc(r.total)
@@ -233,6 +252,7 @@ proc run(r: var TResults, dir, options: string) =
         if existsFile(exeFile):
           var buf = myExec(exeFile)
           var success = strip(buf) == strip(expected.outp)
+          if expected.substr: success = expected.outp in buf
           if success: inc(r.passed)
           r.addResult(t, expected.outp, 
               buf, if success: reSuccess else: reFailure)
@@ -250,8 +270,8 @@ for i in 1.. paramCount():
 
 reject(rejectRes, "tests/reject", options)
 compile(compileRes, "tests/accept/compile/t*.nim", options)
-compile(compileRes, "examples/*.nim", options)
-compile(compileRes, "examples/gtk/*.nim", options)
+compileExample(compileRes, "examples/*.nim", options)
+compileExample(compileRes, "examples/gtk/*.nim", options)
 run(runRes, "tests/accept/run", options)
 listResults(rejectRes, compileRes, runRes)
 openDefaultBrowser(resultsFile)
diff --git a/todo.txt b/todo.txt
index f673f4118..2d4ce4c60 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,4 +1,3 @@
-- clean up the tests!
 - implicit ref/ptr->var conversion
 - warning for implicit openArray -> varargs convention
 - implement explicit varargs
@@ -7,6 +6,8 @@
 High priority (version 0.9.0)
 =============================
 
+- tests: run modules that contain "when isMainModule", compile the other
+  modules; run the GC tests
 - fix implicit generic routines
 - fix the streams implementation so that it uses methods
 - fix overloading resolution
@@ -50,7 +51,6 @@ Low priority
   is hard because of partial evaluation --> symbol files will fix this as
   a side effect
 - floating point checks for EcmaScript
-- enhance `` notation for identifier concatenation: `concat` a `these`
 - prefer proc in current module over other procs with same overloading result?
 - real types for template results
 - generalized case statement (requires better transf)