summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-03-14 23:57:41 +0100
committerAraq <rumpf_a@web.de>2011-03-14 23:57:41 +0100
commit8d734244b14e09c97267432468ac20fcf8ff82eb (patch)
tree253eae61df789c42efe49b7c30cf38c66a3c208e
parent6850fb73c1b9ae8d3f56a61ee37922c3cb3788d6 (diff)
downloadNim-8d734244b14e09c97267432468ac20fcf8ff82eb.tar.gz
linearScanEnd pragma; string case statement optimization
-rwxr-xr-xbuild.bat10
-rwxr-xr-xdoc/manual.txt47
-rwxr-xr-xdoc/nimrodc.txt24
-rwxr-xr-xinstall.sh6
-rwxr-xr-xlib/pure/strutils.nim9
-rwxr-xr-xlib/system.nim4
-rwxr-xr-xlib/system/assign.nim21
-rwxr-xr-xlib/system/inclrtl.nim2
-rwxr-xr-xlib/system/sysstr.nim2
-rwxr-xr-xrod/ast.nim3
-rwxr-xr-xrod/ccgexprs.nim13
-rwxr-xr-xrod/ccgstmts.nim195
-rwxr-xr-xrod/ccgutils.nim96
-rwxr-xr-xrod/cgen.nim19
-rwxr-xr-xrod/main.nim36
-rwxr-xr-xrod/pragmas.nim23
-rwxr-xr-xrod/rst.nim14
-rwxr-xr-xrod/semexprs.nim13
-rwxr-xr-xrod/semtypes.nim3
-rwxr-xr-xrod/transf.nim4
-rwxr-xr-xrod/wordrecg.nim30
-rw-r--r--tests/accept/compile/tfib.nim11
-rw-r--r--tests/accept/run/tsort.nim185
-rw-r--r--tests/accept/run/ttoseq.nim12
-rwxr-xr-xtodo.txt1
-rwxr-xr-xweb/news.txt6
26 files changed, 537 insertions, 252 deletions
diff --git a/build.bat b/build.bat
index b4e46d3f0..34086269c 100755
--- a/build.bat
+++ b/build.bat
@@ -123,6 +123,10 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o
 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/procfind.c -o build/1_1/procfind.o

 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o

 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/pragmas.c -o build/1_1/pragmas.o

+ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/semtypinst.c -o build/1_1/semtypinst.o

+%CC% %COMP_FLAGS% -Ibuild -c build/1_1/semtypinst.c -o build/1_1/semtypinst.o

+ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/sigmatch.c -o build/1_1/sigmatch.o

+%CC% %COMP_FLAGS% -Ibuild -c build/1_1/sigmatch.c -o build/1_1/sigmatch.o

 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o

 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/suggest.c -o build/1_1/suggest.o

 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/docgen.c -o build/1_1/docgen.o

@@ -139,8 +143,6 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o
 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/cgmeth.c -o build/1_1/cgmeth.o

 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o

 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/ecmasgen.c -o build/1_1/ecmasgen.o

-ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/interact.c -o build/1_1/interact.o

-%CC% %COMP_FLAGS% -Ibuild -c build/1_1/interact.c -o build/1_1/interact.o

 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o

 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/passaux.c -o build/1_1/passaux.o

 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/depends.c -o build/1_1/depends.o

@@ -150,8 +152,8 @@ ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/transf.c -o build/1_1/transf.o
 ECHO %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o

 %CC% %COMP_FLAGS% -Ibuild -c build/1_1/parseopt.c -o build/1_1/parseopt.o

 

-ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe  build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o

-%LINKER% %LINK_FLAGS% -o bin\nimrod.exe  build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/interact.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o

+ECHO %LINKER% %LINK_FLAGS% -o bin\nimrod.exe  build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/semtypinst.o build/1_1/sigmatch.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o

+%LINKER% %LINK_FLAGS% -o bin\nimrod.exe  build/1_1/nim__dat.o build/1_1/system.o build/1_1/nimrod.o build/1_1/times.o build/1_1/strutils.o build/1_1/parseutils.o build/1_1/winlean.o build/1_1/commands.o build/1_1/os.o build/1_1/msgs.o build/1_1/options.o build/1_1/lists.o build/1_1/nstrtabs.o build/1_1/nhashes.o build/1_1/nversion.o build/1_1/condsyms.o build/1_1/ast.o build/1_1/crc.o build/1_1/ropes.o build/1_1/platform.o build/1_1/idents.o build/1_1/astalgo.o build/1_1/rodutils.o build/1_1/extccomp.o build/1_1/osproc.o build/1_1/strtabs.o build/1_1/hashes.o build/1_1/streams.o build/1_1/wordrecg.o build/1_1/scanner.o build/1_1/lexbase.o build/1_1/llstream.o build/1_1/nimconf.o build/1_1/main.o build/1_1/syntaxes.o build/1_1/pnimsyn.o build/1_1/pbraces.o build/1_1/ptmplsyn.o build/1_1/rnimsyn.o build/1_1/filters.o build/1_1/rodread.o build/1_1/rodwrite.o build/1_1/passes.o build/1_1/types.o build/1_1/trees.o build/1_1/math.o build/1_1/magicsys.o build/1_1/nimsets.o build/1_1/bitsets.o build/1_1/importer.o build/1_1/lookups.o build/1_1/semdata.o build/1_1/treetab.o build/1_1/sem.o build/1_1/evals.o build/1_1/semfold.o build/1_1/procfind.o build/1_1/pragmas.o build/1_1/semtypinst.o build/1_1/sigmatch.o build/1_1/suggest.o build/1_1/docgen.o build/1_1/rst.o build/1_1/highlite.o build/1_1/cgen.o build/1_1/ccgutils.o build/1_1/cgmeth.o build/1_1/ecmasgen.o build/1_1/passaux.o build/1_1/depends.o build/1_1/transf.o build/1_1/parseopt.o

 

 ECHO SUCCESS

 

diff --git a/doc/manual.txt b/doc/manual.txt
index 49311fb43..975094a56 100755
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -2646,6 +2646,53 @@ hint pragma
 -----------

 The `hint`:idx: pragma is used to make the compiler output a hint message with

 the given content. Compilation continues after the hint.

+
+
+linearScanEnd pragma
+--------------------
+The `linearScanEnd`:idx: pragma can be used to tell the compiler how to 
+compile a Nimrod `case`:idx: statement. Syntactially it has to be used as a
+statement:
+
+.. code-block:: nimrod
+  case myInt
+  of 0: 
+    echo "most common case"
+  of 1: 
+    {.linearScanEnd.}
+    echo "second most common case"
+  of 2: echo "unlikely: use branch table"
+  else: echo "unlikely too: use branch table for ", myInt
+
+In the example, the case branches ``0`` and ``1`` are much more common than 
+the other cases. Therefore the generated assembler code should test for these 
+values first, so that the CPU's branch predictor has a good chance to succeed 
+(avoiding an expensive CPU pipeline stall). The other cases might be put into a
+jump table for O(1) overhead, but at the cost of a (very likely) pipeline
+stall. 
+
+The ``linearScanEnd`` pragma should be put into the last branch that should be
+tested against via linear scanning. If put into the last branch of the
+whole ``case`` statement, the whole ``case`` statement uses linear scanning.
+
+
+unroll pragma
+-------------
+The `unroll`:idx: pragma can be used to tell the compiler that it should unroll
+a `for`:idx: or `while`:idx: loop for runtime efficiency: 
+
+.. code-block:: nimrod
+  proc searchChar(s: string, c: char): int = 
+    for i in 0 .. s.high:
+      {.unroll: 4.}
+      if s[i] == c: return i
+    result = -1
+
+In the above example, the search loop is unrolled by a factor 4. The unroll
+factor can be left out too; the compiler then chooses an appropriate unroll
+factor.
+
+**Note**: Currently the compiler recognizes but ignores this pragma.
 

 

 compilation option pragmas

diff --git a/doc/nimrodc.txt b/doc/nimrodc.txt
index c8cbbaa73..b30071b4e 100755
--- a/doc/nimrodc.txt
+++ b/doc/nimrodc.txt
@@ -293,10 +293,26 @@ However it is not efficient to do:
 .. code-block:: Nimrod

   var s = varA    # assignment has to copy the whole string into a new buffer!

 

-..

-  String case statements are optimized too. A hashing scheme is used for them

-  if several different string constants are used. This is likely to be more

-  efficient than any hand-coded scheme.

+The compiler optimizes string case statements: A hashing scheme is used for them

+if several different string constants are used. So code like this is reasonably
+efficient:
+
+.. code-block:: Nimrod
+  case normalize(k.key)
+  of "name": c.name = v
+  of "displayname": c.displayName = v
+  of "version": c.version = v
+  of "os": c.oses = split(v, {';'})
+  of "cpu": c.cpus = split(v, {';'})
+  of "authors": c.authors = split(v, {';'})
+  of "description": c.description = v
+  of "app":
+    case normalize(v)
+    of "console": c.app = appConsole
+    of "gui": c.app = appGUI
+    else: quit(errorStr(p, "expected: console or gui"))
+  of "license": c.license = UnixToNativePath(k.value)
+  else: quit(errorStr(p, "unknown variable: " & k.key))

 

 

 ..

diff --git a/install.sh b/install.sh
index 16d646f56..60ec70ca1 100755
--- a/install.sh
+++ b/install.sh
@@ -88,8 +88,6 @@ if [ $# -eq 1 ] ; then
   chmod 644 $docdir/abstypes.txt
   cp doc/advopt.txt $docdir/advopt.txt || exit 1
   chmod 644 $docdir/advopt.txt
-  cp doc/altsyn.txt $docdir/altsyn.txt || exit 1
-  chmod 644 $docdir/altsyn.txt
   cp doc/apis.txt $docdir/apis.txt || exit 1
   chmod 644 $docdir/apis.txt
   cp doc/astspec.txt $docdir/astspec.txt || exit 1
@@ -330,6 +328,8 @@ if [ $# -eq 1 ] ; then
   chmod 644 $libdir/core/marshal.nim
   cp lib/core/threads.nim $libdir/core/threads.nim || exit 1
   chmod 644 $libdir/core/threads.nim
+  cp lib/pure/algorithm.nim $libdir/pure/algorithm.nim || exit 1
+  chmod 644 $libdir/pure/algorithm.nim
   cp lib/pure/base64.nim $libdir/pure/base64.nim || exit 1
   chmod 644 $libdir/pure/base64.nim
   cp lib/pure/browsers.nim $libdir/pure/browsers.nim || exit 1
@@ -344,6 +344,8 @@ if [ $# -eq 1 ] ; then
   chmod 644 $libdir/pure/cookies.nim
   cp lib/pure/dynlib.nim $libdir/pure/dynlib.nim || exit 1
   chmod 644 $libdir/pure/dynlib.nim
+  cp lib/pure/gentabs.nim $libdir/pure/gentabs.nim || exit 1
+  chmod 644 $libdir/pure/gentabs.nim
   cp lib/pure/hashes.nim $libdir/pure/hashes.nim || exit 1
   chmod 644 $libdir/pure/hashes.nim
   cp lib/pure/htmlparser.nim $libdir/pure/htmlparser.nim || exit 1
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 435f522eb..de555917c 100755
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -406,14 +406,16 @@ proc ParseInt*(s: string): int {.noSideEffect, procvar,
   ## Parses a decimal integer value contained in `s`. If `s` is not

   ## a valid integer, `EInvalidValue` is raised.

   var L = parseutils.parseInt(s, result, 0)

-  if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)

+  if L != s.len or L == 0:
+    raise newException(EInvalidValue, "invalid integer: " & s)

 

 proc ParseBiggestInt*(s: string): biggestInt {.noSideEffect, procvar,

   rtl, extern: "nsuParseBiggestInt".} =

   ## Parses a decimal integer value contained in `s`. If `s` is not

   ## a valid integer, `EInvalidValue` is raised.

   var L = parseutils.parseBiggestInt(s, result, 0)

-  if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)

+  if L != s.len or L == 0:
+    raise newException(EInvalidValue, "invalid integer: " & s)

 

 proc ParseFloat*(s: string): float {.noSideEffect, procvar,

   rtl, extern: "nsuParseFloat".} =

@@ -421,7 +423,8 @@ proc ParseFloat*(s: string): float {.noSideEffect, procvar,
   ## a valid floating point number, `EInvalidValue` is raised. ``NAN``,

   ## ``INF``, ``-INF`` are also supported (case insensitive comparison).

   var L = parseutils.parseFloat(s, result, 0)

-  if L != s.len: raise newException(EInvalidValue, "invalid float: " & s)

+  if L != s.len or L == 0:
+    raise newException(EInvalidValue, "invalid float: " & s)

 

 proc ParseHexInt*(s: string): int {.noSideEffect, procvar,

   rtl, extern: "nsuParseHexInt".} =

diff --git a/lib/system.nim b/lib/system.nim
index 6909185e6..043275302 100755
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1198,12 +1198,12 @@ proc each*[T](data: var openArray[T], op: proc (x: var T)) =
 
 # ----------------- GC interface ---------------------------------------------
 
-proc GC_disable*() {.rtl.}
+proc GC_disable*() {.rtl, inl.}
   ## disables the GC. If called n-times, n calls to `GC_enable` are needed to
   ## reactivate the GC. Note that in most circumstances one should only disable
   ## the mark and sweep phase with `GC_disableMarkAndSweep`.
 
-proc GC_enable*() {.rtl.}
+proc GC_enable*() {.rtl, inl.}
   ## enables the GC again.
 
 proc GC_fullCollect*() {.rtl.}
diff --git a/lib/system/assign.nim b/lib/system/assign.nim
index 9f0afb363..24d688ca9 100755
--- a/lib/system/assign.nim
+++ b/lib/system/assign.nim
@@ -7,9 +7,7 @@
 #    distribution, for details about the copyright.
 #
 
-#when defined(debugGC):
-#  {.define: logAssign.}
-proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.}
+proc genericAssignAux(dest, src: Pointer, mt: PNimType)
 proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
   var
     d = cast[TAddress](dest)
@@ -17,8 +15,8 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
   case n.kind
   of nkNone: assert(false)
   of nkSlot:
-    genericAssign(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
-                  n.typ)
+    genericAssignAux(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
+                     n.typ)
   of nkList:
     for i in 0..n.len-1:
       genericAssignAux(dest, src, n.sons[i])
@@ -28,7 +26,7 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode) =
     var m = selectBranch(src, n)
     if m != nil: genericAssignAux(dest, src, m)
 
-proc genericAssign(dest, src: Pointer, mt: PNimType) =
+proc genericAssignAux(dest, src: Pointer, mt: PNimType) =
   var
     d = cast[TAddress](dest)
     s = cast[TAddress](src)
@@ -47,7 +45,7 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
                   newObj(mt, seq.len * mt.base.size + GenericSeqSize))
     var dst = cast[taddress](cast[ppointer](dest)^)
     for i in 0..seq.len-1:
-      genericAssign(
+      genericAssignAux(
         cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
         cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
                      GenericSeqSize),
@@ -60,8 +58,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
     genericAssignAux(dest, src, mt.node)
   of tyArray, tyArrayConstr:
     for i in 0..(mt.size div mt.base.size)-1:
-      genericAssign(cast[pointer](d +% i*% mt.base.size),
-                    cast[pointer](s +% i*% mt.base.size), mt.base)
+      genericAssignAux(cast[pointer](d +% i*% mt.base.size),
+                       cast[pointer](s +% i*% mt.base.size), mt.base)
   of tyString: # a leaf
     var s2 = cast[ppointer](s)^
     if s2 != nil: # nil strings are possible!
@@ -75,6 +73,11 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
   else:
     copyMem(dest, src, mt.size) # copy raw bits
 
+proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
+  GC_disable()
+  genericAssignAux(dest, src, mt)
+  GC_enable()
+
 proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
   var src = src # ugly, but I like to stress the parser sometimes :-)
   genericAssign(dest, addr(src), mt)
diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim
index 3898355c8..23cecfbc1 100755
--- a/lib/system/inclrtl.nim
+++ b/lib/system/inclrtl.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.
diff --git a/lib/system/sysstr.nim b/lib/system/sysstr.nim
index 6c5435724..2afb91d7b 100755
--- a/lib/system/sysstr.nim
+++ b/lib/system/sysstr.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.
diff --git a/rod/ast.nim b/rod/ast.nim
index 2b0fc6d38..c7c0fa7d0 100755
--- a/rod/ast.nim
+++ b/rod/ast.nim
@@ -269,7 +269,8 @@ 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
+    tfEnumHasWholes,  # enum cannot be mapped into a range
+    tfShallow         # type can be shallow copied on assignment
 
   TTypeFlags* = set[TTypeFlag]
 
diff --git a/rod/ccgexprs.nim b/rod/ccgexprs.nim
index c8404fef6..65cc33fd4 100755
--- a/rod/ccgexprs.nim
+++ b/rod/ccgexprs.nim
@@ -215,20 +215,21 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
            [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
     else:
       appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
-  of tyArray, tyArrayConstr:
+  of tyObject:                
+    # XXX: check for subtyping?
     if needsComplexAssignment(dest.t):
       appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
            [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
     else:
-      appcg(p, cpsStmts,
-           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
-           [rdLoc(dest), rdLoc(src)])
-  of tyObject:                # XXX: check for subtyping?
+      appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
+  of tyArray, tyArrayConstr:
     if needsComplexAssignment(dest.t):
       appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
            [addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
     else:
-      appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
+      appcg(p, cpsStmts,
+           "memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
+           [rdLoc(dest), rdLoc(src)])
   of tyOpenArray:
     # open arrays are always on the stack - really? What if a sequence is
     # passed to an open array?
diff --git a/rod/ccgstmts.nim b/rod/ccgstmts.nim
index 572b60143..e87305065 100755
--- a/rod/ccgstmts.nim
+++ b/rod/ccgstmts.nim
@@ -10,6 +10,10 @@
 const 
   RangeExpandLimit = 256      # do not generate ranges
                               # over 'RangeExpandLimit' elements
+  stringCaseThreshold = 8
+    # above X strings a hash-switch for strings is generated
+    # this version sets it too high to avoid hashing, because this has not
+    # been tested for a long time
 
 proc genLineDir(p: BProc, t: PNode) = 
   var line = toLinenumber(t.info) # BUGFIX
@@ -229,13 +233,6 @@ proc genRaiseStmt(p: BProc, t: PNode) =
     else: 
       appcg(p, cpsStmts, "#reraiseException();" & tnl)
 
-const 
-  stringCaseThreshold = 100000 
-    # above X strings a hash-switch for strings is generated
-    # this version sets it too high to avoid hashing, because this has not
-    # been tested for a long time
-    # XXX test and enable this optimization!
-
 proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc, 
                           rangeFormat, eqFormat: TFormatStr, labl: TLabel) = 
   var 
@@ -251,90 +248,68 @@ proc genCaseGenericBranch(p: BProc, b: PNode, e: TLoc,
       initLocExpr(p, b.sons[i], x)
       appcg(p, cpsStmts, eqFormat, [rdCharLoc(e), rdCharLoc(x), labl])
 
-proc genCaseSecondPass(p: BProc, t: PNode, labId: int) = 
+proc genCaseSecondPass(p: BProc, t: PNode, labId, until: int): TLabel = 
   var Lend = getLabel(p)
-  for i in countup(1, sonsLen(t) - 1): 
+  for i in 1..until: 
     appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(labId + i)])
-    if t.sons[i].kind == nkOfBranch: # else statement
+    if t.sons[i].kind == nkOfBranch:
       var length = sonsLen(t.sons[i])
       genStmts(p, t.sons[i].sons[length - 1])
       appf(p.s[cpsStmts], "goto $1;$n", [Lend])
     else: 
       genStmts(p, t.sons[i].sons[0])
-  fixLabel(p, Lend)
+  result = Lend
 
-proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) = 
+proc genIfForCaseUntil(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr,
+                       until: int, a: TLoc): TLabel = 
   # generate a C-if statement for a Nimrod case statement
-  var a: TLoc
-  initLocExpr(p, t.sons[0], a) # fist pass: generate ifs+goto:
   var labId = p.labels
-  for i in countup(1, sonsLen(t) - 1): 
+  for i in 1..until: 
     inc(p.labels)
     if t.sons[i].kind == nkOfBranch: # else statement
       genCaseGenericBranch(p, t.sons[i], a, rangeFormat, eqFormat, 
                            con("LA", toRope(p.labels)))
     else: 
       appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)])
-  genCaseSecondPass(p, t, labId)
-
-proc hashString(s: string): biggestInt = 
-  var 
-    a: int32
-    b: int64
-  if CPU[targetCPU].bit == 64: 
-    # we have to use the same bitwidth
-    # as the target CPU
-    b = 0
-    for i in countup(0, len(s) - 1): 
-      b = b +% Ord(s[i])
-      b = b +% `shl`(b, 10)
-      b = b xor `shr`(b, 6)
-    b = b +% `shl`(b, 3)
-    b = b xor `shr`(b, 11)
-    b = b +% `shl`(b, 15)
-    result = b
-  else: 
-    a = 0
-    for i in countup(0, len(s) - 1): 
-      a = a +% int32(Ord(s[i]))
-      a = a +% `shl`(a, int32(10))
-      a = a xor `shr`(a, int32(6))
-    a = a +% `shl`(a, int32(3))
-    a = a xor `shr`(a, int32(11))
-    a = a +% `shl`(a, int32(15))
-    result = a
+  if until < t.len-1: 
+    inc(p.labels)
+    var gotoTarget = p.labels
+    appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(gotoTarget)])
+    result = genCaseSecondPass(p, t, labId, until)
+    appf(p.s[cpsStmts], "LA$1: ;$n", [toRope(gotoTarget)])
+  else:
+    result = genCaseSecondPass(p, t, labId, until)
 
-type 
-  TRopeSeq = seq[PRope]
+proc genCaseGeneric(p: BProc, t: PNode, rangeFormat, eqFormat: TFormatStr) = 
+  var a: TLoc
+  initLocExpr(p, t.sons[0], a)
+  var Lend = genIfForCaseUntil(p, t, rangeFormat, eqFormat, sonsLen(t)-1, a)
+  fixLabel(p, Lend)
 
 proc genCaseStringBranch(p: BProc, b: PNode, e: TLoc, labl: TLabel, 
-                         branches: var TRopeSeq) = 
-  var 
-    length, j: int
-    x: TLoc
-  length = sonsLen(b)
+                         branches: var openArray[PRope]) = 
+  var x: TLoc
+  var length = sonsLen(b)
   for i in countup(0, length - 2): 
     assert(b.sons[i].kind != nkRange)
     initLocExpr(p, b.sons[i], x)
     assert(b.sons[i].kind in {nkStrLit..nkTripleStrLit})
-    j = int(hashString(b.sons[i].strVal) and high(branches))
+    var j = int(hashString(b.sons[i].strVal) and high(branches))
     appcg(p.module, branches[j], "if (#eqStrings($1, $2)) goto $3;$n", 
          [rdLoc(e), rdLoc(x), labl])
 
 proc genStringCase(p: BProc, t: PNode) = 
-  var 
-    strings, bitMask, labId: int
-    a: TLoc
-    branches: TRopeSeq
   # count how many constant strings there are in the case:
-  strings = 0
+  var strings = 0
   for i in countup(1, sonsLen(t) - 1): 
     if t.sons[i].kind == nkOfBranch: inc(strings, sonsLen(t.sons[i]) - 1)
   if strings > stringCaseThreshold: 
-    bitMask = math.nextPowerOfTwo(strings) - 1
+    var bitMask = math.nextPowerOfTwo(strings) - 1
+    var branches: seq[PRope]
     newSeq(branches, bitMask + 1)
+    var a: TLoc
     initLocExpr(p, t.sons[0], a) # fist pass: gnerate ifs+goto:
-    labId = p.labels
+    var labId = p.labels
     for i in countup(1, sonsLen(t) - 1): 
       inc(p.labels)
       if t.sons[i].kind == nkOfBranch: 
@@ -353,67 +328,72 @@ proc genStringCase(p: BProc, t: PNode) =
     if t.sons[sonsLen(t) - 1].kind != nkOfBranch: 
       appf(p.s[cpsStmts], "goto LA$1;$n", [toRope(p.labels)]) 
     # third pass: generate statements
-    genCaseSecondPass(p, t, labId)
+    var Lend = genCaseSecondPass(p, t, labId, sonsLen(t)-1)
+    fixLabel(p, Lend)
   else: 
     genCaseGeneric(p, t, "", "if (#eqStrings($1, $2)) goto $3;$n")
   
 proc branchHasTooBigRange(b: PNode): bool = 
-  for i in countup(0, sonsLen(b) - 2): 
+  for i in countup(0, sonsLen(b)-2): 
     # last son is block
     if (b.sons[i].Kind == nkRange) and
         b.sons[i].sons[1].intVal - b.sons[i].sons[0].intVal > RangeExpandLimit: 
       return true
-  result = false
 
-proc genOrdinalCase(p: BProc, t: PNode) = 
-  # We analyse if we have a too big switch range. If this is the case,
-  # we generate an ordinary if statement and rely on the C compiler
-  # to produce good code.
-  var 
-    canGenerateSwitch, hasDefault: bool
-    length: int
-    a: TLoc
-    v: PNode
-  canGenerateSwitch = true
-  if not (hasSwitchRange in CC[ccompiler].props): 
-    for i in countup(1, sonsLen(t) - 1): 
-      if (t.sons[i].kind == nkOfBranch) and branchHasTooBigRange(t.sons[i]): 
-        canGenerateSwitch = false
-        break 
-  if canGenerateSwitch: 
-    initLocExpr(p, t.sons[0], a)
+proc IfSwitchSplitPoint(p: BProc, n: PNode): int =
+  for i in 1..n.len-1:
+    var branch = n[i]
+    var stmtBlock = lastSon(branch)
+    if stmtBlock.stmtsContainPragma(wLinearScanEnd):
+      result = i
+    elif hasSwitchRange notin CC[ccompiler].props: 
+      if branch.kind == nkOfBranch and branchHasTooBigRange(branch): 
+        result = i
+
+proc genOrdinalCase(p: BProc, n: PNode) = 
+  # analyse 'case' statement:
+  var splitPoint = IfSwitchSplitPoint(p, n)
+  
+  # generate if part (might be empty):
+  var a: TLoc
+  initLocExpr(p, n.sons[0], a)
+  var Lend = if splitPoint > 0: genIfForCaseUntil(p, n, 
+                    rangeFormat = "if ($1 >= $2 && $1 <= $3) goto $4;$n",
+                    eqFormat = "if ($1 == $2) goto $3;$n", 
+                    splitPoint, a) else: nil
+  
+  # generate switch part (might be empty):
+  if splitPoint+1 < n.len:
     appf(p.s[cpsStmts], "switch ($1) {$n", [rdCharLoc(a)])
-    hasDefault = false
-    for i in countup(1, sonsLen(t) - 1): 
-      if t.sons[i].kind == nkOfBranch: 
-        length = sonsLen(t.sons[i])
-        for j in countup(0, length - 2): 
-          if t.sons[i].sons[j].kind == nkRange: 
-            # a range
+    var hasDefault = false
+    for i in splitPoint+1 .. < n.len: 
+      var branch = n[i]
+      if branch.kind == nkOfBranch: 
+        var length = branch.len
+        for j in 0 .. length-2: 
+          if branch[j].kind == nkRange: 
             if hasSwitchRange in CC[ccompiler].props: 
               appf(p.s[cpsStmts], "case $1 ... $2:$n", [
-                  genLiteral(p, t.sons[i].sons[j].sons[0]), 
-                  genLiteral(p, t.sons[i].sons[j].sons[1])])
+                  genLiteral(p, branch[j][0]), 
+                  genLiteral(p, branch[j][1])])
             else: 
-              v = copyNode(t.sons[i].sons[j].sons[0])
-              while (v.intVal <= t.sons[i].sons[j].sons[1].intVal): 
+              var v = copyNode(branch[j][0])
+              while v.intVal <= branch[j][1].intVal: 
                 appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, v)])
                 Inc(v.intVal)
           else: 
-            appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, t.sons[i].sons[j])])
-        genStmts(p, t.sons[i].sons[length - 1])
+            appf(p.s[cpsStmts], "case $1:$n", [genLiteral(p, branch[j])])
+        genStmts(p, branch[length-1])
       else: 
         # else part of case statement:
         app(p.s[cpsStmts], "default:" & tnl)
-        genStmts(p, t.sons[i].sons[0])
+        genStmts(p, branch[0])
         hasDefault = true
       app(p.s[cpsStmts], "break;" & tnl)
     if (hasAssume in CC[ccompiler].props) and not hasDefault: 
       app(p.s[cpsStmts], "default: __assume(0);" & tnl)
     app(p.s[cpsStmts], '}' & tnl)
-  else: 
-    genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n", 
-                   "if ($1 == $2) goto $3;$n")
+  if Lend != nil: fixLabel(p, Lend)
   
 proc genCaseStmt(p: BProc, t: PNode) = 
   genLineDir(p, t)
@@ -424,7 +404,6 @@ proc genCaseStmt(p: BProc, t: PNode) =
     genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n", 
                    "if ($1 == $2) goto $3;$n") 
   else: 
-    # ordinal type: generate a switch statement
     genOrdinalCase(p, t)
   
 proc hasGeneralExceptSection(t: PNode): bool = 
@@ -629,19 +608,17 @@ proc genBreakPoint(p: BProc, t: PNode) =
 proc genPragma(p: BProc, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
     var it = n.sons[i]
-    var key = if it.kind == nkExprColonExpr: it.sons[0] else: it
-    if key.kind == nkIdent: 
-      case whichKeyword(key.ident)
-      of wEmit:
-        genEmit(p, it)
-      of wBreakpoint: 
-        genBreakPoint(p, it)
-      of wDeadCodeElim: 
-        if not (optDeadCodeElim in gGlobalOptions): 
-          # we need to keep track of ``deadCodeElim`` pragma
-          if (sfDeadCodeElim in p.module.module.flags): 
-            addPendingModule(p.module)
-      else: nil
+    case whichPragma(it)
+    of wEmit:
+      genEmit(p, it)
+    of wBreakpoint: 
+      genBreakPoint(p, it)
+    of wDeadCodeElim: 
+      if not (optDeadCodeElim in gGlobalOptions): 
+        # we need to keep track of ``deadCodeElim`` pragma
+        if (sfDeadCodeElim in p.module.module.flags): 
+          addPendingModule(p.module)
+    else: nil
   
 proc genAsgn(p: BProc, e: PNode) = 
   var a: TLoc
diff --git a/rod/ccgutils.nim b/rod/ccgutils.nim
index c7733c5ff..f1d66ca94 100755
--- a/rod/ccgutils.nim
+++ b/rod/ccgutils.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2009 Andreas Rumpf
+#        (c) Copyright 2011 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -10,21 +10,58 @@
 # This module declares some helpers for the C code generator.
 
 import 
-  ast, astalgo, ropes, lists, nhashes, strutils, types, msgs
+  ast, astalgo, ropes, lists, nhashes, strutils, types, msgs, wordrecg, 
+  platform
 
-proc toCChar*(c: Char): string
-proc makeCString*(s: string): PRope
-proc makeLLVMString*(s: string): PRope
-proc TableGetType*(tab: TIdTable, key: PType): PObject
-proc GetUniqueType*(key: PType): PType
-# implementation
+proc whichPragma*(n: PNode): TSpecialWord = 
+  var key = if n.kind == nkExprColonExpr: n.sons[0] else: n
+  if key.kind == nkIdent: result = whichKeyword(key.ident)
+
+proc getPragmaStmt*(n: PNode, w: TSpecialWord): PNode =
+  case n.kind
+  of nkStmtList: 
+    for i in 0 .. < n.len: 
+      result = getPragmaStmt(n[i], w)
+      if result != nil: break
+  of nkPragma:
+    for i in 0 .. < n.len: 
+      if whichPragma(n[i]) == w: return n[i]
+  else: nil
+
+proc stmtsContainPragma*(n: PNode, w: TSpecialWord): bool =
+  result = getPragmaStmt(n, w) != nil
+
+proc hashString*(s: string): biggestInt = 
+  # has to be the same algorithm as system.hashString!
+  if CPU[targetCPU].bit == 64: 
+    # we have to use the same bitwidth
+    # as the target CPU
+    var b = 0'i64
+    for i in countup(0, len(s) - 1): 
+      b = b +% Ord(s[i])
+      b = b +% `shl`(b, 10)
+      b = b xor `shr`(b, 6)
+    b = b +% `shl`(b, 3)
+    b = b xor `shr`(b, 11)
+    b = b +% `shl`(b, 15)
+    result = b
+  else: 
+    var a = 0'i32
+    for i in countup(0, len(s) - 1): 
+      a = a +% Ord(s[i]).int32
+      a = a +% `shl`(a, 10'i32)
+      a = a xor `shr`(a, 6'i32)
+    a = a +% `shl`(a, 3'i32)
+    a = a xor `shr`(a, 11'i32)
+    a = a +% `shl`(a, 15'i32)
+    result = a
 
 var gTypeTable: array[TTypeKind, TIdTable]
 
 proc initTypeTables() = 
   for i in countup(low(TTypeKind), high(TTypeKind)): InitIdTable(gTypeTable[i])
   
-proc GetUniqueType(key: PType): PType = 
+proc GetUniqueType*(key: PType): PType = 
   var 
     t: PType
     k: TTypeKind
@@ -32,33 +69,7 @@ proc GetUniqueType(key: PType): PType =
   result = key
   if key == nil: return 
   k = key.kind
-  case k #
-         #  case key.Kind of
-         #    tyEmpty, tyChar, tyBool, tyNil, tyPointer, tyString, tyCString, 
-         #    tyInt..tyFloat128, tyProc, tyAnyEnum: begin end;
-         #    tyNone, tyForward: 
-         #      InternalError('GetUniqueType: ' + typeToString(key));
-         #    tyGenericParam, tyGeneric, tyAbstract, tySequence,
-         #    tyOpenArray, tySet, tyVar, tyRef, tyPtr, tyArrayConstr,
-         #    tyArray, tyTuple, tyRange: begin
-         #      // we have to do a slow linear search because types may need
-         #      // to be compared by their structure:
-         #      if IdTableHasObjectAsKey(gTypeTable, key) then exit;
-         #      for h := 0 to high(gTypeTable.data) do begin
-         #        t := PType(gTypeTable.data[h].key);
-         #        if (t <> nil) and sameType(t, key) then begin result := t; exit end
-         #      end;
-         #      IdTablePut(gTypeTable, key, key);
-         #    end;
-         #    tyObject, tyEnum: begin
-         #      result := PType(IdTableGet(gTypeTable, key));
-         #      if result = nil then begin
-         #        IdTablePut(gTypeTable, key, key);
-         #        result := key;
-         #      end
-         #    end;
-         #    tyGenericInst, tyAbstract: result := GetUniqueType(lastSon(key));
-         #  end; 
+  case k 
   of tyObject, tyEnum: 
     result = PType(IdTableGet(gTypeTable[k], key))
     if result == nil: 
@@ -78,7 +89,7 @@ proc GetUniqueType(key: PType): PType =
         return t
     IdTablePut(gTypeTable[k], key, key)
 
-proc TableGetType(tab: TIdTable, key: PType): PObject = 
+proc TableGetType*(tab: TIdTable, key: PType): PObject = 
   var t: PType
   # returns nil if we need to declare this type
   result = IdTableGet(tab, key)
@@ -91,13 +102,13 @@ proc TableGetType(tab: TIdTable, key: PType): PObject =
         if sameType(t, key): 
           return tab.data[h].val
 
-proc toCChar(c: Char): string = 
+proc toCChar*(c: Char): string = 
   case c
   of '\0'..'\x1F', '\x80'..'\xFF': result = '\\' & toOctal(c)
   of '\'', '\"', '\\': result = '\\' & c
   else: result = $(c)
   
-proc makeCString(s: string): PRope = 
+proc makeCString*(s: string): PRope = 
   # BUGFIX: We have to split long strings into many ropes. Otherwise
   # this could trigger an InternalError(). See the ropes module for
   # further information.
@@ -117,9 +128,8 @@ proc makeCString(s: string): PRope =
   add(res, '\"')
   app(result, toRope(res))
 
-proc makeLLVMString(s: string): PRope = 
-  const 
-    MaxLineLength = 64
+proc makeLLVMString*(s: string): PRope = 
+  const MaxLineLength = 64
   var res: string
   result = nil
   res = "c\""
@@ -135,4 +145,4 @@ proc makeLLVMString(s: string): PRope =
   add(res, "\\00\"")
   app(result, toRope(res))
 
-InitTypeTables()
\ No newline at end of file
+InitTypeTables()
diff --git a/rod/cgen.nim b/rod/cgen.nim
index 503cb8586..7df9f3d11 100755
--- a/rod/cgen.nim
+++ b/rod/cgen.nim
@@ -308,14 +308,19 @@ proc zeroVar(p: BProc, loc: TLoc, containsGCref: bool) =
 proc zeroTemp(p: BProc, loc: TLoc) = 
   if skipTypes(loc.t, abstractVarRange).Kind notin
       {tyArray, tyArrayConstr, tySet, tyTuple, tyObject}: 
-    var nilLoc: TLoc
-    initLoc(nilLoc, locTemp, loc.t, onStack)
-    nilLoc.r = toRope("NIM_NIL")
-    # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
-    genRefAssign(p, loc, nilLoc, {afSrcIsNil})
+    appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(loc)])
+    when false:
+      var nilLoc: TLoc
+      initLoc(nilLoc, locTemp, loc.t, onStack)
+      nilLoc.r = toRope("NIM_NIL")
+      # puts ``unsureAsgnRef`` etc to ``p.s[cpsStmts]``:
+      genRefAssign(p, loc, nilLoc, {afSrcIsNil})
   else: 
-    appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
-         [addrLoc(loc), genTypeInfo(p.module, loc.t)])
+    appf(p.s[cpsStmts], "memset((void*)$1, 0, sizeof($2));$n", 
+         [addrLoc(loc), rdLoc(loc)])
+    when false:
+      appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n", 
+           [addrLoc(loc), genTypeInfo(p.module, loc.t)])
 
 proc initVariable(p: BProc, v: PSym) = 
   var b = containsGarbageCollectedRef(v.typ)
diff --git a/rod/main.nim b/rod/main.nim
index 977a4ff1b..79059a874 100755
--- a/rod/main.nim
+++ b/rod/main.nim
@@ -193,23 +193,23 @@ proc MainCommand(cmd, filename: string) =
   setID(100)
   passes.gIncludeFile = syntaxes.parseFile
   passes.gImportModule = importModule
-  case whichKeyword(cmd)
-  of wCompile, wCompileToC, wC, wCC: 
+  case cmd.normalize
+  of "c", "cc", "compile", "compiletoc": 
     # compile means compileToC currently
     gCmd = cmdCompileToC
     wantFile(filename)
     CommandCompileToC(filename)
-  of wCompileToCpp: 
+  of "compiletocpp": 
     extccomp.cExt = ".cpp"
     gCmd = cmdCompileToCpp
     wantFile(filename)
     CommandCompileToC(filename)
-  of wCompileToOC, wOC:
+  of "oc", "compiletooc":
     extccomp.cExt = ".m"
     gCmd = cmdCompileToOC
     wantFile(filename)
     CommandCompileToC(filename)
-  of wRun:
+  of "run":
     gCmd = cmdRun
     wantFile(filename)
     when hasTinyCBackend:
@@ -217,61 +217,61 @@ proc MainCommand(cmd, filename: string) =
       CommandCompileToC(filename)
     else: 
       rawMessage(errInvalidCommandX, cmd)
-  of wCompileToEcmaScript, wJs: 
+  of "js", "compiletoecmascript": 
     gCmd = cmdCompileToEcmaScript
     wantFile(filename)
     CommandCompileToEcmaScript(filename)
-  of wCompileToLLVM: 
+  of "compiletollvm": 
     gCmd = cmdCompileToLLVM
     wantFile(filename)
     when has_LLVM_Backend:
       CommandCompileToLLVM(filename)
     else:
       rawMessage(errInvalidCommandX, cmd)
-  of wPretty: 
+  of "pretty": 
     gCmd = cmdPretty
     wantFile(filename)        #CommandExportSymbols(filename);
     CommandPretty(filename)
-  of wDoc: 
+  of "doc": 
     gCmd = cmdDoc
     LoadSpecialConfig(DocConfig)
     wantFile(filename)
     CommandDoc(filename)
-  of wRst2html: 
+  of "rst2html": 
     gCmd = cmdRst2html
     LoadSpecialConfig(DocConfig)
     wantFile(filename)
     CommandRst2Html(filename)
-  of wRst2tex: 
+  of "rst2tex": 
     gCmd = cmdRst2tex
     LoadSpecialConfig(DocTexConfig)
     wantFile(filename)
     CommandRst2TeX(filename)
-  of wGenDepend: 
+  of "gendepend": 
     gCmd = cmdGenDepend
     wantFile(filename)
     CommandGenDepend(filename)
-  of wDump: 
+  of "dump": 
     gCmd = cmdDump
     condsyms.ListSymbols()
     for it in iterSearchPath(): MsgWriteln(it)
-  of wCheck: 
+  of "check": 
     gCmd = cmdCheck
     wantFile(filename)
     CommandCheck(filename)
-  of wParse: 
+  of "parse": 
     gCmd = cmdParse
     wantFile(filename)
     discard parseFile(addFileExt(filename, nimExt))
-  of wScan: 
+  of "scan": 
     gCmd = cmdScan
     wantFile(filename)
     CommandScan(filename)
     MsgWriteln("Beware: Indentation tokens depend on the parser\'s state!")
-  of wI: 
+  of "i": 
     gCmd = cmdInteractive
     CommandInteractive()
-  of wIdeTools:
+  of "idetools":
     gCmd = cmdIdeTools
     wantFile(filename)
     CommandSuggest(filename)
diff --git a/rod/pragmas.nim b/rod/pragmas.nim
index 45543eb74..d7bda4099 100755
--- a/rod/pragmas.nim
+++ b/rod/pragmas.nim
@@ -34,12 +34,12 @@ const
     wStacktrace, wLinetrace, wOptimization, wHint, wWarning, wError, wFatal, 
     wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop, wBreakpoint, 
     wCheckpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated, wFloatChecks,
-    wInfChecks, wNanChecks, wPragma, wEmit}
+    wInfChecks, wNanChecks, wPragma, wEmit, wUnroll, wLinearScanEnd}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
     wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, wPure, 
     wDeprecated, wExtern}
   typePragmas* = {wImportc, wExportc, wDeprecated, wMagic, wAcyclic, wNodecl, 
-    wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern}
+    wPure, wHeader, wCompilerProc, wFinal, wSize, wExtern, wShallow}
   fieldPragmas* = {wImportc, wExportc, wDeprecated, wExtern}
   varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl, 
     wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern}
@@ -357,6 +357,19 @@ proc PragmaEmit(c: PContext, n: PNode) =
 proc noVal(n: PNode) = 
   if n.kind == nkExprColonExpr: invalidPragma(n)
 
+proc PragmaUnroll(c: PContext, n: PNode) = 
+  if c.p.nestedLoopCounter <= 0: 
+    invalidPragma(n)
+  elif n.kind == nkExprColonExpr:
+    var unrollFactor = expectIntLit(c, n)
+    if unrollFactor <% 32: 
+      n.sons[1] = newIntNode(nkIntLit, unrollFactor)
+    else: 
+      invalidPragma(n)
+
+proc PragmaLinearScanEnd(c: PContext, n: PNode) =
+  noVal(n)
+
 proc processPragma(c: PContext, n: PNode, i: int) = 
   var it = n.sons[i]
   if it.kind != nkExprColonExpr: invalidPragma(n)
@@ -475,6 +488,10 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
             noVal(it)
             if sym.typ == nil: invalidPragma(it)
             incl(sym.typ.flags, tfAcyclic)
+          of wShallow:
+            noVal(it)
+            if sym.typ == nil: invalidPragma(it)
+            incl(sym.typ.flags, tfShallow)
           of wTypeCheck: 
             noVal(it)
             incl(sym.flags, sfTypeCheck)
@@ -509,6 +526,8 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
             if sym.typ == nil: invalidPragma(it)
             sym.typ.callConv = wordToCallConv(k)
           of wEmit: PragmaEmit(c, it)
+          of wUnroll: PragmaUnroll(c, it)
+          of wLinearScanEnd: PragmaLinearScanEnd(c, it)
           else: invalidPragma(it)
         else: invalidPragma(it)
     else: processNote(c, it)
diff --git a/rod/rst.nim b/rod/rst.nim
index efda9bd9a..dace43a44 100755
--- a/rod/rst.nim
+++ b/rod/rst.nim
@@ -188,7 +188,7 @@ proc rawGetTok(L: var TLexer, tok: var TToken) =
   of '\x0D', '\x0A': 
     getIndent(L, tok)
   of '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', 
-     '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', 
+     '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{',
      '|', '}', '~': 
     getAdornment(L, tok)
     if len(tok.symbol) <= 3: tok.kind = tkPunct
@@ -257,16 +257,16 @@ type
     value*: PRstNode
 
   TSharedState{.final.} = object 
-    uLevel*, oLevel*: int     # counters for the section levels
-    subs*: seq[TSubstitution] # substitutions
-    refs*: seq[TSubstitution] # references
+    uLevel*, oLevel*: int        # counters for the section levels
+    subs*: seq[TSubstitution]    # substitutions
+    refs*: seq[TSubstitution]    # references
     underlineToLevel*: TLevelMap # Saves for each possible title adornment
                                  # character its level in the
                                  # current document. 
                                  # This is for single underline adornments.
-    overlineToLevel*: TLevelMap # Saves for each possible title adornment 
-                                # character its level in the current document. 
-                                # This is for over-underline adornments.
+    overlineToLevel*: TLevelMap  # Saves for each possible title adornment 
+                                 # character its level in the current document. 
+                                 # This is for over-underline adornments.
   
   PSharedState = ref TSharedState
   TRstParser = object of TObject
diff --git a/rod/semexprs.nim b/rod/semexprs.nim
index 1d20e5253..7a14b931a 100755
--- a/rod/semexprs.nim
+++ b/rod/semexprs.nim
@@ -410,10 +410,13 @@ proc analyseIfAddressTakenInCall(c: PContext, n: PNode) =
   
 proc semDirectCallAnalyseEffects(c: PContext, n: PNode,
                                  flags: TExprFlags): PNode = 
-  if not (efWantIterator in flags): 
-    result = semDirectCall(c, n, {skProc, skMethod, skConverter})
-  else: 
-    result = semDirectCall(c, n, {skIterator})
+  var symflags = {skProc, skMethod, skConverter}
+  if efWantIterator in flags:
+    symflags = {skIterator}
+  elif efAllowType in flags: 
+    # for ``type countup(1,3)``, see ``tests/ttoseq``.
+    symflags.incl(skIterator)
+  result = semDirectCall(c, n, symflags)
   if result != nil: 
     if result.sons[0].kind != nkSym: 
       InternalError("semDirectCallAnalyseEffects")
@@ -1037,7 +1040,7 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
     of paNone: result = nil
     of paTuplePositions: result = semTuplePositionsConstr(c, n)
     of paTupleFields: result = semTupleFieldsConstr(c, n)
-    of paSingle: result = semExpr(c, n.sons[0])
+    of paSingle: result = semExpr(c, n.sons[0], flags)
   of nkCurly: result = semSetConstr(c, n)
   of nkBracket: result = semArrayConstr(c, n)
   of nkLambda: result = semLambda(c, n)
diff --git a/rod/semtypes.nim b/rod/semtypes.nim
index 4a676e00a..8dae5c27b 100755
--- a/rod/semtypes.nim
+++ b/rod/semtypes.nim
@@ -574,7 +574,8 @@ proc semTypeNode(c: PContext, n: PNode, prev: PType): PType =
   case n.kind
   of nkEmpty: nil
   of nkTypeOfExpr: 
-    result = semExprWithType(c, n, {efAllowType}).typ
+    checkSonsLen(n, 1)
+    result = semExprWithType(c, n.sons[0], {efAllowType}).typ
   of nkPar: 
     if sonsLen(n) == 1: result = semTypeNode(c, n.sons[0], prev)
     else: GlobalError(n.info, errTypeExpected)
diff --git a/rod/transf.nim b/rod/transf.nim
index 5b62c7f16..c7c4e3db8 100755
--- a/rod/transf.nim
+++ b/rod/transf.nim
@@ -340,10 +340,6 @@ proc transformAddrDeref(c: PTransf, n: PNode, a, b: TNodeKind): PTransNode =
       #result = newTransNode(n.sons[0])
       #result[1] = transform(c, m.sons[0])
       
-      #if skipTypes(n.sons[0].typ, abstractVar).kind == tyOpenArray:
-      #  debug(result.pnode)
-      #  liMessage(n.info, warnUser, 
-      #    "nkPassAsOpenArray introduced here " & renderTree(n))
     else:
       result = transformSons(c, n)
   else: 
diff --git a/rod/wordrecg.nim b/rod/wordrecg.nim
index f9ea37158..8376fa01b 100755
--- a/rod/wordrecg.nim
+++ b/rod/wordrecg.nim
@@ -53,12 +53,8 @@ type
     wGenerate, wG, wC, wCpp, wBorrow, wRun, wR, wVerbosity, wV, wHelp, wH, 
     wSymbolFiles, wFieldChecks, wX, wVersion, wAdvanced, wSkipcfg, wSkipProjCfg, 
     wCc, wGenscript, wCheckPoint, wCheckPoints, wNoMain, wSubsChar, 
-    wAcyclic, wIndex, 
-    wCompileToC, wCompileToCpp, wCompileToEcmaScript, wCompileToLLVM, 
-    wCompileToOC,
-    wPretty, 
-    wDoc, wGenDepend, wDump, wCheck, wParse, wScan, wJs, wOC, 
-    wRst2html, wRst2tex, wI,
+    wAcyclic, wShallow, wUnroll, wLinearScanEnd,
+    wIndex, 
     wWrite, wPutEnv, wPrependEnv, wAppendEnv, wThreadVar, wEmit, wThreads,
     wRecursivePath, 
     wStdout,
@@ -105,33 +101,25 @@ const
     "cpu", "generate", "g", "c", "cpp", "borrow", "run", "r", "verbosity", "v", 
     "help", "h", "symbolfiles", "fieldchecks", "x", "version", "advanced", 
     "skipcfg", "skipprojcfg", "cc", "genscript", "checkpoint", "checkpoints", 
-    "nomain", "subschar", "acyclic", "index", 
-    "compiletoc", "compiletocpp", "compiletoecmascript", "compiletollvm", 
-    "compiletooc",
-    "pretty", "doc", "gendepend", "dump", "check", "parse", "scan", 
-    "js", "oc", "rst2html", "rst2tex", "i", 
+    "nomain", "subschar", "acyclic", "shallow", "unroll", "linearscanend",
+    "index", 
     "write", "putenv", "prependenv", "appendenv", "threadvar", "emit",
     "threads", "recursivepath", 
     "stdout",
     "idetools", "suggest", "track", "def", "context"]
 
-proc whichKeyword*(id: PIdent): TSpecialWord
-proc whichKeyword*(id: String): TSpecialWord
-proc findStr*(a: openarray[string], s: string): int
-# implementation
-
-proc findStr(a: openarray[string], s: string): int = 
+proc findStr*(a: openarray[string], s: string): int = 
   for i in countup(low(a), high(a)): 
     if cmpIgnoreStyle(a[i], s) == 0: 
       return i
   result = - 1
 
-proc whichKeyword(id: String): TSpecialWord = 
-  result = whichKeyword(getIdent(id))
-
-proc whichKeyword(id: PIdent): TSpecialWord = 
+proc whichKeyword*(id: PIdent): TSpecialWord = 
   if id.id < 0: result = wInvalid
   else: result = TSpecialWord(id.id)
+
+proc whichKeyword*(id: String): TSpecialWord = 
+  result = whichKeyword(getIdent(id))
   
 proc initSpecials() = 
   # initialize the keywords:
diff --git a/tests/accept/compile/tfib.nim b/tests/accept/compile/tfib.nim
new file mode 100644
index 000000000..09a4d5038
--- /dev/null
+++ b/tests/accept/compile/tfib.nim
@@ -0,0 +1,11 @@
+
+iterator fibonacci(): int = 
+  var a = 0
+  var b = 1
+  while true: 
+    yield a
+    var c = b
+    b = a
+    a = a + c
+
+
diff --git a/tests/accept/run/tsort.nim b/tests/accept/run/tsort.nim
new file mode 100644
index 000000000..306e7e360
--- /dev/null
+++ b/tests/accept/run/tsort.nim
@@ -0,0 +1,185 @@
+
+# design criteria:
+# Generic code is expenisve wrt code size!
+# So the implementation should be small.
+# The sort should be stable.
+# 
+
+proc sort[T](arr: var openArray[T], lo, hi: natural) =
+  var k = 0
+  if lo < hi:
+    var mid = (lo + hi) div 2
+    sort(arr, lo, mid)
+    inc(mid)
+    sort(arr, mid, hi)
+    while lo < mid and mid <= hi:
+      if arr[lo] < arr[mid]:
+        inc(lo)
+      else:
+        when swapIsExpensive(T):
+          var help = arr[mid]
+          for k in countdown(mid, succ(lo)):
+            arr[k] = arr[pred(k)]
+          arr[lo] = help
+        else:
+          for k in countdown(mid, succ(lo)):
+            swap(arr[k], arr[pred(k)])
+        inc(lo)
+        inc(mid)
+  
+type
+  TSortOrder* = enum
+    Descending = -1,
+    Ascending = 0
+
+proc flip(x: int, order: TSortOrder): int {.inline.} = 
+  result = x xor ord(order) - ord(order)
+
+# We use a fixed size stack. This size is larger
+# than can be overflowed on a 64-bit machine
+const
+  stackSize = 66
+  minRunSize = 7
+
+type
+  TRun = tuple[index, length: int]
+  TSortState[T] {.pure, final.} = object
+    storage: seq[T]
+    runs: array[0..stackSize-1, TRun]
+    stackHeight: int # The index of the first unwritten element of the stack.
+    partitionedUpTo, length: int
+
+# We keep track of how far we've partitioned up 
+# to so we know where to start the next partition.
+# The idea is that everything < partionedUpTo 
+# is on the stack, everything >= partionedUpTo
+# is not yet on the stack. When partitionedUpTo == length
+# we'll have put everything on the stack.
+  
+proc reverse[T](a: var openArray[T], first, last: int) =
+  for j in first .. < first+length div 2: swap(a[j], a[length-j-1])
+
+proc insertionSort[T]( int xs[], int length) =
+  for i in 1.. < length:
+    # The array before i is sorted. Now insert xs[i] into it
+    var x = xs[i]
+    var j = i-1
+    # Move j down until it's either at the beginning or on
+    # something <= x, and everything to the right of it has
+    # been moved up one.
+    while j >= 0 and xs[j] > x:
+      xs[j+1] = xs[j]
+      dec j
+    xs[j+1] = x
+
+proc boostRunLength(s: TSortState, run: var TRun) =
+  # Need to make sure we don't overshoot the end of the array
+  var length = min(s.length - run.index, minRunSize)
+  insertionSort(run.index, length)
+  run.length = length
+
+proc nextPartition[T](a: var openarray[T], s: var TSortState): bool =
+  if s.partitionedUpTo >= s.length: return false
+  var startIndex = s.partitionedUpTo
+  # Find an increasing run starting from startIndex
+  var nextStartIndex = startIndex + 1
+
+  if nextStartIndex < s.length:
+    if a[nextStartIndex] < a[startIndex]:
+      # We have a decreasing sequence starting here.
+      while nextStartIndex < s.length:
+        if a[nextStartIndex] < a[nextStartIndex-1]: inc(nextStartIndex)
+        else: break
+      # Now reverse it in place.
+      reverse(a, startIndex, nextStartIndex)
+    else:
+      # We have an increasing sequence starting here.
+      while nextStartIndex < s.length:
+        if a[nextStartIndex] >= a[nextStartIndex-1]: inc(nextStartIndex)
+        else: break
+
+  # So now [startIndex, nextStartIndex) is an increasing run.
+  # Push it onto the stack.
+  var runToAdd: TRun = (startIndex, nextStartIndex - startIndex)
+  if runToAdd.length < minRunSize:
+    boostRunLength(s, runToAdd)
+  s.partitionedUpTo = startIndex + runToAdd.length
+
+  s.runs[s.stackHeight] = runToAdd
+  inc s.stackHeight
+  result = true
+
+proc shouldCollapse(s: TSortState): bool =
+  if s.stackHeight > 2: 
+    var h = s.stackHeight-1
+    var headLength = s.runs[h].length
+    var nextLength = s.runs[h-1].length
+    result = 2 * headLength > nextLength
+
+proc merge(int target[], int p1[], int l1, int p2[], int l2, int storage[]) =
+  # Merge the sorted arrays p1, p2 of length l1, l2 into a single
+  # sorted array starting at target. target may overlap with either
+  # of p1 or p2 but must have enough space to store the array.
+  # Use the storage argument for temporary storage. It must have room for
+  # l1 + l2 ints.
+  int *merge_to = storage
+
+  # Current index into each of the two arrays we're writing
+  # from.
+  int i1, i2;
+  i1 = i2 = 0;
+
+  # The address to which we write the next element in the merge
+  int *next_merge_element = merge_to;
+
+  # Iterate over the two arrays, writing the least element at the
+  # current position to merge_to. When the two are equal we prefer
+  # the left one, because if we're merging left, right we want to
+  # ensure stability.
+  # Of course this doesn't matter for integers, but it's the thought
+  # that counts.
+  while i1 < l1 and i2 < l2:
+    if p1[i1] <= p2[i2]:
+      *next_merge_element = p1[i1];
+      i1++
+    else:
+      *next_merge_element = p2[i2];
+      i2++
+    next_merge_element++
+
+  # If we stopped short before the end of one of the arrays
+  # we now copy the rest over.
+  memcpy(next_merge_element, p1 + i1, sizeof(int) * (l1 - i1));
+  memcpy(next_merge_element, p2 + i2, sizeof(int) * (l2 - i2));
+
+  # We've now merged into our additional working space. Time
+  # to copy to the target.
+  memcpy(target, merge_to, sizeof(int) * (l1 + l2));
+
+
+proc mergeCollapse(a:  s: var TSortState) =
+  var X = s.runs[s.stackHeight-2]
+  var Y = s.runs[s.stackHeight-1]
+
+  merge(X.index, X.index, X.length, Y.index, Y.length, s.storage)
+
+  dec s.stackHeight
+  inc X.length, Y.length
+  s.runs[s.stackHeight-1] = X
+
+proc sort[T](arr: var openArray[T], first, last: natural, 
+             cmp: proc (x,y: T): int, order = TSortOrder.ascending) =
+  var s: TSortState
+  newSeq(s.storage, arr.len)
+  s.stackHeight = 0
+  s.partitionedUpTo = 0
+  s.length = arr.len
+
+  while nextPartition(s):
+    while shouldCollapse(s): mergeCollapse(s)
+  while s.stackHeight > 1: mergeCollapse(s)
+
+proc sort[T](arr: var openArray[T], cmp: proc (x, y: T): int = cmp, 
+             order = TSortOrder.ascending) = 
+  sort(arr, 0, high(arr), order)
+
diff --git a/tests/accept/run/ttoseq.nim b/tests/accept/run/ttoseq.nim
new file mode 100644
index 000000000..d3332cce6
--- /dev/null
+++ b/tests/accept/run/ttoseq.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "23456"  
+"""
+
+template toSeq*(iter: expr): expr =
+  var result: seq[type(iter)] = @[]
+  for x in iter: add(result, x)
+  result
+  
+for x, y in items(toSeq(countup(2, 6))).withIndex: 
+  stdout.write(x)
+
diff --git a/todo.txt b/todo.txt
index 5fa136e1f..ab892de8c 100755
--- a/todo.txt
+++ b/todo.txt
@@ -1,5 +1,4 @@
 - 'nimrod def': does not always work
-- BUG: gcleak.nim
 
 - thread support: threadvar on Windows seems broken; 
   add --deadlock_prevention:on|off switch
diff --git a/web/news.txt b/web/news.txt
index 172630467..805c9b200 100755
--- a/web/news.txt
+++ b/web/news.txt
@@ -20,7 +20,8 @@ Bugfixes
 - Bugfix: Multiple yield statements in iterators did not cause local vars to be
   copied.
 - Bugfix: The compiler does not emit very inaccurate floating point literals
-  anymore. 
+  anymore.
+- Lots of other bugfixes: Too many to list them all.
 
 
 Changes affecting backwards compatibility
@@ -65,6 +66,9 @@ Additions
 - Added ``math.floor``.
 - The *interactive mode* (REPL) has been improved and documented for the 
   first time.
+- Added the ``linearScanEnd`` and ``unroll`` pragmas.
+- The compiler now might use a hashing for string case statements depending
+  on the number of string literals in the case statement.
 
 
 2010-10-20 Version 0.8.10 released