summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--boot.nim13
-rw-r--r--config/nimrod.cfg27
-rw-r--r--data/advopt.txt1
-rw-r--r--data/magic.yml3
-rw-r--r--data/messages.yml6
-rw-r--r--doc/filelist.txt2
-rw-r--r--doc/grammar.txt2
-rw-r--r--doc/intern.txt31
-rw-r--r--doc/lib.txt13
-rw-r--r--doc/manual.txt2
-rw-r--r--doc/theindex.txt492
-rw-r--r--doc/tut2.txt5
-rw-r--r--examples/hallo.nim6
-rw-r--r--examples/htmlrefs.nim3
-rw-r--r--examples/htmltitle.nim3
-rw-r--r--examples/statcsv.nim60
-rw-r--r--ide/nimide.nim146
-rw-r--r--install.txt133
-rw-r--r--koch.py80
-rw-r--r--lib/alloc.nim217
-rw-r--r--lib/ansi_c.nim6
-rw-r--r--lib/assign.nim8
-rw-r--r--lib/base/cgi.nim119
-rw-r--r--lib/excpt.nim20
-rw-r--r--lib/gc.nim368
-rw-r--r--lib/lexbase.nim2
-rw-r--r--lib/macros.nim18
-rw-r--r--lib/math.nim35
-rw-r--r--lib/memman.nim698
-rw-r--r--lib/mm.nim187
-rw-r--r--lib/os.nim2
-rw-r--r--lib/osproc.nim92
-rw-r--r--lib/parsecsv.nim176
-rw-r--r--lib/parsexml.nim2
-rw-r--r--lib/ptrset.nim205
-rw-r--r--lib/repr.nim6
-rw-r--r--lib/strutils.nim9
-rw-r--r--lib/sysio.nim9
-rw-r--r--lib/sysstr.nim23
-rw-r--r--lib/system.nim98
-rw-r--r--lib/windows/windows.nim2
-rw-r--r--lib/winlean.nim108
-rw-r--r--lib/wz_jsgraphics.js1107
-rw-r--r--lib/xmlgen.nim406
-rw-r--r--nim/ast.pas52
-rw-r--r--nim/astalgo.pas2
-rw-r--r--nim/ccgexprs.pas27
-rw-r--r--nim/ccgstmts.pas4
-rw-r--r--nim/ccgutils.pas2
-rw-r--r--nim/cgen.pas2
-rw-r--r--nim/commands.pas971
-rw-r--r--nim/condsyms.pas2
-rw-r--r--nim/docgen.pas16
-rw-r--r--nim/ecmasgen.pas2
-rw-r--r--nim/evals.pas63
-rw-r--r--nim/extccomp.pas6
-rw-r--r--nim/hashtest.pas2
-rw-r--r--nim/highlite.pas2
-rw-r--r--nim/idents.pas2
-rw-r--r--nim/interact.pas2
-rw-r--r--nim/magicsys.pas2
-rw-r--r--nim/main.pas2
-rw-r--r--nim/msgs.pas10
-rw-r--r--nim/nhashes.pas (renamed from nim/hashes.pas)2
-rw-r--r--nim/nstrtabs.pas (renamed from nim/strtabs.pas)10
-rw-r--r--nim/nversion.pas80
-rw-r--r--nim/options.pas6
-rw-r--r--nim/osproc.pas30
-rw-r--r--nim/parsecfg.pas2
-rw-r--r--nim/paslex.pas2
-rw-r--r--nim/pragmas.pas4
-rw-r--r--nim/ropes.pas2
-rw-r--r--nim/rst.pas24
-rw-r--r--nim/scanner.pas2
-rw-r--r--nim/sem.pas43
-rw-r--r--nim/semdata.pas1
-rw-r--r--nim/semfold.pas28
-rw-r--r--nim/semstmts.pas3
-rw-r--r--nim/tigen.pas2
-rw-r--r--nim/transf.pas2
-rw-r--r--nim/treetab.pas2
-rw-r--r--nim/wordrecg.pas2
-rw-r--r--objdata.txt8
-rw-r--r--rod/nimrod.ini1
-rw-r--r--tests/csvtest.csv8
-rw-r--r--tests/data.csv6
-rw-r--r--tests/gctest.nim25
-rw-r--r--tests/toop1.nim2
-rw-r--r--todo.txt118
-rw-r--r--tools/niminstbin311978 -> 295608 bytes
-rw-r--r--tools/nimweb.nim10
-rw-r--r--tools/sunset.tmpl4
92 files changed, 3081 insertions, 3470 deletions
diff --git a/boot.nim b/boot.nim
index 7b1745391..b7e2b221f 100644
--- a/boot.nim
+++ b/boot.nim
@@ -11,7 +11,10 @@ import
   os, strutils
 
 const
-  BootCmd = "nimrod cc --compile:build/platdef.c $1 rod/nimrod.nim"
+  BootCmd = [
+    "nimrod cc --compile:build/platdef.c $1 rod/nimrod.nim",
+    "bin/nimrod cc --compile:build/platdef.c $1 rod/nimrod.nim"
+  ]
   PlatdefCTmpl = """
 /* Generated by boot.nim */
 char* nimOS(void) { return "$1"; }
@@ -32,7 +35,7 @@ proc writePlatdefC =
   
 proc rodsrc = 
   const
-    blacklist = ["nsystem", "nmath", "nos", "ntime", "strutils"]
+    blacklist = ["nsystem", "nmath", "nos", "osproc", "ntime", "strutils"]
     cmd = "nimrod boot --skip_proj_cfg -o:rod/$1.nim nim/$1"
   for fi in walkFiles("nim/*.pas"):
     var f = extractFileTrunk(fi)
@@ -46,10 +49,10 @@ proc boot(args: string) =
   rodsrc()
   var newExe = appendFileExt("rod/nimrod", ExeExt)
   var oldExe = appendFileExt("bin/nimrod", ExeExt)
-  for i in 1..2:
-    Echo("iteration: ", $i)
+  for i in 0..1:
+    Echo("iteration: ", $(i+1))
     # use the new executable to compile the files in the bootstrap directory:
-    Exec(Bootcmd % args)
+    Exec(Bootcmd[i] % args)
     if sameFileContent(newExe, oldExe): 
       Echo("executables are equal: SUCCESS!")
       return
diff --git a/config/nimrod.cfg b/config/nimrod.cfg
index e06472cf5..4eb7b785b 100644
--- a/config/nimrod.cfg
+++ b/config/nimrod.cfg
@@ -51,6 +51,20 @@ hint[LineTooLong]=off
   passc = "-cxxlib"

 @end

 

+# Configuration for the GNU C/C++ compiler:

+@if windows:

+  gcc.path = r"$nimrod\dist\mingw\bin"

+@end

+gcc.options.debug = "-g"

+@if macosx:

+  gcc.options.always = "-w -fasm-blocks"

+@else:

+  gcc.options.always = "-w"

+@end

+gcc.options.speed = "-O3 -fno-strict-aliasing"

+gcc.options.size = "-Os"

+#passl = "-pg"

+

 # Configuration for the LLVM GCC compiler:

 llvm_gcc.options.debug = "-g"

 llvm_gcc.options.always = "-w"

@@ -66,19 +80,6 @@ vcc.options.always = "/nologo"
 vcc.options.speed = "/Ox /arch:SSE2"

 vcc.options.size = "/O1"

 

-# Configuration for the GNU C/C++ compiler:

-@if windows:

-  gcc.path = r"$nimrod\dist\mingw\bin"

-@end

-gcc.options.debug = "-g"

-@if macosx:

-  gcc.options.always = "-w -fasm-blocks"

-@else:

-  gcc.options.always = "-w"

-@end

-gcc.options.speed = "-O3 -fno-strict-aliasing"

-gcc.options.size = "-Os"

-

 # Configuration for the Digital Mars C/C++ compiler:

 @if windows:

   dmc.path = r"$nimrod\dist\dm\bin"

diff --git a/data/advopt.txt b/data/advopt.txt
index 1fc1f4845..4cdbc5d0f 100644
--- a/data/advopt.txt
+++ b/data/advopt.txt
@@ -27,6 +27,7 @@ Advanced options:
   --checkpoints:on|off      turn on|off checkpoints; for debugging Nimrod
   --skip_cfg                do not read the general configuration file
   --skip_proj_cfg           do not read the project's configuration file
+  --gc:refc|boehm           use Nimrod's native GC|Boehm GC
   --index:FILE              use FILE to generate a documenation index file
   --putenv:key=value        set an environment variable
   --list_cmd                list the commands used to execute external programs
diff --git a/data/magic.yml b/data/magic.yml
index b569159e4..19013ccc4 100644
--- a/data/magic.yml
+++ b/data/magic.yml
@@ -176,6 +176,9 @@
 'Swap',
 'IsNil',
 'ArrToSeq',
+'CopyStr',
+'CopyStrLast',
+'NewString',
 
 # magic types:
 'Array',
diff --git a/data/messages.yml b/data/messages.yml
index b5b37c6c5..4a2154613 100644
--- a/data/messages.yml
+++ b/data/messages.yml
@@ -46,7 +46,7 @@
 {'errExceptionExpected': 'exception expected'},
 {'errExceptionAlreadyHandled': 'exception already handled'},
 {'errReturnNotAllowedHere': "'return' only allowed in routine"},
-{'errYieldNotAllowedHere': "'yield' only allowed in iterator"},
+{'errYieldNotAllowedHere': "'yield' only allowed in a loop of an iterator"},
 {'errInvalidNumberOfYieldExpr': "invalid number of 'yield' expresions"},
 {'errReturnInvalidInIterator': "'return' not allowed in iterator"},
 {'errCannotReturnExpr': 'current routine cannot return an expression'},
@@ -54,10 +54,10 @@
 {'errStmtInvalidAfterReturn':
   "statement not allowed after 'return', 'break' or 'raise'"},
 {'errStmtExpected': 'statement expected'},
-{'errYieldOnlyInInterators': "'yield' statement is only allowed in iterators"},
 {'errInvalidLabel': "'$1' is no label"},
 {'errInvalidCmdLineOption': "invalid command line option: '$1'"},
 {'errCmdLineArgExpected': "argument for command line option expected: '$1'"},
+{'errCmdLineNoArgExpected': "invalid argument for command line option: '$1'"},
 {'errInvalidVarSubstitution': "invalid variable substitution in '$1'"},
 {'errUnknownVar': "unknown variable: '$1'"},
 {'errUnknownCcompiler': "unknown C compiler: '$1'"},
@@ -105,7 +105,7 @@
   "argument to 'staticAssert' cannot be evaluated at compile time"},
 {'errDotRequiresRecordOrObjectType': "'.' requires a record or object type"},
 {'errUndeclaredFieldX': "undeclared field: '$1'"},
-{'errIndexNoIntType': 'index has to be an integer type'},
+{'errNilAccess': 'attempt to access a nil address'},
 {'errIndexOutOfBounds': 'index out of bounds'},
 {'errIndexTypesDoNotMatch': 'index types do not match'},
 {'errBracketsInvalidForType': "'[]' operator invalid for this type"},
diff --git a/doc/filelist.txt b/doc/filelist.txt
index e094b6fb3..0e636652a 100644
--- a/doc/filelist.txt
+++ b/doc/filelist.txt
@@ -7,6 +7,8 @@ Module          Description
 nimrod          main module: parses the command line and calls
                 ``main.MainCommand``
 main            implements the top-level command dispatching
+nimconf         implements the config file reader
+
 lexbase         buffer handling of the lexical analyser
 scanner         lexical analyser
 pnimsyn         Nimrod's parser
diff --git a/doc/grammar.txt b/doc/grammar.txt
index 9fbd1eb15..11e26e33f 100644
--- a/doc/grammar.txt
+++ b/doc/grammar.txt
@@ -30,7 +30,7 @@ symbol ::= '`' (KEYWORD | IDENT | operator | '(' ')'
                | '[' ']' | '=' | literal)+ '`'
          | IDENT
 primary ::= (prefixOperator optInd)* (symbol | constructor |
-                                             | castExpr | addrExpr) (
+                                      castExpr | addrExpr) (
                '.' optInd symbol
              | '(' optInd namedExprList [SAD] ')'
              | '[' optInd
diff --git a/doc/intern.txt b/doc/intern.txt
index 6496e0e29..646cb9d9c 100644
--- a/doc/intern.txt
+++ b/doc/intern.txt
@@ -18,6 +18,7 @@ The Nimrod project's directory structure is:
 Path           Purpose
 ============   ==============================================
 ``bin``        binary files go into here
+``build``      generated C code for the installation
 ``nim``        Pascal sources of the Nimrod compiler; this
                should be modified, not the Nimrod version in
                ``rod``!
@@ -28,7 +29,7 @@ Path           Purpose
                code go into here
 ``doc``        the documentation lives here; it is a bunch of
                reStructuredText files
-``dist``       download packages as zip archives go into here
+``dist``       additional packages for the distribution
 ``config``     configuration files for Nimrod go into here
 ``lib``        the Nimrod library lives here; ``rod`` depends
                on it!
@@ -45,8 +46,8 @@ The compiler is written in a subset of Pascal with special annotations so
 that it can be translated to Nimrod code automatically. This conversion is
 done by Nimrod itself via the undocumented ``boot`` command. Thus both Nimrod
 and Free Pascal can compile the Nimrod compiler. However, the Pascal version
-has no garbage collector and leaks memory like crazy! So the Pascal version
-should only be used for bootstrapping.
+has no garbage collector and leaks memory! So the Pascal version should only 
+be used for bootstrapping.
 
 Requirements for bootstrapping:
 
@@ -214,7 +215,7 @@ address within this page. So including a cell is done as follows:
 
 Removing a cell is analogous - the bit has to be set to zero.
 Single page descriptors are never deleted from the hash table. This is not
-needed as the data structures need to be periodically rebuilt anyway.
+needed as the data structures needs to be rebuilt periodically anyway.
 
 Complete traversal is done in this way::
 
@@ -288,11 +289,8 @@ The synax tree consists of nodes which may have an arbitrary number of
 children. Types and symbols are represented by other nodes, because they
 may contain cycles. The AST changes its shape after semantic checking. This
 is needed to make life easier for the code generators. See the "ast" module
-for the type definitions.
-
-I use the notation ``nodeKind(fields, [sons])`` for describing
-nodes. ``nodeKind[sons]`` is a short-cut for ``nodeKind([sons])``.
-XXX: Description of the language's syntax and the corresponding trees.
+for the type definitions. The `macros <macros.html>`_ module contains many
+examples how the AST represents each syntactic structure. 
 
 
 How the RTL is compiled
@@ -310,6 +308,21 @@ semantic checking, a ``compilerproc`` is a proc that is used by the code
 generator.
 
 
+Debugging Nimrod's memory management
+====================================
+
+The following paragraphs are mostly a reminder for myself. Things to keep
+in mind:
+
+* Segmentation faults can have multiple reasons: One that is frequently
+  forgotten is that *stack overflow* can trigger one!
+* If an assertion in Nimrod's memory manager or GC fails, the stack trace
+  keeps allocating memory! Thus a stack overflow may happen, hiding the
+  real issue. 
+* What seem to be C code generation problems is often a bug resulting from
+  not producing prototypes, so that some types default to ``cint``. Testing
+  without the ``-w`` option helps!
+
 
 Generation of dynamic link libraries
 ====================================
diff --git a/doc/lib.txt b/doc/lib.txt
index b45c02262..0b11c28cc 100644
--- a/doc/lib.txt
+++ b/doc/lib.txt
@@ -22,6 +22,9 @@ Pure libraries
   implicitly by the compiler. Do not import it directly. It relies on compiler
   magic to work.
 
+* `macros <macros.html>`_ 
+  Contains the AST API and documentation of Nimrod for writing macros.
+
 * `strutils <strutils.html>`_
   This module contains common string handling operations like converting a
   string into uppercase, splitting a string into substrings, searching for
@@ -33,6 +36,9 @@ Pure libraries
   commands, etc. This module is -- like any other basic library --
   platform independant.
 
+* `osproc <osproc.html>`_
+  Module for process communication beyond ``os.executeShellCommand``.
+
 * `math <math.html>`_
   Mathematical operations like cosine, square root.
 
@@ -60,6 +66,9 @@ Pure libraries
   to be somewhat error correcting, so that even some "wild HTML" found on the 
   web can be parsed with it.
 
+* `parsecsv <parsecsv.html>`_ 
+  The ``parsecsv`` module implements a simple high performance CSV parser.
+
 * `strtabs <strtabs.html>`_
   The ``strtabs`` module implements an efficient hash table that is a mapping
   from strings to strings. Supports a case-sensitive, case-insensitive and
@@ -98,6 +107,10 @@ Pure libraries
 * `md5 <md5.html>`_
   This module implements the MD5 checksum algorithm.
 
+* `xmlgen <xmlgen.html>`_
+  This module implements macros for HTML code generation.
+
+
 
 Impure libraries
 ================
diff --git a/doc/manual.txt b/doc/manual.txt
index 2fa24f756..9acaae3cd 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -1649,7 +1649,7 @@ possible within a single ``type`` section.
 Generics
 ~~~~~~~~
 
-`Version 0.7.6: Generic types like in the example do not work.`:red:
+`Version 0.7.8: Generic types like in the example do not work.`:red:
 
 Example:
 
diff --git a/doc/theindex.txt b/doc/theindex.txt
index 6aeb786fa..06be1fc5d 100644
--- a/doc/theindex.txt
+++ b/doc/theindex.txt
@@ -6,6 +6,9 @@ Index
 .. index::
 
 
+   `!`:idx:
+     `macros.html#115 <macros.html#115>`_
+
    `!=`:idx:
      `system.html#351 <system.html#351>`_
 
@@ -20,6 +23,7 @@ Index
      * `system.html#429 <system.html#429>`_
      * `times.html#109 <times.html#109>`_
      * `times.html#110 <times.html#110>`_
+     * `macros.html#116 <macros.html#116>`_
 
    `%`:idx:
      * `strutils.html#111 <strutils.html#111>`_
@@ -176,6 +180,7 @@ Index
      * `system.html#305 <system.html#305>`_
 
    `==`:idx:
+     * `md5.html#107 <md5.html#107>`_
      * `system.html#246 <system.html#246>`_
      * `system.html#247 <system.html#247>`_
      * `system.html#248 <system.html#248>`_
@@ -193,7 +198,7 @@ Index
      * `system.html#335 <system.html#335>`_
      * `system.html#458 <system.html#458>`_
      * `complex.html#102 <complex.html#102>`_
-     * `md5.html#107 <md5.html#107>`_
+     * `macros.html#117 <macros.html#117>`_
 
    `=~`:idx:
      `regexprs.html#111 <regexprs.html#111>`_
@@ -216,12 +221,21 @@ Index
    `[]`:idx:
      `strtabs.html#107 <strtabs.html#107>`_
 
+   `[]`:idx:
+     `macros.html#113 <macros.html#113>`_
+
    `[]=`:idx:
      `strtabs.html#106 <strtabs.html#106>`_
 
+   `[]=`:idx:
+     `macros.html#114 <macros.html#114>`_
+
    `[ESC]`:idx:
      `manual.html#134 <manual.html#134>`_
 
+   `a`:idx:
+     `xmlgen.html#107 <xmlgen.html#107>`_
+
    `abs`:idx:
      * `system.html#261 <system.html#261>`_
      * `system.html#262 <system.html#262>`_
@@ -231,6 +245,9 @@ Index
      * `system.html#320 <system.html#320>`_
      * `complex.html#108 <complex.html#108>`_
 
+   `acronym`:idx:
+     `xmlgen.html#108 <xmlgen.html#108>`_
+
    `acyclic`:idx:
      `nimrodc.html#113 <nimrodc.html#113>`_
 
@@ -240,6 +257,8 @@ Index
      * `system.html#368 <system.html#368>`_
      * `system.html#369 <system.html#369>`_
      * `system.html#370 <system.html#370>`_
+     * `macros.html#119 <macros.html#119>`_
+     * `macros.html#120 <macros.html#120>`_
 
    `addf`:idx:
      `strutils.html#113 <strutils.html#113>`_
@@ -252,6 +271,9 @@ Index
    `addQuitProc`:idx:
      `system.html#404 <system.html#404>`_
 
+   `address`:idx:
+     `xmlgen.html#109 <xmlgen.html#109>`_
+
    `addSep`:idx:
      `strutils.html#151 <strutils.html#151>`_
 
@@ -302,6 +324,9 @@ Index
    `arctan2`:idx:
      `math.html#125 <math.html#125>`_
 
+   `area`:idx:
+     `xmlgen.html#110 <xmlgen.html#110>`_
+
    `arithmetic bit shifts`:idx:
      `tut1.html#110 <tut1.html#110>`_
 
@@ -321,6 +346,9 @@ Index
    `assert`:idx:
      `system.html#418 <system.html#418>`_
 
+   `AST`:idx:
+     `macros.html#101 <macros.html#101>`_
+
    `attrKey`:idx:
      `parsexml.html#113 <parsexml.html#113>`_
 
@@ -334,6 +362,9 @@ Index
      * `manual.html#144 <manual.html#144>`_
      * `tut1.html#111 <tut1.html#111>`_
 
+   `b`:idx:
+     `xmlgen.html#111 <xmlgen.html#111>`_
+
    `backslash`:idx:
      * `manual.html#127 <manual.html#127>`_
      * `regexprs.html#101 <regexprs.html#101>`_
@@ -341,6 +372,12 @@ Index
    `backspace`:idx:
      `manual.html#132 <manual.html#132>`_
 
+   `base`:idx:
+     `xmlgen.html#112 <xmlgen.html#112>`_
+
+   `big`:idx:
+     `xmlgen.html#113 <xmlgen.html#113>`_
+
    `BiggestFloat`:idx:
      `system.html#374 <system.html#374>`_
 
@@ -362,6 +399,12 @@ Index
    `block`:idx:
      `manual.html#192 <manual.html#192>`_
 
+   `blockquote`:idx:
+     `xmlgen.html#114 <xmlgen.html#114>`_
+
+   `body`:idx:
+     `xmlgen.html#115 <xmlgen.html#115>`_
+
    `bool`:idx:
      `system.html#109 <system.html#109>`_
 
@@ -369,12 +412,18 @@ Index
      * `manual.html#146 <manual.html#146>`_
      * `tut1.html#107 <tut1.html#107>`_
 
+   `br`:idx:
+     `xmlgen.html#116 <xmlgen.html#116>`_
+
    `break`:idx:
      `manual.html#193 <manual.html#193>`_
 
    `breakpoint`:idx:
      `endb.html#103 <endb.html#103>`_
 
+   `button`:idx:
+     `xmlgen.html#117 <xmlgen.html#117>`_
+
    `Byte`:idx:
      `system.html#128 <system.html#128>`_
 
@@ -384,6 +433,9 @@ Index
    `capitalize`:idx:
      `strutils.html#119 <strutils.html#119>`_
 
+   `caption`:idx:
+     `xmlgen.html#118 <xmlgen.html#118>`_
+
    `card`:idx:
      `system.html#169 <system.html#169>`_
 
@@ -450,6 +502,9 @@ Index
    `cint`:idx:
      `system.html#378 <system.html#378>`_
 
+   `cite`:idx:
+     `xmlgen.html#119 <xmlgen.html#119>`_
+
    `classify`:idx:
      `math.html#104 <math.html#104>`_
 
@@ -532,6 +587,7 @@ Index
      * `lexbase.html#105 <lexbase.html#105>`_
      * `parsecfg.html#105 <parsecfg.html#105>`_
      * `parsexml.html#108 <parsexml.html#108>`_
+     * `parsecsv.html#109 <parsecsv.html#109>`_
      * `zipfiles.html#103 <zipfiles.html#103>`_
 
    `CloseFile`:idx:
@@ -556,6 +612,18 @@ Index
    `cmpRunesIgnoreCase`:idx:
      `unicode.html#115 <unicode.html#115>`_
 
+   `code`:idx:
+     `xmlgen.html#120 <xmlgen.html#120>`_
+
+   `col`:idx:
+     `xmlgen.html#121 <xmlgen.html#121>`_
+
+   `colgroup`:idx:
+     `xmlgen.html#122 <xmlgen.html#122>`_
+
+   `comma separated value`:idx:
+     `parsecsv.html#102 <parsecsv.html#102>`_
+
    `comment pieces`:idx:
      * `manual.html#115 <manual.html#115>`_
      * `tut1.html#103 <tut1.html#103>`_
@@ -564,6 +632,9 @@ Index
      * `manual.html#114 <manual.html#114>`_
      * `tut1.html#102 <tut1.html#102>`_
 
+   `commonAttr`:idx:
+     `xmlgen.html#105 <xmlgen.html#105>`_
+
    `COMP_HEADER_SIZE`:idx:
      `mysql.html#266 <mysql.html#266>`_
 
@@ -605,6 +676,15 @@ Index
    `copyMem`:idx:
      `system.html#410 <system.html#410>`_
 
+   `copyNimNode`:idx:
+     `macros.html#136 <macros.html#136>`_
+
+   `copyNimTree`:idx:
+     `macros.html#137 <macros.html#137>`_
+
+   `coreAttr`:idx:
+     `xmlgen.html#103 <xmlgen.html#103>`_
+
    `cos`:idx:
      `math.html#126 <math.html#126>`_
 
@@ -642,6 +722,9 @@ Index
    `cstringArray`:idx:
      `system.html#384 <system.html#384>`_
 
+   `CSV`:idx:
+     `parsecsv.html#101 <parsecsv.html#101>`_
+
    `cuint`:idx:
      `mysql.html#109 <mysql.html#109>`_
 
@@ -1014,6 +1097,9 @@ Index
    `dbgLineHook`:idx:
      `system.html#435 <system.html#435>`_
 
+   `dd`:idx:
+     `xmlgen.html#123 <xmlgen.html#123>`_
+
    `dead_code_elim`:idx:
      `nimrodc.html#114 <nimrodc.html#114>`_
 
@@ -1026,15 +1112,25 @@ Index
    `dec`:idx:
      `system.html#160 <system.html#160>`_
 
+   `decodeData`:idx:
+     `cgi.html#107 <cgi.html#107>`_
+
    `define`:idx:
      `manual.html#222 <manual.html#222>`_
 
    `defined`:idx:
      `system.html#114 <system.html#114>`_
 
+   `del`:idx:
+     * `xmlgen.html#124 <xmlgen.html#124>`_
+     * `macros.html#121 <macros.html#121>`_
+
    `deleteStr`:idx:
      `strutils.html#129 <strutils.html#129>`_
 
+   `dfn`:idx:
+     `xmlgen.html#125 <xmlgen.html#125>`_
+
    `Digits`:idx:
      `strutils.html#104 <strutils.html#104>`_
 
@@ -1050,6 +1146,10 @@ Index
      * `system.html#213 <system.html#213>`_
      * `system.html#214 <system.html#214>`_
      * `system.html#215 <system.html#215>`_
+     * `xmlgen.html#126 <xmlgen.html#126>`_
+
+   `dl`:idx:
+     `xmlgen.html#127 <xmlgen.html#127>`_
 
    `dom`:idx:
      `nimrodc.html#120 <nimrodc.html#120>`_
@@ -1058,6 +1158,9 @@ Index
      * `manual.html#211 <manual.html#211>`_
      * `tut2.html#111 <tut2.html#111>`_
 
+   `dt`:idx:
+     `xmlgen.html#128 <xmlgen.html#128>`_
+
    `dynamic type`:idx:
      `manual.html#104 <manual.html#104>`_
 
@@ -1099,11 +1202,14 @@ Index
      `system.html#145 <system.html#145>`_
 
    `editDistance`:idx:
-     `strutils.html#158 <strutils.html#158>`_
+     `strutils.html#159 <strutils.html#159>`_
 
    `EDivByZero`:idx:
      `system.html#141 <system.html#141>`_
 
+   `EInvalidCsv`:idx:
+     `parsecsv.html#105 <parsecsv.html#105>`_
+
    `EInvalidField`:idx:
      `system.html#149 <system.html#149>`_
 
@@ -1128,6 +1234,9 @@ Index
    `elementName`:idx:
      `parsexml.html#111 <parsexml.html#111>`_
 
+   `em`:idx:
+     `xmlgen.html#129 <xmlgen.html#129>`_
+
    `Embedded Nimrod Debugger`:idx:
      `endb.html#101 <endb.html#101>`_
 
@@ -1204,6 +1313,7 @@ Index
    `error`:idx:
      * `manual.html#221 <manual.html#221>`_
      * `manual.html#224 <manual.html#224>`_
+     * `macros.html#138 <macros.html#138>`_
 
    `errorMsg`:idx:
      `parsexml.html#120 <parsexml.html#120>`_
@@ -1230,6 +1340,9 @@ Index
    `ESystem`:idx:
      `system.html#136 <system.html#136>`_
 
+   `eventAttr`:idx:
+     `xmlgen.html#104 <xmlgen.html#104>`_
+
    `except`:idx:
      `manual.html#187 <manual.html#187>`_
 
@@ -1263,9 +1376,21 @@ Index
    `expandFilename`:idx:
      `os.html#116 <os.html#116>`_
 
+   `expectKind`:idx:
+     `macros.html#147 <macros.html#147>`_
+
+   `expectLen`:idx:
+     `macros.html#149 <macros.html#149>`_
+
+   `expectMinLen`:idx:
+     `macros.html#148 <macros.html#148>`_
+
    `exportc`:idx:
      `nimrodc.html#102 <nimrodc.html#102>`_
 
+   `expr`:idx:
+     `macros.html#111 <macros.html#111>`_
+
    `expression macros`:idx:
      `tut2.html#112 <tut2.html#112>`_
 
@@ -1293,6 +1418,9 @@ Index
    `fatal`:idx:
      `manual.html#225 <manual.html#225>`_
 
+   `fieldset`:idx:
+     `xmlgen.html#130 <xmlgen.html#130>`_
+
    `FIELD_TYPE_BIT`:idx:
      `mysql.html#231 <mysql.html#231>`_
 
@@ -1419,6 +1547,12 @@ Index
    `float64`:idx:
      `system.html#108 <system.html#108>`_
 
+   `floatVal`:idx:
+     `macros.html#124 <macros.html#124>`_
+
+   `floatVal=`:idx:
+     `macros.html#130 <macros.html#130>`_
+
    `FlushFile`:idx:
      `system.html#492 <system.html#492>`_
 
@@ -1426,6 +1560,9 @@ Index
      * `manual.html#203 <manual.html#203>`_
      * `tut1.html#105 <tut1.html#105>`_
 
+   `form`:idx:
+     `xmlgen.html#131 <xmlgen.html#131>`_
+
    `form feed`:idx:
      `manual.html#124 <manual.html#124>`_
 
@@ -1503,10 +1640,10 @@ Index
      `os.html#115 <os.html#115>`_
 
    `getContentLength`:idx:
-     `cgi.html#109 <cgi.html#109>`_
+     `cgi.html#110 <cgi.html#110>`_
 
    `getContentType`:idx:
-     `cgi.html#110 <cgi.html#110>`_
+     `cgi.html#111 <cgi.html#111>`_
 
    `getCurrentDir`:idx:
      `os.html#112 <os.html#112>`_
@@ -1521,7 +1658,7 @@ Index
      `times.html#111 <times.html#111>`_
 
    `getDocumentRoot`:idx:
-     `cgi.html#111 <cgi.html#111>`_
+     `cgi.html#112 <cgi.html#112>`_
 
    `getEnv`:idx:
      `os.html#143 <os.html#143>`_
@@ -1540,7 +1677,7 @@ Index
      `system.html#437 <system.html#437>`_
 
    `getGatewayInterface`:idx:
-     `cgi.html#112 <cgi.html#112>`_
+     `cgi.html#113 <cgi.html#113>`_
 
    `getGMTime`:idx:
      `times.html#107 <times.html#107>`_
@@ -1549,31 +1686,31 @@ Index
      `os.html#114 <os.html#114>`_
 
    `getHttpAccept`:idx:
-     `cgi.html#113 <cgi.html#113>`_
+     `cgi.html#114 <cgi.html#114>`_
 
    `getHttpAcceptCharset`:idx:
-     `cgi.html#114 <cgi.html#114>`_
+     `cgi.html#115 <cgi.html#115>`_
 
    `getHttpAcceptEncoding`:idx:
-     `cgi.html#115 <cgi.html#115>`_
+     `cgi.html#116 <cgi.html#116>`_
 
    `getHttpAcceptLanguage`:idx:
-     `cgi.html#116 <cgi.html#116>`_
+     `cgi.html#117 <cgi.html#117>`_
 
    `getHttpConnection`:idx:
-     `cgi.html#117 <cgi.html#117>`_
+     `cgi.html#118 <cgi.html#118>`_
 
    `getHttpCookie`:idx:
-     `cgi.html#118 <cgi.html#118>`_
+     `cgi.html#119 <cgi.html#119>`_
 
    `getHttpHost`:idx:
-     `cgi.html#119 <cgi.html#119>`_
+     `cgi.html#120 <cgi.html#120>`_
 
    `getHttpReferer`:idx:
-     `cgi.html#120 <cgi.html#120>`_
+     `cgi.html#121 <cgi.html#121>`_
 
    `getHttpUserAgent`:idx:
-     `cgi.html#121 <cgi.html#121>`_
+     `cgi.html#122 <cgi.html#122>`_
 
    `getLastModificationTime`:idx:
      `os.html#140 <os.html#140>`_
@@ -1595,37 +1732,37 @@ Index
      `parseopt.html#106 <parseopt.html#106>`_
 
    `getPathInfo`:idx:
-     `cgi.html#122 <cgi.html#122>`_
+     `cgi.html#123 <cgi.html#123>`_
 
    `getPathTranslated`:idx:
-     `cgi.html#123 <cgi.html#123>`_
+     `cgi.html#124 <cgi.html#124>`_
 
    `getQueryString`:idx:
-     `cgi.html#124 <cgi.html#124>`_
+     `cgi.html#125 <cgi.html#125>`_
 
    `getRefcount`:idx:
      `system.html#430 <system.html#430>`_
 
    `getRemoteAddr`:idx:
-     `cgi.html#125 <cgi.html#125>`_
+     `cgi.html#126 <cgi.html#126>`_
 
    `getRemoteHost`:idx:
-     `cgi.html#126 <cgi.html#126>`_
+     `cgi.html#127 <cgi.html#127>`_
 
    `getRemoteIdent`:idx:
-     `cgi.html#127 <cgi.html#127>`_
+     `cgi.html#128 <cgi.html#128>`_
 
    `getRemotePort`:idx:
-     `cgi.html#128 <cgi.html#128>`_
+     `cgi.html#129 <cgi.html#129>`_
 
    `getRemoteUser`:idx:
-     `cgi.html#129 <cgi.html#129>`_
+     `cgi.html#130 <cgi.html#130>`_
 
    `getRequestMethod`:idx:
-     `cgi.html#130 <cgi.html#130>`_
+     `cgi.html#131 <cgi.html#131>`_
 
    `getRequestURI`:idx:
-     `cgi.html#131 <cgi.html#131>`_
+     `cgi.html#132 <cgi.html#132>`_
 
    `getRestOfCommandLine`:idx:
      `parseopt.html#105 <parseopt.html#105>`_
@@ -1637,31 +1774,31 @@ Index
      `mysql.html#274 <mysql.html#274>`_
 
    `getScriptFilename`:idx:
-     `cgi.html#132 <cgi.html#132>`_
+     `cgi.html#133 <cgi.html#133>`_
 
    `getScriptName`:idx:
-     `cgi.html#133 <cgi.html#133>`_
+     `cgi.html#134 <cgi.html#134>`_
 
    `getServerAddr`:idx:
-     `cgi.html#134 <cgi.html#134>`_
+     `cgi.html#135 <cgi.html#135>`_
 
    `getServerAdmin`:idx:
-     `cgi.html#135 <cgi.html#135>`_
+     `cgi.html#136 <cgi.html#136>`_
 
    `getServerName`:idx:
-     `cgi.html#136 <cgi.html#136>`_
+     `cgi.html#137 <cgi.html#137>`_
 
    `getServerPort`:idx:
-     `cgi.html#137 <cgi.html#137>`_
+     `cgi.html#138 <cgi.html#138>`_
 
    `getServerProtocol`:idx:
-     `cgi.html#138 <cgi.html#138>`_
+     `cgi.html#139 <cgi.html#139>`_
 
    `getServerSignature`:idx:
-     `cgi.html#139 <cgi.html#139>`_
+     `cgi.html#140 <cgi.html#140>`_
 
    `getServerSoftware`:idx:
-     `cgi.html#140 <cgi.html#140>`_
+     `cgi.html#141 <cgi.html#141>`_
 
    `getStartMilsecs`:idx:
      `times.html#116 <times.html#116>`_
@@ -1684,6 +1821,24 @@ Index
    `GROUP_FLAG`:idx:
      `mysql.html#139 <mysql.html#139>`_
 
+   `h1`:idx:
+     `xmlgen.html#132 <xmlgen.html#132>`_
+
+   `h2`:idx:
+     `xmlgen.html#133 <xmlgen.html#133>`_
+
+   `h3`:idx:
+     `xmlgen.html#134 <xmlgen.html#134>`_
+
+   `h4`:idx:
+     `xmlgen.html#135 <xmlgen.html#135>`_
+
+   `h5`:idx:
+     `xmlgen.html#136 <xmlgen.html#136>`_
+
+   `h6`:idx:
+     `xmlgen.html#137 <xmlgen.html#137>`_
+
    `HandleCR`:idx:
      `lexbase.html#108 <lexbase.html#108>`_
 
@@ -1712,6 +1867,9 @@ Index
    `hasKey`:idx:
      `strtabs.html#108 <strtabs.html#108>`_
 
+   `head`:idx:
+     `xmlgen.html#138 <xmlgen.html#138>`_
+
    `header`:idx:
      `nimrodc.html#105 <nimrodc.html#105>`_
 
@@ -1721,6 +1879,7 @@ Index
    `hint`:idx:
      * `manual.html#219 <manual.html#219>`_
      * `manual.html#227 <manual.html#227>`_
+     * `macros.html#140 <macros.html#140>`_
 
    `hostCPU`:idx:
      `system.html#399 <system.html#399>`_
@@ -1731,8 +1890,15 @@ Index
    `hostOS`:idx:
      `system.html#398 <system.html#398>`_
 
+   `hr`:idx:
+     `xmlgen.html#140 <xmlgen.html#140>`_
+
+   `html`:idx:
+     `xmlgen.html#139 <xmlgen.html#139>`_
+
    `HTML`:idx:
-     `parsexml.html#102 <parsexml.html#102>`_
+     * `parsexml.html#102 <parsexml.html#102>`_
+     * `xmlgen.html#102 <xmlgen.html#102>`_
 
    `HTTPPOST_BUFFER`:idx:
      `libcurl.html#266 <libcurl.html#266>`_
@@ -1755,6 +1921,15 @@ Index
    `hypot`:idx:
      `math.html#128 <math.html#128>`_
 
+   `i`:idx:
+     `xmlgen.html#141 <xmlgen.html#141>`_
+
+   `ident`:idx:
+     `macros.html#126 <macros.html#126>`_
+
+   `ident=`:idx:
+     `macros.html#132 <macros.html#132>`_
+
    `IdentChars`:idx:
      `strutils.html#105 <strutils.html#105>`_
 
@@ -1770,6 +1945,9 @@ Index
    `if`:idx:
      `manual.html#180 <manual.html#180>`_
 
+   `img`:idx:
+     `xmlgen.html#142 <xmlgen.html#142>`_
+
    `implicit block`:idx:
      `manual.html#205 <manual.html#205>`_
 
@@ -1808,6 +1986,12 @@ Index
    `inline`:idx:
      `manual.html#167 <manual.html#167>`_
 
+   `input`:idx:
+     `xmlgen.html#143 <xmlgen.html#143>`_
+
+   `ins`:idx:
+     `xmlgen.html#144 <xmlgen.html#144>`_
+
    `int`:idx:
      `system.html#101 <system.html#101>`_
 
@@ -1829,6 +2013,12 @@ Index
    `intToStr`:idx:
      `strutils.html#143 <strutils.html#143>`_
 
+   `intVal`:idx:
+     `macros.html#123 <macros.html#123>`_
+
+   `intVal=`:idx:
+     `macros.html#129 <macros.html#129>`_
+
    `is`:idx:
      `system.html#357 <system.html#357>`_
 
@@ -1903,15 +2093,25 @@ Index
      * `os.html#118 <os.html#118>`_
      * `os.html#120 <os.html#120>`_
 
+   `kbd`:idx:
+     `xmlgen.html#145 <xmlgen.html#145>`_
+
    `keywords`:idx:
      `manual.html#117 <manual.html#117>`_
 
    `kind`:idx:
-     `parsexml.html#110 <parsexml.html#110>`_
+     * `parsexml.html#110 <parsexml.html#110>`_
+     * `macros.html#122 <macros.html#122>`_
 
    `l-values`:idx:
      `manual.html#107 <manual.html#107>`_
 
+   `label`:idx:
+     `xmlgen.html#146 <xmlgen.html#146>`_
+
+   `legend`:idx:
+     `xmlgen.html#147 <xmlgen.html#147>`_
+
    `len`:idx:
      * `system.html#162 <system.html#162>`_
      * `system.html#163 <system.html#163>`_
@@ -1919,10 +2119,14 @@ Index
      * `system.html#165 <system.html#165>`_
      * `system.html#166 <system.html#166>`_
      * `strtabs.html#109 <strtabs.html#109>`_
+     * `macros.html#118 <macros.html#118>`_
 
    `Letters`:idx:
      `strutils.html#103 <strutils.html#103>`_
 
+   `li`:idx:
+     `xmlgen.html#148 <xmlgen.html#148>`_
+
    `LIBCURL_VERSION`:idx:
      `libcurl.html#272 <libcurl.html#272>`_
 
@@ -1950,6 +2154,9 @@ Index
    `line_trace`:idx:
      `nimrodc.html#109 <nimrodc.html#109>`_
 
+   `link`:idx:
+     `xmlgen.html#149 <xmlgen.html#149>`_
+
    `Literal strings`:idx:
      `manual.html#119 <manual.html#119>`_
 
@@ -2014,6 +2221,9 @@ Index
    `MANAGER_OK`:idx:
      `mysql.html#334 <mysql.html#334>`_
 
+   `map`:idx:
+     `xmlgen.html#150 <xmlgen.html#150>`_
+
    `match`:idx:
      * `regexprs.html#106 <regexprs.html#106>`_
      * `regexprs.html#107 <regexprs.html#107>`_
@@ -2083,6 +2293,9 @@ Index
    `MEM_ROOT`:idx:
      `mysql.html#325 <mysql.html#325>`_
 
+   `meta`:idx:
+     `xmlgen.html#151 <xmlgen.html#151>`_
+
    `method call syntax`:idx:
      `tut2.html#104 <tut2.html#104>`_
 
@@ -2643,6 +2856,9 @@ Index
    `neginf`:idx:
      `system.html#433 <system.html#433>`_
 
+   `nestList`:idx:
+     `macros.html#152 <macros.html#152>`_
+
    `NET`:idx:
      `mysql.html#199 <mysql.html#199>`_
 
@@ -2686,16 +2902,33 @@ Index
      * `system.html#119 <system.html#119>`_
      * `system.html#120 <system.html#120>`_
 
+   `newCall`:idx:
+     * `macros.html#150 <macros.html#150>`_
+     * `macros.html#151 <macros.html#151>`_
+
    `newFileStream`:idx:
      * `streams.html#120 <streams.html#120>`_
      * `streams.html#121 <streams.html#121>`_
 
+   `newFloatLitNode`:idx:
+     `macros.html#143 <macros.html#143>`_
+
+   `newIdentNode`:idx:
+     * `macros.html#144 <macros.html#144>`_
+     * `macros.html#145 <macros.html#145>`_
+
+   `newIntLitNode`:idx:
+     `macros.html#142 <macros.html#142>`_
+
    `newline`:idx:
      `manual.html#121 <manual.html#121>`_
 
    `NewLines`:idx:
      `lexbase.html#102 <lexbase.html#102>`_
 
+   `newNimNode`:idx:
+     `macros.html#135 <macros.html#135>`_
+
    `newSeq`:idx:
      `system.html#161 <system.html#161>`_
 
@@ -2709,6 +2942,9 @@ Index
      * `strtabs.html#104 <strtabs.html#104>`_
      * `strtabs.html#105 <strtabs.html#105>`_
 
+   `newStrLitNode`:idx:
+     `macros.html#141 <macros.html#141>`_
+
    `next`:idx:
      * `parseopt.html#104 <parseopt.html#104>`_
      * `parsecfg.html#106 <parsecfg.html#106>`_
@@ -2747,6 +2983,9 @@ Index
    `normalize`:idx:
      `strutils.html#120 <strutils.html#120>`_
 
+   `noscript`:idx:
+     `xmlgen.html#152 <xmlgen.html#152>`_
+
    `not`:idx:
      * `system.html#115 <system.html#115>`_
      * `system.html#191 <system.html#191>`_
@@ -2771,11 +3010,15 @@ Index
      `mysql.html#137 <mysql.html#137>`_
 
    `object`:idx:
-     `manual.html#155 <manual.html#155>`_
+     * `manual.html#155 <manual.html#155>`_
+     * `xmlgen.html#153 <xmlgen.html#153>`_
 
    `octet2hex`:idx:
      `mysql.html#276 <mysql.html#276>`_
 
+   `ol`:idx:
+     `xmlgen.html#154 <xmlgen.html#154>`_
+
    `ONLY_KILL_QUERY`:idx:
      `mysql.html#189 <mysql.html#189>`_
 
@@ -2783,6 +3026,7 @@ Index
      * `lexbase.html#104 <lexbase.html#104>`_
      * `parsecfg.html#104 <parsecfg.html#104>`_
      * `parsexml.html#107 <parsexml.html#107>`_
+     * `parsecsv.html#106 <parsecsv.html#106>`_
      * `zipfiles.html#102 <zipfiles.html#102>`_
 
    `openarray`:idx:
@@ -2799,6 +3043,12 @@ Index
    `Operators`:idx:
      `manual.html#202 <manual.html#202>`_
 
+   `optgroup`:idx:
+     `xmlgen.html#155 <xmlgen.html#155>`_
+
+   `option`:idx:
+     `xmlgen.html#156 <xmlgen.html#156>`_
+
    `or`:idx:
      * `system.html#117 <system.html#117>`_
      * `system.html#236 <system.html#236>`_
@@ -2819,12 +3069,18 @@ Index
    `OSError`:idx:
      `os.html#147 <os.html#147>`_
 
+   `p`:idx:
+     `xmlgen.html#157 <xmlgen.html#157>`_
+
    `packet_error`:idx:
      `mysql.html#201 <mysql.html#201>`_
 
    `pairs`:idx:
      `strtabs.html#110 <strtabs.html#110>`_
 
+   `param`:idx:
+     `xmlgen.html#158 <xmlgen.html#158>`_
+
    `paramCount`:idx:
      `os.html#145 <os.html#145>`_
 
@@ -3062,6 +3318,15 @@ Index
    `PNET`:idx:
      `mysql.html#200 <mysql.html#200>`_
 
+   `PNimrodNode`:idx:
+     `macros.html#110 <macros.html#110>`_
+
+   `PNimrodSymbol`:idx:
+     `macros.html#109 <macros.html#109>`_
+
+   `PNimrodType`:idx:
+     `macros.html#108 <macros.html#108>`_
+
    `PObject`:idx:
      `system.html#132 <system.html#132>`_
 
@@ -3102,6 +3367,9 @@ Index
    `Prand_struct`:idx:
      `mysql.html#253 <mysql.html#253>`_
 
+   `pre`:idx:
+     `xmlgen.html#159 <xmlgen.html#159>`_
+
    `pred`:idx:
      `system.html#158 <system.html#158>`_
 
@@ -3115,6 +3383,9 @@ Index
    `procedures`:idx:
      `manual.html#199 <manual.html#199>`_
 
+   `processedRows`:idx:
+     `parsecsv.html#107 <parsecsv.html#107>`_
+
    `Psockaddr`:idx:
      `mysql.html#250 <mysql.html#250>`_
 
@@ -3199,6 +3470,9 @@ Index
    `PUSED_MEM`:idx:
      `mysql.html#322 <mysql.html#322>`_
 
+   `push`:idx:
+     `math.html#134 <math.html#134>`_
+
    `push/pop`:idx:
      `manual.html#228 <manual.html#228>`_
 
@@ -3211,6 +3485,9 @@ Index
    `PZipFileStream`:idx:
      `zipfiles.html#108 <zipfiles.html#108>`_
 
+   `q`:idx:
+     `xmlgen.html#160 <xmlgen.html#160>`_
+
    `quit`:idx:
      * `system.html#479 <system.html#479>`_
      * `system.html#480 <system.html#480>`_
@@ -3262,7 +3539,7 @@ Index
      `system.html#506 <system.html#506>`_
 
    `readData`:idx:
-     `cgi.html#107 <cgi.html#107>`_
+     `cgi.html#108 <cgi.html#108>`_
 
    `readFile`:idx:
      `system.html#493 <system.html#493>`_
@@ -3289,6 +3566,9 @@ Index
      * `system.html#501 <system.html#501>`_
      * `streams.html#114 <streams.html#114>`_
 
+   `readRow`:idx:
+     `parsecsv.html#108 <parsecsv.html#108>`_
+
    `readStr`:idx:
      `streams.html#113 <streams.html#113>`_
 
@@ -3420,6 +3700,9 @@ Index
    `sameFileContent`:idx:
      `os.html#149 <os.html#149>`_
 
+   `samp`:idx:
+     `xmlgen.html#161 <xmlgen.html#161>`_
+
    `scope`:idx:
      * `manual.html#106 <manual.html#106>`_
      * `manual.html#217 <manual.html#217>`_
@@ -3442,9 +3725,15 @@ Index
    `SCRAMBLE_LENGTH_323`:idx:
      `mysql.html#121 <mysql.html#121>`_
 
+   `script`:idx:
+     `xmlgen.html#162 <xmlgen.html#162>`_
+
    `ScriptExt`:idx:
      `os.html#108 <os.html#108>`_
 
+   `select`:idx:
+     `xmlgen.html#163 <xmlgen.html#163>`_
+
    `separate compilation`:idx:
      * `manual.html#214 <manual.html#214>`_
      * `tut1.html#127 <tut1.html#127>`_
@@ -3528,7 +3817,7 @@ Index
      * `system.html#417 <system.html#417>`_
 
    `setTestData`:idx:
-     `cgi.html#141 <cgi.html#141>`_
+     `cgi.html#142 <cgi.html#142>`_
 
    `shl`:idx:
      * `system.html#226 <system.html#226>`_
@@ -3556,9 +3845,15 @@ Index
    `sizeof`:idx:
      `system.html#156 <system.html#156>`_
 
+   `small`:idx:
+     `xmlgen.html#164 <xmlgen.html#164>`_
+
    `sockaddr`:idx:
      `mysql.html#251 <mysql.html#251>`_
 
+   `span`:idx:
+     `xmlgen.html#165 <xmlgen.html#165>`_
+
    `split`:idx:
      * `strutils.html#131 <strutils.html#131>`_
      * `strutils.html#132 <strutils.html#132>`_
@@ -4084,6 +4379,9 @@ Index
    `stack_trace`:idx:
      `nimrodc.html#108 <nimrodc.html#108>`_
 
+   `standardDeviation`:idx:
+     `math.html#136 <math.html#136>`_
+
    `startsWith`:idx:
      `strutils.html#149 <strutils.html#149>`_
 
@@ -4117,6 +4415,9 @@ Index
    `st_mem_root`:idx:
      `mysql.html#324 <mysql.html#324>`_
 
+   `stmt`:idx:
+     `macros.html#112 <macros.html#112>`_
+
    `st_mysql`:idx:
      `mysql.html#356 <mysql.html#356>`_
 
@@ -4163,6 +4464,9 @@ Index
    `strip`:idx:
      `strutils.html#114 <strutils.html#114>`_
 
+   `strong`:idx:
+     `xmlgen.html#166 <xmlgen.html#166>`_
+
    `strStart`:idx:
      `strutils.html#107 <strutils.html#107>`_
 
@@ -4172,6 +4476,12 @@ Index
    `strutils`:idx:
      `nimrodc.html#117 <nimrodc.html#117>`_
 
+   `strVal`:idx:
+     `macros.html#128 <macros.html#128>`_
+
+   `strVal=`:idx:
+     `macros.html#134 <macros.html#134>`_
+
    `st_udf_args`:idx:
      `mysql.html#258 <mysql.html#258>`_
 
@@ -4181,9 +4491,15 @@ Index
    `st_used_mem`:idx:
      `mysql.html#320 <mysql.html#320>`_
 
+   `style`:idx:
+     `xmlgen.html#167 <xmlgen.html#167>`_
+
    `style-insensitive`:idx:
      `manual.html#118 <manual.html#118>`_
 
+   `sub`:idx:
+     `xmlgen.html#168 <xmlgen.html#168>`_
+
    `subrange`:idx:
      * `manual.html#149 <manual.html#149>`_
      * `tut1.html#115 <tut1.html#115>`_
@@ -4197,15 +4513,27 @@ Index
    `sum`:idx:
      `math.html#110 <math.html#110>`_
 
+   `sup`:idx:
+     `xmlgen.html#169 <xmlgen.html#169>`_
+
    `swap`:idx:
      `system.html#419 <system.html#419>`_
 
+   `symbol`:idx:
+     `macros.html#125 <macros.html#125>`_
+
+   `symbol=`:idx:
+     `macros.html#131 <macros.html#131>`_
+
    `syscall`:idx:
      `manual.html#171 <manual.html#171>`_
 
    `system`:idx:
      `manual.html#218 <manual.html#218>`_
 
+   `table`:idx:
+     `xmlgen.html#170 <xmlgen.html#170>`_
+
    `tabulator`:idx:
      `manual.html#125 <manual.html#125>`_
 
@@ -4227,6 +4555,9 @@ Index
    `Tbind_destructor_func`:idx:
      `sqlite3.html#183 <sqlite3.html#183>`_
 
+   `tbody`:idx:
+     `xmlgen.html#171 <xmlgen.html#171>`_
+
    `TCfgEvent`:idx:
      `parsecfg.html#102 <parsecfg.html#102>`_
 
@@ -4254,6 +4585,12 @@ Index
    `Tcreate_function_step_func`:idx:
      `sqlite3.html#184 <sqlite3.html#184>`_
 
+   `TCsvParser`:idx:
+     `parsecsv.html#104 <parsecsv.html#104>`_
+
+   `TCsvRow`:idx:
+     `parsecsv.html#103 <parsecsv.html#103>`_
+
    `TCurl`:idx:
      `libcurl.html#140 <libcurl.html#140>`_
 
@@ -4407,12 +4744,18 @@ Index
    `Tcurl_write_callback`:idx:
      `libcurl.html#143 <libcurl.html#143>`_
 
+   `td`:idx:
+     `xmlgen.html#172 <xmlgen.html#172>`_
+
    `template`:idx:
      `manual.html#209 <manual.html#209>`_
 
    `TEndian`:idx:
      `system.html#385 <system.html#385>`_
 
+   `textarea`:idx:
+     `xmlgen.html#173 <xmlgen.html#173>`_
+
    `TFile`:idx:
      `system.html#481 <system.html#481>`_
 
@@ -4428,6 +4771,9 @@ Index
    `TFloatClass`:idx:
      `math.html#103 <math.html#103>`_
 
+   `tfoot`:idx:
+     `xmlgen.html#174 <xmlgen.html#174>`_
+
    `TForegroundColor`:idx:
      `terminal.html#113 <terminal.html#113>`_
 
@@ -4437,9 +4783,15 @@ Index
    `TGC_Strategy`:idx:
      `system.html#464 <system.html#464>`_
 
+   `th`:idx:
+     `xmlgen.html#175 <xmlgen.html#175>`_
+
    `THash`:idx:
      `hashes.html#101 <hashes.html#101>`_
 
+   `thead`:idx:
+     `xmlgen.html#176 <xmlgen.html#176>`_
+
    `TimeInfoToTime`:idx:
      `times.html#108 <times.html#108>`_
 
@@ -4449,9 +4801,30 @@ Index
    `TIMESTAMP_FLAG`:idx:
      `mysql.html#134 <mysql.html#134>`_
 
+   `title`:idx:
+     `xmlgen.html#177 <xmlgen.html#177>`_
+
    `TMonth`:idx:
      `times.html#101 <times.html#101>`_
 
+   `TNimNodeKinds`:idx:
+     `macros.html#103 <macros.html#103>`_
+
+   `TNimrodNodeKind`:idx:
+     `macros.html#102 <macros.html#102>`_
+
+   `TNimrodSymKind`:idx:
+     `macros.html#106 <macros.html#106>`_
+
+   `TNimrodTypeKind`:idx:
+     `macros.html#104 <macros.html#104>`_
+
+   `TNimSymKinds`:idx:
+     `macros.html#107 <macros.html#107>`_
+
+   `TNimTypeKinds`:idx:
+     `macros.html#105 <macros.html#105>`_
+
    `toBiggestFloat`:idx:
      `system.html#401 <system.html#401>`_
 
@@ -4490,6 +4863,9 @@ Index
    `toString`:idx:
      `strutils.html#147 <strutils.html#147>`_
 
+   `toStrLit`:idx:
+     `macros.html#146 <macros.html#146>`_
+
    `toTitle`:idx:
      `unicode.html#108 <unicode.html#108>`_
 
@@ -4513,6 +4889,9 @@ Index
    `TPathComponent`:idx:
      `os.html#152 <os.html#152>`_
 
+   `tr`:idx:
+     `xmlgen.html#178 <xmlgen.html#178>`_
+
    `traced`:idx:
      * `manual.html#159 <manual.html#159>`_
      * `tut1.html#121 <tut1.html#121>`_
@@ -4529,6 +4908,9 @@ Index
    `TRune16`:idx:
      `unicode.html#102 <unicode.html#102>`_
 
+   `TRunningStat`:idx:
+     `math.html#133 <math.html#133>`_
+
    `try`:idx:
      * `manual.html#185 <manual.html#185>`_
      * `tut2.html#107 <tut2.html#107>`_
@@ -4560,6 +4942,9 @@ Index
    `TStyle`:idx:
      `terminal.html#111 <terminal.html#111>`_
 
+   `tt`:idx:
+     `xmlgen.html#179 <xmlgen.html#179>`_
+
    `TTime`:idx:
      `times.html#103 <times.html#103>`_
 
@@ -4584,6 +4969,12 @@ Index
    `TXmlParser`:idx:
      `parsexml.html#106 <parsexml.html#106>`_
 
+   `typ`:idx:
+     `macros.html#127 <macros.html#127>`_
+
+   `typ=`:idx:
+     `macros.html#133 <macros.html#133>`_
+
    `type`:idx:
      * `manual.html#102 <manual.html#102>`_
      * `manual.html#140 <manual.html#140>`_
@@ -4611,6 +5002,9 @@ Index
    `UDF_INIT`:idx:
      `mysql.html#263 <mysql.html#263>`_
 
+   `ul`:idx:
+     `xmlgen.html#180 <xmlgen.html#180>`_
+
    `unchecked runtime error`:idx:
      `manual.html#111 <manual.html#111>`_
 
@@ -4660,11 +5054,17 @@ Index
      `mysql.html#112 <mysql.html#112>`_
 
    `validateData`:idx:
-     `cgi.html#108 <cgi.html#108>`_
+     `cgi.html#109 <cgi.html#109>`_
 
    `validEmailAddress`:idx:
      `strutils.html#157 <strutils.html#157>`_
 
+   `validIdentifier`:idx:
+     `strutils.html#158 <strutils.html#158>`_
+
+   `var`:idx:
+     `xmlgen.html#181 <xmlgen.html#181>`_
+
    `Var`:idx:
      `manual.html#178 <manual.html#178>`_
 
@@ -4672,7 +5072,8 @@ Index
      `nimrodc.html#106 <nimrodc.html#106>`_
 
    `variance`:idx:
-     `math.html#112 <math.html#112>`_
+     * `math.html#112 <math.html#112>`_
+     * `math.html#135 <math.html#135>`_
 
    `variant`:idx:
      * `manual.html#156 <manual.html#156>`_
@@ -4694,6 +5095,7 @@ Index
    `warning`:idx:
      * `manual.html#220 <manual.html#220>`_
      * `manual.html#226 <manual.html#226>`_
+     * `macros.html#139 <macros.html#139>`_
 
    `when`:idx:
      * `manual.html#182 <manual.html#182>`_
@@ -4726,7 +5128,7 @@ Index
      `system.html#509 <system.html#509>`_
 
    `writeContentType`:idx:
-     `cgi.html#142 <cgi.html#142>`_
+     `cgi.html#143 <cgi.html#143>`_
 
    `writeln`:idx:
      * `system.html#502 <system.html#502>`_
@@ -4736,7 +5138,11 @@ Index
      `terminal.html#112 <terminal.html#112>`_
 
    `XML`:idx:
-     `parsexml.html#101 <parsexml.html#101>`_
+     * `parsexml.html#101 <parsexml.html#101>`_
+     * `xmlgen.html#101 <xmlgen.html#101>`_
+
+   `xmlCheckedTag`:idx:
+     `xmlgen.html#106 <xmlgen.html#106>`_
 
    `XMLencode`:idx:
      `cgi.html#103 <cgi.html#103>`_
diff --git a/doc/tut2.txt b/doc/tut2.txt
index 0bea28a8f..6d2fd3094 100644
--- a/doc/tut2.txt
+++ b/doc/tut2.txt
@@ -396,7 +396,7 @@ is not executed (if an exception occurs).
 Generics
 ========
 
-`Version 0.7.6: Complex generic types like in the example do not work.`:red:
+`Version 0.7.8: Complex generic types like in the example do not work.`:red:
 
 `Generics`:idx: are Nimrod's means to parametrize procs, iterators or types 
 with `type parameters`:idx:. They are most useful for efficient type safe
@@ -596,7 +596,8 @@ Nimrod's syntax is flexible enough anyway.
 `Macros`:idx: can be used to implement `domain specific languages`:idx:. 
 
 To write macros, one needs to know how the Nimrod concrete syntax is converted
-to an abstract syntax tree (AST). (Unfortunately the AST is not documented yet.)
+to an abstract syntax tree (AST). The AST is documented in the 
+`macros <macros.html>`_ module.
 
 There are two ways to invoke a macro:
 (1) invoking a macro like a procedure call (`expression macros`:idx:)
diff --git a/examples/hallo.nim b/examples/hallo.nim
index 73ef2cb95..20aa4695c 100644
--- a/examples/hallo.nim
+++ b/examples/hallo.nim
@@ -1,7 +1,3 @@
 # Hallo world program
 
-import strutils
-
-echo($(parseFloat("0.5")* toFloat(5000) / toFloat(parseInt("5000"))))
-
-echo("Hallo world!")
+echo "Hallo world!"
diff --git a/examples/htmlrefs.nim b/examples/htmlrefs.nim
index cf1b3be28..b1695ee7a 100644
--- a/examples/htmlrefs.nim
+++ b/examples/htmlrefs.nim
@@ -1,7 +1,6 @@
 # Example program to show the new parsexml module
 # This program reads an HTML file and writes all its used links to stdout.
 # Errors and whitespace are ignored.
-# (c) 2009 Andreas Rumpf
 
 import os, streams, parsexml, strutils
 
@@ -15,7 +14,7 @@ if paramCount() < 1:
 var links = 0 # count the number of links
 var filename = appendFileExt(ParamStr(1), "html")
 var s = newFileStream(filename, fmRead)
-if s == nil: quit("cannot open the file" & filename)
+if s == nil: quit("cannot open the file " & filename)
 var x: TXmlParser
 open(x, s, filename)
 next(x) # get first event
diff --git a/examples/htmltitle.nim b/examples/htmltitle.nim
index 6cdfd90eb..ae023e379 100644
--- a/examples/htmltitle.nim
+++ b/examples/htmltitle.nim
@@ -1,7 +1,6 @@
 # Example program to show the new parsexml module
 # This program reads an HTML file and writes its title to stdout.
 # Errors and whitespace are ignored.
-# (c) 2009 Andreas Rumpf
 
 import os, streams, parsexml, strutils
 
@@ -10,7 +9,7 @@ if paramCount() < 1:
 
 var filename = appendFileExt(ParamStr(1), "html")
 var s = newFileStream(filename, fmRead)
-if s == nil: quit("cannot open the file" & filename)
+if s == nil: quit("cannot open the file " & filename)
 var x: TXmlParser
 open(x, s, filename)
 while true:
diff --git a/examples/statcsv.nim b/examples/statcsv.nim
new file mode 100644
index 000000000..9c1ebd113
--- /dev/null
+++ b/examples/statcsv.nim
@@ -0,0 +1,60 @@
+# Example program to show the parsecsv module
+# This program reads a CSV file and computes sum, mean, minimum, maximum and
+# the standard deviation of its columns.
+# The CSV file can have a header which is then used for the output.
+
+import os, streams, parsecsv, strutils, math
+
+if paramCount() < 1:
+  quit("Usage: sumcsv filename[.csv]")
+
+var filename = appendFileExt(ParamStr(1), "csv")
+var s = newFileStream(filename, fmRead)
+if s == nil: quit("cannot open the file " & filename)
+
+var
+  x: TCsvParser
+  header: seq[string]
+  res: seq[TRunningStat]
+open(x, s, filename, separator=';', skipInitialSpace = true)
+while readRow(x):
+  if processedRows(x) == 1:
+    newSeq(res, x.row.len) # allocate space for the result
+    if validIdentifier(x.row[0]):
+      # header line:
+      header = x.row
+    else:
+      newSeq(header, x.row.len)
+      for i in 0..x.row.len-1: header[i] = "Col " & $(i+1)
+  else:
+    # data line:
+    for i in 0..x.row.len-1: 
+      push(res[i], parseFloat(x.row[i]))
+x.close()
+
+# Write results:
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(header[i])
+stdout.write("\nSum")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].sum)
+stdout.write("\nMean")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].mean)
+stdout.write("\nMin")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].min)
+stdout.write("\nMax")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].max)
+stdout.write("\nStdDev")
+for i in 0..header.len-1:
+  stdout.write("\t")
+  stdout.write(res[i].standardDeviation)
+stdout.write("\n")
+
diff --git a/ide/nimide.nim b/ide/nimide.nim
index 671405bbc..741f71afb 100644
--- a/ide/nimide.nim
+++ b/ide/nimide.nim
@@ -26,14 +26,14 @@ type
     currTab: int
   PEditor = ptr TEditor
 
-proc on_window_destroy(obj: PGtkObject, event: PGdkEvent, 
-                       data: pointer): gboolean {.cdecl.} =
-  gtk_main_quit()
+proc onWindowDestroy(obj: PGtkObject, event: PGdkEvent, 
+                     data: pointer): gboolean {.cdecl.} =
+  gtkMainQuit()
 
-proc on_about_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
-  gtk_show_about_dialog(e.window,
+proc onAboutMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
+  gtkShowAboutDialog(e.window,
     "comments", "A fast and leight-weight IDE for Nimrod",
-    "copyright", "Copyright \xc2\xa9 2008 Andreas Rumpf",
+    "copyright", "Copyright \xc2\xa9 2009 Andreas Rumpf",
     "version", "0.1",
     "website", "http://nimrod.ethexor.com",
     "program-name", "Nimrod IDE",
@@ -42,9 +42,9 @@ proc on_about_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
 proc getTabIndex(e: PEditor, tab: PTab): int = 
   var i = 0
   while true:
-    var w = gtk_notebook_get_nth_page(e.notebook, i)
+    var w = gtkNotebookGetNthPage(e.notebook, i)
     if w == nil: return -1
-    var v = gtk_notebook_get_tab_label(e.notebook, w)
+    var v = gtkNotebookGetTabLabel(e.notebook, w)
     if tab.hbox == v: return i
     inc(i)
   
@@ -56,12 +56,11 @@ type
     answerYes, answerNo, answerCancel
   
 proc askWhetherToSave(e: PEditor): TAnswer = 
-  var dialog = gtk_dialog_new_with_buttons("Should the changes be saved?", 
-    e.window, GTK_DIALOG_MODAL, GTK_STOCK_SAVE, 1,
-                                "gtk-discard", 2,
-                                GTK_STOCK_CANCEL, 3, nil)
-  result = TAnswer(gtk_dialog_run(dialog)+1)
-  gtk_widget_destroy(dialog)
+  var dialog = gtkDialogNewWithButtons("Should the changes be saved?", 
+    e.window, GTK_DIALOG_MODAL, GTK_STOCK_SAVE, 1, "gtk-discard", 2,
+    GTK_STOCK_CANCEL, 3, nil)
+  result = TAnswer(gtkDialogRun(dialog)+1)
+  gtkWidgetDestroy(dialog)
 
 proc saveTab(tab: PTab) = 
   if tab.untitled: 
@@ -76,13 +75,13 @@ proc OnCloseTab(button: PGtkButton, tab: PTab) {.cdecl.} =
       idx = i
       break
   if idx >= 0: 
-    if gtk_text_buffer_get_modified(gtk_text_view_get_buffer(tab.textView)):
+    if gtkTextBufferGetModified(gtkTextViewGetBuffer(tab.textView)):
       case askWhetherToSave(tab.e)
       of answerCancel: return
       of answerYes: saveTab(tab)
       of answerNo: nil
     
-    gtk_notebook_remove_page(tab.e.notebook, idx)
+    gtkNotebookRemovePage(tab.e.notebook, idx)
     if idx < high(tab.e.tabs):
       for i in idx..high(tab.e.tabs)-1:  
         tab.e.tabs[i] = tab.e.tabs[i+1]
@@ -95,95 +94,96 @@ proc OnCloseTab(button: PGtkButton, tab: PTab) {.cdecl.} =
 
 proc createTab(e: PEditor, filename: string, untitled: bool) = 
   var t = cast[PTab](alloc0(sizeof(TTab)))
-  t.textview = gtk_text_view_new_with_buffer(gtk_text_buffer_new(nil))
-  var font_desc = pango_font_description_from_string("monospace 10")
-  gtk_widget_modify_font(t.textview, font_desc)
-  pango_font_description_free(font_desc)
+  t.textview = gtkTextViewNewWithBuffer(gtkTextBufferNew(nil))
+  var fontDesc = pangoFontDescriptionFromString("monospace 10")
+  gtkWidgetModifyFont(t.textview, fontDesc)
+  pangoFontDescriptionFree(fontDesc)
   t.filename = filename
   t.untitled = untitled
-  gtk_widget_show(t.textview)
-  var scroll = gtk_scrolled_window_new(nil, nil)
-  gtk_container_add(scroll, t.textview)
-  gtk_widget_show(scroll)
+  gtkWidgetShow(t.textview)
+  var scroll = gtkScrolledWindowNew(nil, nil)
+  gtkContainerAdd(scroll, t.textview)
+  gtkWidgetShow(scroll)
   
   t.e = e
-  t.hbox = gtk_hbox_new(false, 0)
-  var image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)
-  var button = gtk_button_new()
-  var lab = gtk_label_new(filename)
-  gtk_button_set_image(button, image)
-  gtk_button_set_relief(button, GTK_RELIEF_NONE)
-  gtk_box_pack_start(t.hbox, lab, false, false, 2)
-  gtk_box_pack_end(t.hbox, button, false, false, 0)
+  t.hbox = gtkHboxNew(false, 0)
+  var image = gtkImageNewFromStock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)
+  var button = gtkButtonNew()
+  var lab = gtkLabelNew(filename)
+  gtkButtonSetImage(button, image)
+  gtkButtonSetRelief(button, GTK_RELIEF_NONE)
+  gtkBoxPackStart(t.hbox, lab, false, false, 2)
+  gtkBoxPackEnd(t.hbox, button, false, false, 0)
   
-  discard g_signal_connect(button, "clicked", G_Callback(onCloseTab), t)
-  gtk_widget_show(button)
-  gtk_widget_show(lab)
+  discard gSignalConnect(button, "clicked", G_Callback(onCloseTab), t)
+  gtkWidgetShow(button)
+  gtkWidgetShow(lab)
  
-  var idx = gtk_notebook_append_page(e.notebook, scroll, t.hbox)
+  var idx = gtkNotebookAppendPage(e.notebook, scroll, t.hbox)
   e.currTab = idx
   add(e.tabs, t)
-  gtk_notebook_set_current_page(e.notebook, idx)
+  gtkNotebookSetCurrentPage(e.notebook, idx)
   
 
-proc on_open_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
+proc onOpenMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
   var files = ChooseFilesToOpen(e.window, getRoot(getActiveTab(e)))
   for f in items(files): createTab(e, f, untitled=false)
 
-proc on_save_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
-  var cp = gtk_notebook_get_current_page(e.notebook)
+proc onSaveMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
+  var cp = gtkNotebookGetCurrentPage(e.notebook)
   
   
-proc on_save_as_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
+proc onSaveAsMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
   nil
 
-proc on_new_menu_item_activate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
+proc onNewMenuItemActivate(menuItem: PGtkMenuItem, e: PEditor) {.cdecl.} =
   inc(e.tabname)
   createTab(e, "untitled-" & $e.tabname, true)
 
 proc main(e: PEditor) = 
-  var builder = glade_xml_new(getApplicationDir() / GuiTemplate, nil, nil)
+  var builder = gladeXmlNew(getApplicationDir() / GuiTemplate, nil, nil)
   if builder == nil: quit("cannot open: " & GuiTemplate)
   # get the components:
-  e.window = GTK_WINDOW(glade_xml_get_widget(builder, "window"))
-  e.statusbar = GTK_STATUSBAR(glade_xml_get_widget(builder, "statusbar"))
-  e.notebook = GTK_NOTEBOOK(glade_xml_get_widget(builder, "notebook"))
+  e.window = GTK_WINDOW(gladeXmlGetWidget(builder, "window"))
+  e.statusbar = GTK_STATUSBAR(gladeXmlGetWidget(builder, "statusbar"))
+  e.notebook = GTK_NOTEBOOK(gladeXmlGetWidget(builder, "notebook"))
   e.tabs = @[]
   e.currTab = -1
   setHomogeneous(e.notebook^, 1)
 
   # connect the signal handlers:
-  glade_xml_signal_connect(builder, "on_window_destroy",
-                           GCallback(on_window_destroy))
-  var about = GTK_MENU_ITEM(glade_xml_get_widget(builder, "about_menu_item"))
-  discard g_signal_connect(about, "activate", 
-                           G_CALLBACK(on_about_menu_item_activate), e)
-
-  var newItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "new_menu_item"))
-  discard g_signal_connect(newItem, "activate", 
-                           G_CALLBACK(on_new_menu_item_activate), e)
-
-  var quitItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "quit_menu_item"))
-  discard g_signal_connect(quitItem, "activate", 
-                           G_CALLBACK(on_window_destroy), e)
-
-  var openItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "open_menu_item"))
-  discard g_signal_connect(openItem, "activate", 
-                           G_CALLBACK(on_open_menu_item_activate), e)
+  gladeXmlSignalConnect(builder, "on_window_destroy",
+                        GCallback(onWindowDestroy))
+  var about = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "about_menu_item"))
+  discard gSignalConnect(about, "activate", 
+                         G_CALLBACK(onAboutMenuItemActivate), e)
+
+  var newItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "new_menu_item"))
+  discard gSignalConnect(newItem, "activate", 
+                         G_CALLBACK(onNewMenuItemActivate), e)
+
+  var quitItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "quit_menu_item"))
+  discard gSignalConnect(quitItem, "activate", 
+                         G_CALLBACK(onWindowDestroy), e)
+
+  var openItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "open_menu_item"))
+  discard gSignalConnect(openItem, "activate", 
+                         G_CALLBACK(onOpenMenuItemActivate), e)
   
-  var saveItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "save_menu_item")) 
-  discard g_signal_connect(saveItem, "activate", 
-                           G_CALLBACK(on_save_menu_item_activate), e)
+  var saveItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "save_menu_item")) 
+  discard gSignalConnect(saveItem, "activate", 
+                         G_CALLBACK(onSaveMenuItemActivate), e)
   
-  var saveAsItem = GTK_MENU_ITEM(glade_xml_get_widget(builder, "save_as_menu_item")) 
-  discard g_signal_connect(saveAsItem, "activate", 
-                           G_CALLBACK(on_save_as_menu_item_activate), e)
+  var saveAsItem = GTK_MENU_ITEM(gladeXmlGetWidget(builder, "save_as_menu_item")) 
+  discard gSignalConnect(saveAsItem, "activate", 
+                         G_CALLBACK(onSaveAsMenuItemActivate), e)
 
-  gtk_window_set_default_icon_name(GTK_STOCK_EDIT)
-  gtk_widget_show(e.window)
-  gtk_main()
+  gtkWindowSetDefaultIconName(GTK_STOCK_EDIT)
+  gtkWidgetShow(e.window)
+  gtkMain()
 
 
-gtk_nimrod_init()
+gtkNimrodInit()
 var e = cast[PEditor](alloc0(sizeof(TEditor)))
 main(e)
+
diff --git a/install.txt b/install.txt
index 568c54282..a5aef4cbe 100644
--- a/install.txt
+++ b/install.txt
@@ -1,66 +1,67 @@
-Installation

-============

-

-

-Installation on Linux/UNIX

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

-

-Note:

-  A C compiler is required - knowledge of C is not!

-

-The GNU C Compiler is fully supported, other compilers may work. The C compiler

-should be in your ``$PATH`` (most likely the case). Note that some few Linux

-distributions do not ship with a GCC compiler preinstalled - then you have to

-install it.

-

-Install Nimrod by downloading the appropriate ``.zip`` file and extracting it 

-to a directory of your choice. The Nimrod Compiler will stay in this

-directory (unless you copy it somewhere else). The compiler does not need 

-write access to its directory anymore, so copying the nimrod folder to ``/opt`` 

-does work.

-

-Then run the following command::

-

-  sh build.sh

-

-Unlike other software, Nimrod does not distribute its files over the whole file

-hierarchy. This has the advantage that you can deinstall it by just deleting

-its folder. The disadvantage is that you have to add it to your ``PATH``

-manually. An alternative is to create a symbolic link in ``/usr/bin``::

-

-  [sudo] ln -s $your_install_dir/bin/nimrod  /usr/bin/nimrod

-

-

-Installation on the Macintosh

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

-

-Only MacOS X is supported.

-Since MacOS X is UNIX based too, it works like the installation on Linux. You

-need to install Apple's developer's tools for the GNU Compiler Collection

-though.

-

-

-Installation on Windows

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

-

-Install Nimrod by downloading and running

-the ``nimrod_$version.exe`` file. As default, the ``LLVM-GCC`` 

-compiler is used that is bundled with this installer. You can change

-the configuration file to use another C compiler.

-

-Currently, the following C compilers are supported under Windows:

-

-- | Microsoft's Visual C++

-  | http://msdn.microsoft.com/visualc

-  | (You need the SDK too - but not the full one: Essential are only

-    the win32api header files and import libraries.)

-- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)

-  | http://www.mingw.org/download.shtml

-- | LLVM with GNU C/C++ frontend

-  | http://llvm.org/releases/download.html#2.2

-- | Digital Mars C++

-  | http://www.digitalmars.com/download/freecompiler.html

-

-For better compile times I recommend Digital Mars C++ -- it is easy to install

-and a small package.

-

+Installation
+============
+
+
+Installation on Linux/UNIX
+--------------------------
+
+Note:
+  A C compiler is required - knowledge of C is not!
+
+The GNU C Compiler is fully supported, other compilers may work. The C compiler
+should be in your ``$PATH`` (most likely the case). Note that some few Linux
+distributions do not ship with a GCC compiler preinstalled - then you have to
+install it.
+
+Install Nimrod by downloading the appropriate ``.zip`` file and extracting it 
+to a directory of your choice. The Nimrod Compiler will stay in this
+directory (unless you copy it somewhere else). The compiler does not need 
+write access to its directory, so copying the nimrod folder to ``/opt`` 
+does work.
+
+Then run the following command::
+
+  sh build.sh
+
+Unlike other software, Nimrod does not distribute its files over the whole file
+hierarchy. This has the advantage that you can deinstall it by just deleting
+its folder. The disadvantage is that you have to add it to your ``PATH``
+manually. An alternative is to create a symbolic link in ``/usr/bin``::
+
+  [sudo] ln -s $your_install_dir/bin/nimrod  /usr/bin/nimrod
+
+
+Installation on the Macintosh
+-----------------------------
+
+Only MacOS X is supported.
+Since MacOS X is UNIX based too, it works like the installation on Linux. You
+need to install Apple's developer's tools for the GNU Compiler Collection
+though.
+
+
+Installation on Windows
+-----------------------
+
+Install Nimrod by downloading and running
+the ``nimrod_$version.exe`` file. As default, the ``GCC`` 
+compiler is used that is bundled with this installer. **You can change
+the configuration file** ``config/nimrod.cfg`` **to use another C compiler 
+or change the path to GCC.**
+
+Currently, the following C compilers are supported under Windows:
+
+- | Microsoft's Visual C++
+  | http://msdn.microsoft.com/visualc
+  | (You need the SDK too - but not the full one: Only
+    the win32api header files and import libraries are essential.)
+- | Gnu C Compiler (the mingw version; the cygwin version has not been tested!)
+  | http://www.mingw.org/download.shtml
+- | LLVM with GNU C/C++ frontend
+  | http://llvm.org/releases/download.html#2.2
+- | Digital Mars C++
+  | http://www.digitalmars.com/download/freecompiler.html
+
+For better compile times I recommend Digital Mars C++ -- it is easy to install
+and a small package.
+
diff --git a/koch.py b/koch.py
index 5b6cf8cff..6fcb1336d 100644
--- a/koch.py
+++ b/koch.py
@@ -12,7 +12,7 @@ from pycompab import *
 
 # --------------------- constants  ----------------------------------------
 
-NIMROD_VERSION = '0.7.6'
+NIMROD_VERSION = '0.7.8'
 # This string contains Nimrod's version. It is the only place
 # where the version needs to be updated. The rest is done by
 # the build process automatically. It is replaced **everywhere**!
@@ -34,6 +34,46 @@ USE_FPC = true
 BOOTCMD = "$1 cc --compile:build/platdef.c $2 rod/nimrod.nim"
 # the command used for bootstrapping
 
+# ---------------------- compiler detection --------------------------------
+
+def detect(cmd, lookFor="version"):
+  try:
+    pipe = os.popen4(cmd)[1]
+  except AttributeError:
+    pipe = os.popen(cmd)
+  result = None
+  for line in pipe.readlines():
+    if find(lower(line), lookFor) >= 0:
+      result = line[:-1]
+      break
+  pipe.close()
+  if not result:
+    # don't give up yet; it may have written to stderr
+    if os.system(cmd) == 0:
+      result = cmd
+  return result
+
+def detectNimrod():
+  if detect("nimrod"): 
+    return "nimrod"
+  elif detect("bin/nimrod"):
+    return "bin/nimrod"
+  else:
+    Error("could not find a working nimrod executable")
+
+def detectNim():
+  if USE_FPC and detect("fpc -h"):
+    # workaround a bug in the macosx version of nim:
+    if getHost() == "macosx": return "nim" 
+    else: return "bin/nim"
+  return detectNimrod()
+
+def detectAndCompileNim():
+  result = detectNim()
+  if result == "bin/nim" or result == "nim":
+    cmd_nim()
+  return result
+
 # --------------------------------------------------------------------------
 
 def Error(msg): sys.exit("[Koch] *** ERROR: " + msg)
@@ -453,12 +493,8 @@ def genBootDiff(genA, genB):
 
 def cmd_rodsrc():
   "converts the src/*.pas files into Nimrod syntax"
-  PAS_FILES_BLACKLIST = split("""nsystem nmath nos ntime strutils""")
-  if USE_FPC and detect("fpc -h"):
-    cmd_nim()
-    compiler = "nim"
-  else:
-    compiler = "nimrod"
+  PAS_FILES_BLACKLIST = split("""nsystem nmath nos osproc ntime strutils""")
+  compiler = detectAndCompileNim()
   CMD = "$1 boot --skip_proj_cfg -o:rod/$2.nim nim/$3"
   result = false
   for fi in Glob("nim/*.pas"):
@@ -484,14 +520,7 @@ def cmd_boot(args):
       Move(ExeExt("rod/nimcache/nimrod"), ExeExt("rod/nimrod"))
 
   writePlatdefC(getNimrodPath())
-  d = detect("fpc -h")
-  if USE_FPC and d:
-    Echo(Subs("'$1' detected", d))
-    cmd_nim()
-    compiler = "nim"
-  else:
-    compiler = "nimrod"
-
+  compiler = detectAndCompileNim()
   cmd_rodsrc() # regenerate nimrod version of the files
 
   # move the new executable to bin directory (is done by cmd_rod())
@@ -501,7 +530,7 @@ def cmd_boot(args):
   # move the new executable to bin directory:
   moveExes()
   # compile again and compare:
-  myExec("nimrod")
+  myExec("bin/nimrod") # here we always use the new executable
   genB = readCFiles() # second generation of generated C files
   diff = genBootDiff(genA, genB)
   if diff:
@@ -517,7 +546,7 @@ def cmd_boot(args):
     # move the new executable to bin directory:
     moveExes()
     # use the new executable to compile Nimrod:
-    myExec("nimrod")
+    myExec("bin/nimrod")
     if SameFileContent(Path(ExeExt("rod/nimrod")),
                        Path(ExeExt("bin/nimrod"))):
       Echo("executables are equal: SUCCESS!")
@@ -614,23 +643,6 @@ def writePlatdefC(nimrodpath):
                '\n', host, processor))
   f.close()
 
-def detect(cmd, lookFor="version"):
-  try:
-    pipe = os.popen4(cmd)[1]
-  except AttributeError:
-    pipe = os.popen(cmd)
-  result = None
-  for line in pipe.readlines():
-    if find(lower(line), lookFor) >= 0:
-      result = line[:-1]
-      break
-  pipe.close()
-  if not result:
-    # don't give up yet; it may have written to stderr
-    if os.system(cmd) == 0:
-      result = cmd
-  return result
-
 def getNimrodPath():
   if os.name == "posix":
     # Does not work 100% reliably. It is the best solution though.
diff --git a/lib/alloc.nim b/lib/alloc.nim
index 8648b322a..e4d828449 100644
--- a/lib/alloc.nim
+++ b/lib/alloc.nim
@@ -7,29 +7,27 @@
 #    distribution, for details about the copyright.
 #
 
-# Low level allocator for Nimrod.
+# Low level allocator for Nimrod. Has been designed to support the GC.
 # TODO: 
 # - eliminate "used" field
 # - make searching for block O(1)
 
-proc raiseOutOfMem {.noinline.} =
-  assert false
-  quit(1)
-
 # ------------ platform specific chunk allocation code -----------------------
 
 when defined(posix): 
-  const # XXX: make these variables for portability?
+  const
     PROT_READ  = 1             # page can be read 
     PROT_WRITE = 2             # page can be written 
     MAP_PRIVATE = 2            # Changes are private 
   
-  when defined(linux):
+  when defined(linux) or defined(aix):
     const MAP_ANONYMOUS = 0x20       # don't use a file
-  elif defined(macosx):
+  elif defined(macosx) or defined(bsd):
     const MAP_ANONYMOUS = 0x1000
+  elif defined(solaris): 
+    const MAP_ANONYMOUS = 0x100
   else:
-    const MAP_ANONYMOUS = 0 # other operating systems may not know about this
+    {.error: "Port memory manager to your platform".}
 
   proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
             off: int): pointer {.header: "<sys/mman.h>".}
@@ -43,7 +41,7 @@ when defined(posix):
       raiseOutOfMem()
       
   proc osDeallocPages(p: pointer, size: int) {.inline} =
-    munmap(p, size)
+    when reallyOsDealloc: munmap(p, size)
   
 elif defined(windows): 
   const
@@ -69,7 +67,7 @@ elif defined(windows):
 
   proc osDeallocPages(p: pointer, size: int) {.inline.} = 
     # according to Microsoft, 0 is the only correct value here:
-    VirtualFree(p, 0, MEM_RELEASE)
+    when reallyOsDealloc: VirtualFree(p, 0, MEM_RELEASE)
 
 else: 
   {.error: "Port memory manager to your platform".}
@@ -77,48 +75,14 @@ else:
 # --------------------- end of non-portable code -----------------------------
 
 # We manage *chunks* of memory. Each chunk is a multiple of the page size.
-# The page size may or may not the operating system's page size. Each chunk
-# starts at an address that is divisible by the page size. Chunks that are
-# bigger than ``ChunkOsReturn`` are returned back to the operating system
-# immediately.
-
-
-# Guess the page size of the system; if it is the
-# wrong value, performance may be worse (this is not
-# for sure though), but GC still works; must be a power of two!
-when defined(linux) or defined(windows) or defined(macosx):
-  const
-    PageShift = 12
-    PageSize = 1 shl PageShift # on 32 bit systems 4096
-else:
-  {.error: "unkown page size".}
+# Each chunk starts at an address that is divisible by the page size. Chunks
+# that are bigger than ``ChunkOsReturn`` are returned back to the operating
+# system immediately.
 
 const
-  PageMask = PageSize-1
-  
-  SmallChunkSize = PageSize # * 4
-
-  MemAlign = 8 # minimal memory block that can be allocated
-
-  BitsPerPage = PageSize div MemAlign
-  UnitsPerPage = BitsPerPage div (sizeof(int)*8)
-    # how many ints do we need to describe a page:
-    # on 32 bit systems this is only 16 (!)
-
-  ChunkOsReturn = 64 * PageSize
+  ChunkOsReturn = 256 * PageSize
   InitialMemoryRequest = ChunkOsReturn div 2 # < ChunkOsReturn!
-  
-  # Compile time options:
-  coalescRight = true
-  coalescLeft = true
-
-const
-  TrunkShift = 9
-  BitsPerTrunk = 1 shl TrunkShift # needs to be a power of 2 and divisible by 64
-  TrunkMask = BitsPerTrunk - 1
-  IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8)
-  IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
-  IntMask = 1 shl IntShift - 1
+  SmallChunkSize = PageSize
 
 type 
   PTrunk = ptr TTrunk
@@ -132,10 +96,11 @@ type
     data: TTrunkBuckets
   
 type
-  TAlignType = float
+  TAlignType = biggestFloat
   TFreeCell {.final, pure.} = object
     next: ptr TFreeCell  # next free cell in chunk (overlaid with refcount)
-    zeroField: pointer   # nil means cell is not used (overlaid with typ field)
+    zeroField: int       # 0 means cell is not used (overlaid with typ field)
+                         # 1 means cell is manually managed pointer
 
   PChunk = ptr TBaseChunk
   PBigChunk = ptr TBigChunk
@@ -155,15 +120,20 @@ type
   TBigChunk = object of TBaseChunk # not necessarily > PageSize!
     next: PBigChunk      # chunks of the same (or bigger) size
     prev: PBigChunk
+    align: int
     data: TAlignType     # start of usable memory
 
 template smallChunkOverhead(): expr = sizeof(TSmallChunk)-sizeof(TAlignType)
 template bigChunkOverhead(): expr = sizeof(TBigChunk)-sizeof(TAlignType)
 
-proc roundup(x, v: int): int {.inline.} = return ((-x) and (v-1)) +% x
+proc roundup(x, v: int): int {.inline.} = 
+  result = (x + (v-1)) and not (v-1)
+  assert(result >= x)
+  #return ((-x) and (v-1)) +% x
 
 assert(roundup(14, PageSize) == PageSize)
 assert(roundup(15, 8) == 16)
+assert(roundup(65, 8) == 72)
 
 # ------------- chunk table ---------------------------------------------------
 # We use a PtrSet of chunk starts and a table[Page, chunksize] for chunk
@@ -180,7 +150,7 @@ type
     
   TAllocator {.final, pure.} = object
     llmem: PLLChunk
-    currMem, maxMem: int  # currently and maximum used memory size (allocated from OS)
+    currMem, maxMem, freeMem: int # memory sizes (allocated from OS)
     freeSmallChunks: array[0..SmallChunkSize div MemAlign-1, PSmallChunk]
     freeChunksList: PBigChunk # XXX make this a datastructure with O(1) access
     chunkStarts: TIntSet
@@ -277,8 +247,10 @@ var lastSize = PageSize
 
 proc requestOsChunks(a: var TAllocator, size: int): PBigChunk = 
   incCurrMem(a, size)
+  inc(a.freeMem, size)
   result = cast[PBigChunk](osAllocPages(size))
   assert((cast[TAddress](result) and PageMask) == 0)
+  #zeroMem(result, size)
   result.next = nil
   result.prev = nil
   result.used = false
@@ -312,11 +284,28 @@ proc freeOsChunks(a: var TAllocator, p: pointer, size: int) =
   excl(a.chunkStarts, pageIndex(p))
   osDeallocPages(p, size)
   decCurrMem(a, size)
+  dec(a.freeMem, size)
+  #c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
 
 proc isAccessible(p: pointer): bool {.inline.} = 
   result = Contains(allocator.chunkStarts, pageIndex(p))
 
+proc contains[T](list, x: T): bool = 
+  var it = list
+  while it != nil:
+    if it == x: return true
+    it = it.next
+    
+proc writeFreeList(a: TAllocator) =
+  var it = a.freeChunksList
+  c_fprintf(c_stdout, "freeChunksList: %p\n", it)
+  while it != nil: 
+    c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", 
+              it, it.next, it.prev)
+    it = it.next
+
 proc ListAdd[T](head: var T, c: T) {.inline.} = 
+  assert(c notin head)
   assert c.prev == nil
   assert c.next == nil
   c.next = head
@@ -326,6 +315,7 @@ proc ListAdd[T](head: var T, c: T) {.inline.} =
   head = c
 
 proc ListRemove[T](head: var T, c: T) {.inline.} =
+  assert(c in head)
   if c == head: 
     head = c.next
     assert c.prev == nil
@@ -344,13 +334,22 @@ proc isSmallChunk(c: PChunk): bool {.inline.} =
 proc chunkUnused(c: PChunk): bool {.inline.} = 
   result = not c.used
   
+proc updatePrevSize(a: var TAllocator, c: PBigChunk, 
+                    prevSize: int) {.inline.} = 
+  var ri = cast[PChunk](cast[TAddress](c) +% c.size)
+  assert((cast[TAddress](ri) and PageMask) == 0)
+  if isAccessible(ri):
+    ri.prevSize = prevSize
+  
 proc freeBigChunk(a: var TAllocator, c: PBigChunk) = 
   var c = c
   assert(c.size >= PageSize)
+  inc(a.freeMem, c.size)
   when coalescRight:
     var ri = cast[PChunk](cast[TAddress](c) +% c.size)
     assert((cast[TAddress](ri) and PageMask) == 0)
     if isAccessible(ri) and chunkUnused(ri):
+      assert(not isSmallChunk(ri))
       if not isSmallChunk(ri):
         ListRemove(a.freeChunksList, cast[PBigChunk](ri))
         inc(c.size, ri.size)
@@ -360,6 +359,7 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
       var le = cast[PChunk](cast[TAddress](c) -% c.prevSize)
       assert((cast[TAddress](le) and PageMask) == 0)
       if isAccessible(le) and chunkUnused(le):
+        assert(not isSmallChunk(le))
         if not isSmallChunk(le):
           ListRemove(a.freeChunksList, cast[PBigChunk](le))
           inc(le.size, c.size)
@@ -367,6 +367,8 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
           c = cast[PBigChunk](le)
 
   if c.size < ChunkOsReturn: 
+    incl(a.chunkStarts, pageIndex(c))
+    updatePrevSize(a, c, c.size)
     ListAdd(a.freeChunksList, c)
     c.used = false
   else:
@@ -374,11 +376,16 @@ proc freeBigChunk(a: var TAllocator, c: PBigChunk) =
 
 proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) = 
   var rest = cast[PBigChunk](cast[TAddress](c) +% size)
+  if rest in a.freeChunksList: 
+    c_fprintf(c_stdout, "to add: %p\n", rest)
+    writeFreeList(allocator)
+    assert false
   rest.size = c.size - size
   rest.used = false
-  rest.next = nil # XXX
+  rest.next = nil
   rest.prev = nil
   rest.prevSize = size
+  updatePrevSize(a, c, rest.size)
   c.size = size
   incl(a.chunkStarts, pageIndex(rest))
   ListAdd(a.freeChunksList, rest)
@@ -386,26 +393,32 @@ proc splitChunk(a: var TAllocator, c: PBigChunk, size: int) =
 proc getBigChunk(a: var TAllocator, size: int): PBigChunk = 
   # use first fit for now:
   assert((size and PageMask) == 0)
+  assert(size > 0)
   result = a.freeChunksList
   block search:
     while result != nil:
+      #if not chunkUnused(result): 
+      #  c_fprintf(c_stdout, "%lld\n", int(result.used))
       assert chunkUnused(result)
       if result.size == size: 
         ListRemove(a.freeChunksList, result)
         break search
       elif result.size > size:
-        splitChunk(a, result, size)
+        #c_fprintf(c_stdout, "res size: %lld; size: %lld\n", result.size, size)
         ListRemove(a.freeChunksList, result)
+        splitChunk(a, result, size)
         break search
       result = result.next
+      assert result != a.freeChunksList
     if size < InitialMemoryRequest: 
       result = requestOsChunks(a, InitialMemoryRequest)
       splitChunk(a, result, size)
     else:
       result = requestOsChunks(a, size)
-  result.prevSize = 0
+  result.prevSize = 0 # XXX why is this needed?
   result.used = true
   incl(a.chunkStarts, pageIndex(result))
+  dec(a.freeMem, size)
 
 proc getSmallChunk(a: var TAllocator): PSmallChunk = 
   var res = getBigChunk(a, PageSize)
@@ -419,8 +432,11 @@ proc getCellSize(p: pointer): int {.inline.} =
   var c = pageAddr(p)
   result = c.size
   
-proc alloc(a: var TAllocator, requestedSize: int): pointer =
-  var size = roundup(max(requestedSize, sizeof(TFreeCell)), MemAlign)
+proc rawAlloc(a: var TAllocator, requestedSize: int): pointer =
+  assert(roundup(65, 8) == 72)
+  assert requestedSize >= sizeof(TFreeCell)
+  var size = roundup(requestedSize, MemAlign)
+  #c_fprintf(c_stdout, "alloc; size: %ld; %ld\n", requestedSize, size)
   if size <= SmallChunkSize-smallChunkOverhead(): 
     # allocate a small block: for small chunks, we use only its next pointer
     var s = size div MemAlign
@@ -436,8 +452,11 @@ proc alloc(a: var TAllocator, requestedSize: int): pointer =
       c.prev = nil
       ListAdd(a.freeSmallChunks[s], c)
       result = addr(c.data)
+      assert((cast[TAddress](result) and (MemAlign-1)) == 0)
     else:
       assert c.next != c
+      #if c.size != size:
+      #  c_fprintf(c_stdout, "csize: %lld; size %lld\n", c.size, size)
       assert c.size == size
       if c.freeList == nil:
         assert(c.acc + smallChunkOverhead() + size <= SmallChunkSize) 
@@ -445,9 +464,10 @@ proc alloc(a: var TAllocator, requestedSize: int): pointer =
         inc(c.acc, size)      
       else:
         result = c.freeList
-        assert(c.freeList.zeroField == nil)
+        assert(c.freeList.zeroField == 0)
         c.freeList = c.freeList.next
       dec(c.free, size)
+      assert((cast[TAddress](result) and (MemAlign-1)) == 0)
     if c.free < size: 
       ListRemove(a.freeSmallChunks[s], c)
   else:
@@ -458,16 +478,10 @@ proc alloc(a: var TAllocator, requestedSize: int): pointer =
     assert c.next == nil
     assert c.size == size
     result = addr(c.data)
-  cast[ptr TFreeCell](result).zeroField = cast[ptr TFreeCell](1) # make it != nil
-  #echo("setting to one: ", $cast[TAddress](addr(cast[ptr TFreeCell](result).zeroField)))
-
-proc contains(list, x: PSmallChunk): bool = 
-  var it = list
-  while it != nil:
-    if it == x: return true
-    it = it.next
+    assert((cast[TAddress](result) and (MemAlign-1)) == 0)
+  assert(isAccessible(result))
 
-proc dealloc(a: var TAllocator, p: pointer) = 
+proc rawDealloc(a: var TAllocator, p: pointer) = 
   var c = pageAddr(p)
   if isSmallChunk(c):
     # `p` is within a small chunk:
@@ -475,8 +489,8 @@ proc dealloc(a: var TAllocator, p: pointer) =
     var s = c.size
     var f = cast[ptr TFreeCell](p)
     #echo("setting to nil: ", $cast[TAddress](addr(f.zeroField)))
-    assert(f.zeroField != nil)
-    f.zeroField = nil
+    assert(f.zeroField != 0)
+    f.zeroField = 0
     f.next = c.freeList
     c.freeList = f
     # check if it is not in the freeSmallChunks[s] list:
@@ -495,23 +509,64 @@ proc dealloc(a: var TAllocator, p: pointer) =
     # free big chunk
     freeBigChunk(a, cast[PBigChunk](c))
 
-proc realloc(a: var TAllocator, p: pointer, size: int): pointer = 
-  # could be made faster, but this is unnecessary, the GC does not use it anyway
-  result = alloc(a, size)
-  copyMem(result, p, getCellSize(p))
-  dealloc(a, p)
-
 proc isAllocatedPtr(a: TAllocator, p: pointer): bool = 
   if isAccessible(p):
     var c = pageAddr(p)
     if not chunkUnused(c):
       if isSmallChunk(c):
-        result = (cast[TAddress](p) -% cast[TAddress](c) -%
-                 smallChunkOverhead()) %% c.size == 0 and
-          cast[ptr TFreeCell](p).zeroField != nil
+        var c = cast[PSmallChunk](c)
+        var offset = (cast[TAddress](p) and (PageSize-1)) -% 
+                     smallChunkOverhead()
+        result = (c.acc >% offset) and (offset %% c.size == 0) and
+          (cast[ptr TFreeCell](p).zeroField >% 1)
       else:
         var c = cast[PBigChunk](c)
-        result = p == addr(c.data)
+        result = p == addr(c.data) and cast[ptr TFreeCell](p).zeroField >% 1
+
+# ---------------------- interface to programs -------------------------------
+
+proc alloc(size: int): pointer =
+  result = rawAlloc(allocator, size+sizeof(TFreeCell))
+  cast[ptr TFreeCell](result).zeroField = 1 # mark it as used
+  assert(not isAllocatedPtr(allocator, result))
+  result = cast[pointer](cast[TAddress](result) +% sizeof(TFreeCell))
+
+proc alloc0(size: int): pointer =
+  result = alloc(size)
+  zeroMem(result, size)
+
+proc dealloc(p: pointer) =
+  var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
+  assert(cast[ptr TFreeCell](x).zeroField == 1)
+  rawDealloc(allocator, x)
+  assert(not isAllocatedPtr(allocator, x))
+
+proc ptrSize(p: pointer): int =
+  var x = cast[pointer](cast[TAddress](p) -% sizeof(TFreeCell))
+  result = pageAddr(x).size - sizeof(TFreeCell)
+
+proc realloc(p: pointer, newsize: int): pointer =
+  if newsize > 0:
+    result = alloc(newsize)
+    if p != nil:
+      copyMem(result, p, ptrSize(p))
+      dealloc(p)
+  elif p != nil:
+    dealloc(p)
+
+proc countFreeMem(): int =
+  # only used for assertions
+  var it = allocator.freeChunksList
+  while it != nil:
+    inc(result, it.size)
+    it = it.next
+
+proc getFreeMem(): int = 
+  result = allocator.freeMem
+  #assert(result == countFreeMem())
+
+proc getTotalMem(): int = return allocator.currMem
+proc getOccupiedMem(): int = return getTotalMem() - getFreeMem()
 
 when isMainModule:
   const iterations = 4000_000
diff --git a/lib/ansi_c.nim b/lib/ansi_c.nim
index 8e39c9e39..81abd2a3e 100644
--- a/lib/ansi_c.nim
+++ b/lib/ansi_c.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -82,3 +82,7 @@ proc c_ferror(stream: C_TextFileStar): bool {.importc: "ferror", nodecl.}
 proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", nodecl.}
 proc c_abort() {.importc: "abort", nodecl.}
 proc c_feof(stream: C_TextFileStar): bool {.importc: "feof", nodecl.}
+
+proc c_malloc(size: int): pointer {.importc: "malloc", nodecl.}
+proc c_free(p: pointer) {.importc: "free", nodecl.}
+proc c_realloc(p: pointer, newsize: int): pointer {.importc: "realloc", nodecl.}
diff --git a/lib/assign.nim b/lib/assign.nim
index 17b4f5949..3d4bf4d61 100644
--- a/lib/assign.nim
+++ b/lib/assign.nim
@@ -43,12 +43,8 @@ proc genericAssign(dest, src: Pointer, mt: PNimType) =
       x^ = nil
       return
     assert(dest != nil)
-    when defined(boehmGC):
-      unsureAsgnRef(cast[ppointer](dest),
-                    newObj(seq.len * mt.base.size + GenericSeqSize))
-    else:
-      unsureAsgnRef(cast[ppointer](dest),
-                    newObj(mt, seq.len * mt.base.size + GenericSeqSize))
+    unsureAsgnRef(cast[ppointer](dest),
+                  newObj(mt, seq.len * mt.base.size + GenericSeqSize))
     var dst = cast[taddress](cast[ppointer](dest)^)
     for i in 0..seq.len-1:
       genericAssign(
diff --git a/lib/base/cgi.nim b/lib/base/cgi.nim
index 0dc3a4394..5cf6d0bfa 100644
--- a/lib/base/cgi.nim
+++ b/lib/base/cgi.nim
@@ -103,71 +103,77 @@ proc cgiError*(msg: string) {.noreturn.} =
   e.msg = msg
   raise e
 
-proc readData*(allowedMethods: set[TRequestMethod] = 
-               {methodNone, methodPost, methodGet}): PStringTable = 
-  ## Read CGI data. If the client does not use a method listed in the
-  ## `allowedMethods` set, an `ECgi` exception is raised.
-  result = newStringTable()
-  var enc: string # encoded data
+proc getEncodedData(allowedMethods: set[TRequestMethod]): string = 
   case getenv("REQUEST_METHOD") 
   of "POST": 
     if methodPost notin allowedMethods: 
       cgiError("'REQUEST_METHOD' 'POST' is not supported")
-    # read from stdin:
     var L = parseInt(getenv("CONTENT_LENGTH"))
-    enc = newString(L)
-    if readBuffer(stdin, addr(enc[0]), L) != L:
+    result = newString(L)
+    if readBuffer(stdin, addr(result[0]), L) != L:
       cgiError("cannot read from stdin")
   of "GET":
     if methodGet notin allowedMethods: 
       cgiError("'REQUEST_METHOD' 'GET' is not supported")
-    # read from the QUERY_STRING environment variable:
-    enc = getenv("QUERY_STRING")
+    result = getenv("QUERY_STRING")
   else: 
-    if methodNone in allowedMethods:
-      return result
-    else:
+    if methodNone notin allowedMethods:
       cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'")
-  
-  # decode everything in one pass:
-  var i = 0
-  var name = ""
-  var value = ""
-  while true:
-    setLen(name, 0) # reuse memory
-    while true:
-      case enc[i]
-      of '\0': return
-      of '%': 
-        var x = 0
-        handleHexChar(enc[i+1], x)
-        handleHexChar(enc[i+2], x)
-        inc(i, 2)
-        add(name, chr(x))
-      of '+': add(name, ' ')
-      of '=', '&': break
-      else: add(name, enc[i])
-      inc(i)
-    if enc[i] != '=': cgiError("'=' expected")
-    inc(i) # skip '='
-    setLen(value, 0) # reuse memory
-    while true:
-      case enc[i]
-      of '%': 
-        var x = 0
-        handleHexChar(enc[i+1], x)
-        handleHexChar(enc[i+2], x)
-        inc(i, 2)
-        add(value, chr(x))
-      of '+': add(value, ' ')
-      of '&', '\0': break
-      else: add(value, enc[i])
-      inc(i)
-    result[name] = value
-    if enc[i] == '&': inc(i)
-    elif enc[i] == '\0': break
-    else: cgiError("'&' expected")
 
+iterator decodeData*(allowedMethods: set[TRequestMethod] = 
+       {methodNone, methodPost, methodGet}): tuple[key, value: string] = 
+  ## Reads and decodes CGI data and yields the (name, value) pairs the
+  ## data consists of. If the client does not use a method listed in the
+  ## `allowedMethods` set, an `ECgi` exception is raised.
+  var enc = getEncodedData(allowedMethods)
+  if not isNil(enc): 
+    # decode everything in one pass:
+    var i = 0
+    var name = ""
+    var value = ""
+    while enc[i] != '\0':
+      setLen(name, 0) # reuse memory
+      while true:
+        case enc[i]
+        of '\0': break
+        of '%': 
+          var x = 0
+          handleHexChar(enc[i+1], x)
+          handleHexChar(enc[i+2], x)
+          inc(i, 2)
+          add(name, chr(x))
+        of '+': add(name, ' ')
+        of '=', '&': break
+        else: add(name, enc[i])
+        inc(i)
+      if enc[i] != '=': cgiError("'=' expected")
+      inc(i) # skip '='
+      setLen(value, 0) # reuse memory
+      while true:
+        case enc[i]
+        of '%': 
+          var x = 0
+          handleHexChar(enc[i+1], x)
+          handleHexChar(enc[i+2], x)
+          inc(i, 2)
+          add(value, chr(x))
+        of '+': add(value, ' ')
+        of '&', '\0': break
+        else: add(value, enc[i])
+        inc(i)
+      yield (name, value)
+      if enc[i] == '&': inc(i)
+      elif enc[i] == '\0': break
+      else: cgiError("'&' expected")
+
+proc readData*(allowedMethods: set[TRequestMethod] = 
+               {methodNone, methodPost, methodGet}): PStringTable = 
+  ## Read CGI data. If the client does not use a method listed in the
+  ## `allowedMethods` set, an `ECgi` exception is raised.
+  result = newStringTable()
+  for name, value in decodeData(allowedMethods): 
+    result[name] = value
+  
 proc validateData*(data: PStringTable, validKeys: openarray[string]) = 
   ## validates data; raises `ECgi` if this fails. This checks that each variable
   ## name of the CGI `data` occurs in the `validKeys` array.
@@ -323,8 +329,13 @@ proc setTestData*(keysvalues: openarray[string]) =
 
 proc writeContentType*() = 
   ## call this before starting to send your HTML data to `stdout`. This
-  ## is just a shorthand for: 
+  ## implements this part of the CGI protocol: 
   ##
   ## .. code-block:: Nimrod
   ##     write(stdout, "Content-type: text/html\n\n")
+  ## 
+  ## It also modifies the debug stack traces so that they contain
+  ## ``<br />`` and are easily readable in a browser.  
   write(stdout, "Content-type: text/html\n\n")
+  system.stackTraceNewLine = "<br />\n"
+  
diff --git a/lib/excpt.nim b/lib/excpt.nim
index 38d34f3f4..293491fe9 100644
--- a/lib/excpt.nim
+++ b/lib/excpt.nim
@@ -70,6 +70,8 @@ var
   framePtr {.exportc.}: PFrame
 
   tempFrames: array [0..127, PFrame] # cannot be allocated on the stack!
+  
+  stackTraceNewLine* = "\n" ## undocumented feature
 
 proc auxWriteStackTrace(f: PFrame, s: var string) =
   const 
@@ -101,19 +103,21 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
     if tempFrames[j] == nil: 
       add(s, "(")
       add(s, $(total-i-1))
-      add(s, " calls omitted) ...\n")
+      add(s, " calls omitted) ...")
     else:
       add(s, $tempFrames[j].procname)
       if tempFrames[j].line > 0:
         add(s, ", line: ")
         add(s, $tempFrames[j].line)
-      add(s, "\n")
+    add(s, stackTraceNewLine)
 
 proc rawWriteStackTrace(s: var string) =
   if framePtr == nil:
-    add(s, "No stack traceback available\n")
+    add(s, "No stack traceback available")
+    add(s, stackTraceNewLine)
   else:
-    add(s, "Traceback (most recent call last)\n")
+    add(s, "Traceback (most recent call last)")
+    add(s, stackTraceNewLine)
     auxWriteStackTrace(framePtr, s)
 
 proc quitOrDebug() {.inline.} =
@@ -151,6 +155,8 @@ var
 
 proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
   if not cond:
+    #c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
+    #quit(1)
     GC_disable() # BUGFIX: `$` allocates a new string object!
     if not isNil(assertBuf):
       # BUGFIX: when debugging the GC, assertBuf may be nil
@@ -162,7 +168,11 @@ proc internalAssert(file: cstring, line: int, cond: bool) {.compilerproc.} =
       add(assertBuf, "\n")
       gAssertionFailed.msg = assertBuf
     GC_enable()
-    raise gAssertionFailed # newException(EAssertionFailed, assertBuf)
+    if gAssertionFailed != nil:
+      raise gAssertionFailed
+    else:
+      c_fprintf(c_stdout, "Assertion failure: file %s line %ld\n", file, line)
+      quit(1)
 
 proc WriteStackTrace() =
   var s = ""
diff --git a/lib/gc.nim b/lib/gc.nim
index aaef70c03..1c353b559 100644
--- a/lib/gc.nim
+++ b/lib/gc.nim
@@ -9,23 +9,17 @@
 
 
 #            Garbage Collector
-# Current Features:
-# * incremental
-# * non-recursive
-# * generational
-
+#
+# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
+# Special care has been taken to avoid recursion as far as possible to avoid
+# stack overflows when traversing deep datastructures. This is comparable to
+# an incremental and generational GC. It should be well-suited for soft real
+# time applications (like games).
+#
 # Future Improvements:
 # * Support for multi-threading. However, locks for the reference counting
 #   might turn out to be too slow.
 
-# ---------------------------------------------------------------------------
-
-proc getOccupiedMem(): int = return tlsfUsed()
-proc getFreeMem(): int = return tlsfMax() - tlsfUsed()
-proc getTotalMem(): int = return tlsfMax()
-
-# ---------------------------------------------------------------------------
-
 const
   CycleIncrease = 2 # is a multiplicative increase
   InitialCycleThreshold = 4*1024*1024 # X MB because cycle checking is slow
@@ -36,14 +30,14 @@ const
 const
   rcIncrement = 0b1000 # so that lowest 3 bits are not touched
   # NOTE: Most colors are currently unused
-  rcBlack = 0b000 # cell is colored black; in use or free
-  rcGray = 0b001  # possible member of a cycle
-  rcWhite = 0b010 # member of a garbage cycle
+  rcBlack = 0b000  # cell is colored black; in use or free
+  rcGray = 0b001   # possible member of a cycle
+  rcWhite = 0b010  # member of a garbage cycle
   rcPurple = 0b011 # possible root of a cycle
-  rcZct = 0b100  # in ZCT
-  rcRed = 0b101 # Candidate cycle undergoing sigma-computation
+  rcZct = 0b100    # in ZCT
+  rcRed = 0b101    # Candidate cycle undergoing sigma-computation
   rcOrange = 0b110 # Candidate cycle awaiting epoch boundary
-  rcShift = 3 # shift by rcShift to get the reference counter
+  rcShift = 3      # shift by rcShift to get the reference counter
   colorMask = 0b111
 type
   TWalkOp = enum
@@ -52,21 +46,22 @@ type
   TFinalizer {.compilerproc.} = proc (self: pointer)
     # A ref type can have a finalizer that is called before the object's
     # storage is freed.
-  TGcHeap {.final, pure.} = object # this contains the zero count and
-                                   # non-zero count table
-    mask: TAddress           # mask for fast pointer detection
-    zct: TCellSeq            # the zero count table
-    stackCells: TCellSet     # cells and addresses that look like a cell but
-                             # aren't of the hardware stack
 
+  TGcStat {.final, pure.} = object
     stackScans: int          # number of performed stack scans (for statistics)
     cycleCollections: int    # number of performed full collections
     maxThreshold: int        # max threshold that has been set
     maxStackSize: int        # max stack size
-    maxStackPages: int       # max number of pages in stack
-    cycleTableSize: int      # max entries in cycle table
+    maxStackCells: int       # max stack cells in ``decStack``
+    cycleTableSize: int      # max entries in cycle table  
+  
+  TGcHeap {.final, pure.} = object # this contains the zero count and
+                                   # non-zero count table
+    zct: TCellSeq            # the zero count table
+    decStack: TCellSeq       # cells in the stack that are to decref again
     cycleRoots: TCellSet
     tempStack: TCellSeq      # temporary stack for recursion elimination
+    stat: TGcStat
 
 var
   stackBottom: pointer
@@ -82,13 +77,13 @@ var
 proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc.}
   # unsureAsgnRef updates the reference counters only if dest is not on the
   # stack. It is used by the code generator if it cannot decide wether a
-  # reference is in the stack or not (this can happen for out/var parameters).
+  # reference is in the stack or not (this can happen for var parameters).
 #proc growObj(old: pointer, newsize: int): pointer {.compilerproc.}
 proc newObj(typ: PNimType, size: int): pointer {.compilerproc.}
 proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.}
 
 proc addZCT(s: var TCellSeq, c: PCell) {.noinline.} =
-  if (c.refcount and colorMask) != rcZct:
+  if (c.refcount and rcZct) == 0:
     c.refcount = c.refcount and not colorMask or rcZct
     add(s, c)
 
@@ -131,7 +126,7 @@ proc GC_disableMarkAndSweep() =
   # set to the max value to suppress the cycle detector
 
 # this that has to equals zero, otherwise we have to round up UnitsPerPage:
-when BitsPerPage mod BitsPerUnit != 0:
+when BitsPerPage mod (sizeof(int)*8) != 0:
   {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
 
 when debugGC:
@@ -203,8 +198,7 @@ template gcTrace(cell, state: expr): stmt =
 # -----------------------------------------------------------------------------
 
 # forward declarations:
-proc updateZCT()
-proc collectCT(gch: var TGcHeap, zctUpdated: bool)
+proc collectCT(gch: var TGcHeap)
 proc IsOnStack(p: pointer): bool {.noinline.}
 proc forAllChildren(cell: PCell, op: TWalkOp)
 proc doOperation(p: pointer, op: TWalkOp)
@@ -232,7 +226,7 @@ proc decRef(c: PCell) {.inline.} =
   when stressGC:
     if c.refcount <% rcIncrement:
       writeCell("broken cell", c)
-  assert(c.refcount >% rcIncrement)
+  assert(c.refcount >=% rcIncrement)
   c.refcount = c.refcount -% rcIncrement
   if c.refcount <% rcIncrement:
     addZCT(gch.zct, c)
@@ -242,7 +236,6 @@ proc decRef(c: PCell) {.inline.} =
 proc incRef(c: PCell) {.inline.} = 
   c.refcount = c.refcount +% rcIncrement
   if canBeCycleRoot(c):
-    # OPT: the code generator should special case this
     incl(gch.cycleRoots, c)
 
 proc nimGCref(p: pointer) {.compilerproc, inline.} = incRef(usrToCell(p))
@@ -277,19 +270,18 @@ proc unsureAsgnRef(dest: ppointer, src: pointer) =
 
 proc initGC() =
   when traceGC:
-    for i in low(TCellState)..high(TCellState): CellSetInit(states[i])
-  gch.stackScans = 0
-  gch.cycleCollections = 0
-  gch.maxThreshold = 0
-  gch.maxStackSize = 0
-  gch.maxStackPages = 0
-  gch.cycleTableSize = 0
+    for i in low(TCellState)..high(TCellState): Init(states[i])
+  gch.stat.stackScans = 0
+  gch.stat.cycleCollections = 0
+  gch.stat.maxThreshold = 0
+  gch.stat.maxStackSize = 0
+  gch.stat.maxStackCells = 0
+  gch.stat.cycleTableSize = 0
   # init the rt
   init(gch.zct)
   init(gch.tempStack)
-  CellSetInit(gch.cycleRoots)
-  CellSetInit(gch.stackCells)
-  gch.mask = 0
+  Init(gch.cycleRoots)
+  Init(gch.decStack)
   new(gOutOfMem) # reserve space for the EOutOfMemory exception here!
 
 proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
@@ -333,54 +325,63 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
   of tyString: nil
   else: assert(false)
 
-proc checkCollection(zctUpdated: bool) {.inline.} =
+proc checkCollection {.inline.} =
   # checks if a collection should be done
   if recGcLock == 0:
-    collectCT(gch, zctUpdated)
+    collectCT(gch)
 
 proc newObj(typ: PNimType, size: int): pointer =
   # generates a new object and sets its reference counter to 0
   assert(typ.kind in {tyRef, tyString, tySequence})
-  var zctUpdated = false
-  if gch.zct.len >= ZctThreshold:
-    updateZCT()
-    zctUpdated = true
-  # check if we have to collect:
-  checkCollection(zctUpdated)
-  var res = cast[PCell](gcAlloc(size + sizeof(TCell)))
-  when stressGC: assert((cast[TAddress](res) and (MemAlignment-1)) == 0)
+  checkCollection()
+  var res = cast[PCell](rawAlloc(allocator, size + sizeof(TCell)))
+  zeroMem(res, size+sizeof(TCell))
+  assert((cast[TAddress](res) and (MemAlign-1)) == 0)
   # now it is buffered in the ZCT
   res.typ = typ
   when debugGC:
     if framePtr != nil and framePtr.prev != nil:
       res.filename = framePtr.prev.filename
       res.line = framePtr.prev.line
-  res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT
-  add(gch.zct, res) # its refcount is zero, so add it to the ZCT
-  gch.mask = gch.mask or cast[TAddress](res)
+  res.refcount = rcZct # refcount is zero, but mark it to be in the ZCT  
+  assert(isAllocatedPtr(allocator, res))
+  # its refcount is zero, so add it to the ZCT:
+  block addToZCT: 
+    # we check the last 8 entries (cache line) for a slot
+    # that could be reused
+    var L = gch.zct.len
+    var d = gch.zct.d
+    for i in countdown(L-1, max(0, L-8)):
+      var c = d[i]
+      if c.refcount >=% rcIncrement:
+        c.refcount = c.refcount and not colorMask
+        d[i] = res
+        break addToZCT
+    add(gch.zct, res)
   when logGC: writeCell("new cell", res)
   gcTrace(res, csAllocated)
   result = cellToUsr(res)
 
 proc newSeq(typ: PNimType, len: int): pointer =
-  # XXX: overflow checks!
-  result = newObj(typ, len * typ.base.size + GenericSeqSize)
+  result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
   cast[PGenericSeq](result).len = len
   cast[PGenericSeq](result).space = len
 
 proc growObj(old: pointer, newsize: int): pointer =
-  checkCollection(false)
+  checkCollection()
   var ol = usrToCell(old)
   assert(ol.typ != nil)
   assert(ol.typ.kind in {tyString, tySequence})
-  var res = cast[PCell](gcAlloc(newsize + sizeof(TCell)))
+  var res = cast[PCell](rawAlloc(allocator, newsize + sizeof(TCell)))
   var elemSize = 1
   if ol.typ.kind != tyString:
     elemSize = ol.typ.base.size
-  copyMem(res, ol, cast[PGenericSeq](old).len*elemSize +
-          GenericSeqSize + sizeof(TCell))
-
-  assert((cast[TAddress](res) and (MemAlignment-1)) == 0)
+  
+  var oldsize = cast[PGenericSeq](old).len*elemSize + GenericSeqSize
+  copyMem(res, ol, oldsize + sizeof(TCell))
+  zeroMem(cast[pointer](cast[TAddress](res)+% oldsize +% sizeof(TCell)),
+          newsize-oldsize)
+  assert((cast[TAddress](res) and (MemAlign-1)) == 0)
   assert(res.refcount shr rcShift <=% 1)
   #if res.refcount <% rcIncrement:
   #  add(gch.zct, res)
@@ -395,13 +396,12 @@ proc growObj(old: pointer, newsize: int): pointer =
         break
       dec(j)
   if canBeCycleRoot(ol): excl(gch.cycleRoots, ol)
-  gch.mask = gch.mask or cast[TAddress](res)
   when logGC:
     writeCell("growObj old cell", ol)
     writeCell("growObj new cell", res)
   gcTrace(ol, csZctFreed)
   gcTrace(res, csAllocated)
-  when reallyDealloc: tlsf_free(ol)
+  when reallyDealloc: rawDealloc(allocator, ol)
   else:
     assert(ol.typ != nil)
     zeroMem(ol, sizeof(TCell))
@@ -409,13 +409,6 @@ proc growObj(old: pointer, newsize: int): pointer =
 
 # ---------------- cycle collector -------------------------------------------
 
-# When collecting cycles, we have to consider the following:
-# * there may still be references in the stack
-# * some cells may still be in the ZCT, because they are referenced from
-#   the stack (!), so their refcounts are zero
-# the ZCT is a subset of stackCells here, so we only need to care
-# for stackcells
-
 proc doOperation(p: pointer, op: TWalkOp) =
   if p == nil: return
   var c: PCell = usrToCell(p)
@@ -438,36 +431,25 @@ proc collectCycles(gch: var TGcHeap) =
   for c in elements(gch.cycleRoots):
     inc(tabSize)
     forallChildren(c, waCycleDecRef)
-  gch.cycleTableSize = max(gch.cycleTableSize, tabSize)
+  gch.stat.cycleTableSize = max(gch.stat.cycleTableSize, tabSize)
 
   # restore reference counts (a depth-first traversal is needed):
-  var marker, newRoots: TCellSet
-  CellSetInit(marker)
-  CellSetInit(newRoots)
+  var marker: TCellSet
+  Init(marker)
   for c in elements(gch.cycleRoots):
-    var needsRestore = false
-    if c in gch.stackCells:
-      needsRestore = true
-      incl(newRoots, c)
-      # we need to scan this later again; maybe stack changes
-      # NOTE: adding to ZCT here does NOT work
-    elif c.refcount >=% rcIncrement:
-      needsRestore = true
-    if needsRestore:
-      if c notin marker:
-        incl(marker, c)
+    if c.refcount >=% rcIncrement:
+      if not containsOrIncl(marker, c):
         gch.tempStack.len = 0
         forAllChildren(c, waPush)
         while gch.tempStack.len > 0:
           dec(gch.tempStack.len)
           var d = gch.tempStack.d[gch.tempStack.len]
           d.refcount = d.refcount +% rcIncrement
-          if d notin marker and d in gch.cycleRoots:
-            incl(marker, d)
+          if d in gch.cycleRoots and not containsOrIncl(marker, d):
             forAllChildren(d, waPush)
   # remove cycles:
   for c in elements(gch.cycleRoots):
-    if c.refcount <% rcIncrement and c notin gch.stackCells:
+    if c.refcount <% rcIncrement:
       gch.tempStack.len = 0
       forAllChildren(c, waPush)
       while gch.tempStack.len > 0:
@@ -480,21 +462,23 @@ proc collectCycles(gch: var TGcHeap) =
       prepareDealloc(c)
       gcTrace(c, csCycFreed)
       when logGC: writeCell("cycle collector dealloc cell", c)
-      when reallyDealloc: tlsf_free(c)
+      when reallyDealloc: rawDealloc(allocator, c)
       else:
         assert(c.typ != nil)
         zeroMem(c, sizeof(TCell))
-  CellSetDeinit(gch.cycleRoots)
-  gch.cycleRoots = newRoots
+  Deinit(gch.cycleRoots)
+  Init(gch.cycleRoots)
 
-proc gcMark(p: pointer) {.noinline.} =
+proc gcMark(p: pointer) {.inline.} =
   # the addresses are not as objects on the stack, so turn them to objects:
   var cell = usrToCell(p)
   var c = cast[TAddress](cell)
-  if ((c and gch.mask) == c) and c >% 1024:
+  if c >% PageSize:
     # fast check: does it look like a cell?
-    when logGC: cfprintf(cstdout, "in stackcells %p\n", cell)
-    incl(gch.stackCells, cell)  # yes: mark it
+    if isAllocatedPtr(allocator, cell): 
+      # mark the cell:
+      cell.refcount = cell.refcount +% rcIncrement
+      add(gch.decStack, cell)
 
 # ----------------- stack management --------------------------------------
 #  inspired from Smart Eiffel
@@ -560,53 +544,6 @@ elif defined(hppa) or defined(hp9000) or defined(hp9000s300) or
         gcMark(sp^)
         sp = cast[ppointer](cast[TAddress](sp) -% sizeof(pointer))
 
-elif defined(I386) and asmVersion:
-  # addresses decrease as the stack grows:
-  proc isOnStack(p: pointer): bool =
-    var
-      stackTop: array [0..1, pointer]
-    result = p >= addr(stackTop[0]) and p <= stackBottom
-
-  proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
-    # This code should be safe even for aggressive optimizers. The try
-    # statement safes all registers into the safepoint, which we
-    # scan additionally to the stack.
-    type
-      TPtrArray = array[0..0xffffff, pointer]
-    try:
-      var pa = cast[ptr TPtrArray](excHandler)
-      for i in 0 .. sizeof(TSafePoint) - 1:
-        gcMark(pa[i])
-    finally:
-      # iterate over the stack:
-      var max = cast[TAddress](stackBottom)
-      var stackTop{.volatile.}: array [0..15, pointer]
-      var sp {.volatile.} = cast[TAddress](addr(stackTop[0]))
-      while sp <= max:
-        gcMark(cast[ppointer](sp)^)
-        sp = sp +% sizeof(pointer)
-    when false:
-      var counter = 0
-      #mov ebx, OFFSET `stackBottom`
-      #mov ebx, [ebx]
-      asm """
-        pusha
-        mov edi, esp
-        call `getStackBottom`
-        mov ebx, eax
-      L1:
-        cmp edi, ebx
-        ja L2
-        mov eax, [edi]
-        call `gcMark`
-        add edi, 4
-        inc [`counter`]
-        jmp L1
-      L2:
-        popa
-      """
-      cfprintf(cstdout, "stack %ld\n", counter)
-
 else:
   # ---------------------------------------------------------------------------
   # Generic code for architectures where addresses decrease as the stack grows.
@@ -617,82 +554,47 @@ else:
     result = p >= addr(stackTop[0]) and p <= stackBottom
 
   var
-    gRegisters: C_JmpBuf
     jmpbufSize {.importc: "sizeof(jmp_buf)", nodecl.}: int
       # a little hack to get the size of a TJmpBuf in the generated C code
       # in a platform independant way
 
   proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
-    when false:
-      # new version: several C compilers are too smart here
-      var
-        max = cast[TAddress](stackBottom)
-        stackTop: array [0..15, pointer]
-      if c_setjmp(gregisters) == 0'i32: # To fill the C stack with registers.
-        # iterate over the registers:
-        var sp = cast[TAddress](addr(gregisters))
-        while sp < cast[TAddress](addr(gregisters))+%jmpbufSize:
-          gcMark(cast[ppointer](sp)^)
-          sp = sp +% sizeof(pointer)
-        # iterate over the stack:
-        sp = cast[TAddress](addr(stackTop[0]))
-        while sp <= max:
-          gcMark(cast[ppointer](sp)^)
-          sp = sp +% sizeof(pointer)
-      else:
-        c_longjmp(gregisters, 42)
-        # this can never happen, but should trick any compiler that is
-        # not as smart as a human
-    else:
-      var
-        max = stackBottom
-        registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
-        sp: PPointer        # Used to traverse the stack and registers assuming
-                            # that 'setjmp' will save registers in the C stack.
-      if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
-        sp = cast[ppointer](addr(registers))
-        while sp <= max:
-          gcMark(sp^)
-          sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
+    var
+      max = stackBottom
+      registers: C_JmpBuf # The jmp_buf buffer is in the C stack.
+      sp: PPointer        # Used to traverse the stack and registers assuming
+                          # that 'setjmp' will save registers in the C stack.
+    if c_setjmp(registers) == 0'i32: # To fill the C stack with registers.
+      sp = cast[ppointer](addr(registers))
+      while sp <= max:
+        gcMark(sp^)
+        sp = cast[ppointer](cast[TAddress](sp) +% sizeof(pointer))
 
 # ----------------------------------------------------------------------------
 # end of non-portable code
 # ----------------------------------------------------------------------------
 
-proc updateZCT() =
-  # We have to make an additional pass over the ZCT unfortunately, because 
-  # the ZCT may be out of date, which means it contains cells with a
-  # refcount > 0. The reason is that ``incRef`` does not bother to remove
-  # the cell from the ZCT as this might be too slow.
-  var j = 0
-  var L = gch.zct.len # because globals make it hard for the optimizer
-  var d = gch.zct.d
-  while j < L:
-    var c = d[j]
-    if c.refcount >=% rcIncrement:
-      when logGC: writeCell("remove from ZCT", c)
-      # remove from ZCT:
-      dec(L)
-      d[j] = d[L]
-      c.refcount = c.refcount and not colorMask
-      # we have a new cell at position j, so don't increment j
-    else:
-      inc(j)
-  gch.zct.len = L
-
 proc CollectZCT(gch: var TGcHeap) =
-  var i = 0
-  while i < gch.zct.len:
-    var c = gch.zct.d[i]
-    assert(c.refcount <% rcIncrement)
+  # Note: Freeing may add child objects to the ZCT! So essentially we do 
+  # deep freeing, which is bad for incremental operation. In order to 
+  # avoid a deep stack, we move objects to keep the ZCT small.
+  # This is performance critical!
+  var L = addr(gch.zct.len)
+  while L^ > 0:
+    var c = gch.zct.d[0]
+    # remove from ZCT:
     assert((c.refcount and colorMask) == rcZct)
-    if canBeCycleRoot(c): excl(gch.cycleRoots, c)
-    if c notin gch.stackCells:
-      # remove from ZCT:
-      c.refcount = c.refcount and not colorMask
-      gch.zct.d[i] = gch.zct.d[gch.zct.len-1]
-      # we have a new cell at position i, so don't increment i
-      dec(gch.zct.len)
+    c.refcount = c.refcount and not colorMask
+    gch.zct.d[0] = gch.zct.d[L^ - 1]
+    dec(L^)
+    if c.refcount <% rcIncrement: 
+      # It may have a RC > 0, if it is in the hardware stack or
+      # it has not been removed yet from the ZCT. This is because
+      # ``incref`` does not bother to remove the cell from the ZCT 
+      # as this might be too slow.
+      # In any case,  it should be removed from the ZCT. But not
+      # freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
+      if canBeCycleRoot(c): excl(gch.cycleRoots, c)
       when logGC: writeCell("zct dealloc cell", c)
       gcTrace(c, csZctFreed)
       # We are about to free the object, call the finalizer BEFORE its
@@ -700,51 +602,53 @@ proc CollectZCT(gch: var TGcHeap) =
       # access invalid memory. This is done by prepareDealloc():
       prepareDealloc(c)
       forAllChildren(c, waZctDecRef)
-      when reallyDealloc: tlsf_free(c)
+      when reallyDealloc: rawDealloc(allocator, c)
       else:
         assert(c.typ != nil)
         zeroMem(c, sizeof(TCell))
-    else:
-      inc(i)
-  when stressGC:
-    for j in 0..gch.zct.len-1: assert(gch.zct.d[j] in gch.stackCells)
 
-proc collectCT(gch: var TGcHeap, zctUpdated: bool) =
+proc unmarkStackAndRegisters(gch: var TGcHeap) = 
+  var d = gch.decStack.d
+  for i in 0..gch.decStack.len-1:
+    assert isAllocatedPtr(allocator, d[i])
+    decRef(d[i]) # OPT: cannot create a cycle!
+  gch.decStack.len = 0
+
+proc collectCT(gch: var TGcHeap) =
   if gch.zct.len >= ZctThreshold or (cycleGC and
-      getOccupiedMem() >= cycleThreshold) or stressGC:    
-    if not zctUpdated: updateZCT()
-    gch.maxStackSize = max(gch.maxStackSize, stackSize())
-    CellSetInit(gch.stackCells)
+      getOccupiedMem() >= cycleThreshold) or stressGC:
+    gch.stat.maxStackSize = max(gch.stat.maxStackSize, stackSize())
+    assert(gch.decStack.len == 0)
     markStackAndRegisters(gch)
-    gch.maxStackPages = max(gch.maxStackPages, gch.stackCells.counter)
-    inc(gch.stackScans)
+    gch.stat.maxStackCells = max(gch.stat.maxStackCells, gch.decStack.len)
+    inc(gch.stat.stackScans)
     collectZCT(gch)
     when cycleGC:
       if getOccupiedMem() >= cycleThreshold or stressGC:
         collectCycles(gch)
         collectZCT(gch)
-        inc(gch.cycleCollections)
+        inc(gch.stat.cycleCollections)
         cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
                              cycleIncrease)
-        gch.maxThreshold = max(gch.maxThreshold, cycleThreshold)
-    CellSetDeinit(gch.stackCells)
+        gch.stat.maxThreshold = max(gch.stat.maxThreshold, cycleThreshold)
+    unmarkStackAndRegisters(gch)
 
 proc GC_fullCollect() =
   var oldThreshold = cycleThreshold
   cycleThreshold = 0 # forces cycle collection
-  collectCT(gch, false)
+  collectCT(gch)
   cycleThreshold = oldThreshold
 
 proc GC_getStatistics(): string =
   GC_disable()
   result = "[GC] total memory: " & $(getTotalMem()) & "\n" &
            "[GC] occupied memory: " & $(getOccupiedMem()) & "\n" &
-           "[GC] stack scans: " & $gch.stackScans & "\n" &
-           "[GC] stack pages: " & $gch.maxStackPages & "\n" &
-           "[GC] cycle collections: " & $gch.cycleCollections & "\n" &
-           "[GC] max threshold: " & $gch.maxThreshold & "\n" &
+           "[GC] stack scans: " & $gch.stat.stackScans & "\n" &
+           "[GC] stack cells: " & $gch.stat.maxStackCells & "\n" &
+           "[GC] cycle collections: " & $gch.stat.cycleCollections & "\n" &
+           "[GC] max threshold: " & $gch.stat.maxThreshold & "\n" &
            "[GC] zct capacity: " & $gch.zct.cap & "\n" &
-           "[GC] max cycle table size: " & $gch.cycleTableSize & "\n" &
-           "[GC] max stack size: " & $gch.maxStackSize
+           "[GC] max cycle table size: " & $gch.stat.cycleTableSize & "\n" &
+           "[GC] max stack size: " & $gch.stat.maxStackSize
   when traceGC: writeLeakage()
   GC_enable()
diff --git a/lib/lexbase.nim b/lib/lexbase.nim
index f6861a5b6..bb207e92a 100644
--- a/lib/lexbase.nim
+++ b/lib/lexbase.nim
@@ -1,7 +1,7 @@
 #
 #
 #           The Nimrod Compiler
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
diff --git a/lib/macros.nim b/lib/macros.nim
index 2c71f31c8..2b75a1545 100644
--- a/lib/macros.nim
+++ b/lib/macros.nim
@@ -1,15 +1,17 @@
 #

 #

 #            Nimrod's Runtime Library

-#        (c) Copyright 2008 Andreas Rumpf

+#        (c) Copyright 2009 Andreas Rumpf

 #

 #    See the file "copying.txt", included in this

 #    distribution, for details about the copyright.

 #

 

 

-## This module contains the interface to the compiler's abstract syntax tree.

-## Abstract syntax trees should be modified in macros.

+## This module contains the interface to the compiler's abstract syntax 
+## tree (`AST`:idx:). Macros operate on this tree.

+
+## .. include:: ../doc/astspec.txt
 

 #[[[cog

 #def toEnum(name, elems):

@@ -235,3 +237,13 @@ proc newCall*(theProc: string,
   result.add(newIdentNode(theProc))

   result.add(args)

 
+proc nestList*(theProc: TNimrodIdent,  
+               x: PNimrodNode): PNimrodNode {.compileTime.} = 
+  ## nests the list `x` into a tree of call expressions:
+  ## ``[a, b, c]`` is transformed into ``theProc(a, theProc(c, d))``
+  var L = x.len
+  result = newCall(theProc, x[L-2], x[L-1])
+  var a = result
+  for i in countdown(L-3, 0):
+    a = newCall(theProc, x[i], copyNimTree(a))
+
diff --git a/lib/math.nim b/lib/math.nim
index 31783efce..bc180f72c 100644
--- a/lib/math.nim
+++ b/lib/math.nim
@@ -208,5 +208,40 @@ else:
     var y = exp(2.0*x)
     return (y-1.0)/(y+1.0)
 
+
+type
+  TRunningStat* = object  ## an accumulator for statistical data
+    n*: int               ## number of pushed data
+    sum*, min*, max*, mean*: float ## self-explaining
+    oldM, oldS, newS: float
+
+proc push*(s: var TRunningStat, x: float) = 
+  ## pushes a value `x` for processing
+  inc(s.n)
+  # See Knuth TAOCP vol 2, 3rd edition, page 232
+  if s.n == 1:
+    s.oldM = x
+    s.mean = x
+    s.oldS = 0.0
+  else:
+    s.mean = s.oldM + (x - s.oldM)/toFloat(s.n)
+    s.newS = s.oldS + (x - s.oldM)*(x - s.mean)
+
+    # set up for next iteration:
+    s.oldM = s.mean
+    s.oldS = s.newS
+  
+  s.sum = s.sum + x
+  if s.min > x: s.min = x
+  if s.max < x: s.max = x
+
+proc variance*(s: TRunningStat): float = 
+  ## computes the current variance of `s`
+  if s.n > 1: result = s.newS / (toFloat(s.n - 1))
+
+proc standardDeviation*(s: TRunningStat): float = 
+  ## computes the current standard deviation of `s`
+  result = sqrt(variance(s))
+
 {.pop.}
 {.pop.}
diff --git a/lib/memman.nim b/lib/memman.nim
deleted file mode 100644
index 249607e2d..000000000
--- a/lib/memman.nim
+++ /dev/null
@@ -1,698 +0,0 @@
-#
-#
-#            Nimrod's Runtime Library
-#        (c) Copyright 2008 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-
-# Memory manager. Based on:
-# Two Levels Segregate Fit memory allocator (TLSF)
-# Version 2.4.2
-#
-# Written by Miguel Masmano Tello <mimastel@doctor.upv.es>
-#
-# Thanks to Ismael Ripoll for his suggestions and reviews
-#
-# Copyright (C) 2008, 2007, 2006, 2005, 2004
-# 
-# This code is released using a dual license strategy: GPL/LGPL
-# You can choose the licence that better fits your requirements.
-# 
-# Released under the terms of the GNU General Public License Version 2.0
-# Released under the terms of the GNU Lesser General Public License Version 2.1
-
-
-# Some IMPORTANT TLSF parameters
-const
-  blockAlign = sizeof(pointer) * 2
-  maxFli = 30
-  maxLog2Sli = 5
-  maxSli = 1 shl maxLog2Sli
-  
-  fliOffset = 6 # tlsf structure just will manage blocks bigger than 128 bytes
-  smallBlock = 128
-  realFli = MaxFli - fliOffset
-  
-type
-  TFreePtr {.final.} = object
-    prev, next: PBhdr
-  Pbhdr = ptr Tbhdr
-  Tbhdr {.final.} = object
-    prevHdr: Pbhdr # this is just valid if the first bit of size is set
-    size: int # the size is stored in bytes 
-              # bit 0 indicates whether the block is used and
-              # bit 1 allows to know whether the previous block is free
-    freePtr: TFreePtr # at this offset bhdr.buffer starts (was a union in the
-                      # C version)
-  TAreaInfo  {.final.} = object  # This structure is embedded at the beginning
-                                 # of each area, giving us enough information 
-                                 # to cope with a set of areas
-    theEnd: Pbhdr
-    next: PAreaInfo
-  PAreaInfo = ptr TAreaInfo
-
-  TLSF {.final.} = object
-    tlsf_signature: int32 # the TLSF's structure signature
-    usedSize, maxSize: int
-    areaHead: PAreaInfo # A linked list holding all the existing areas
-
-    flBitmap: int32  # the first-level bitmap
-                     # This array should have a size of REAL_FLI bits
-    slBitmap: array[0..realFli, int32] # the second-level bitmap
-    matrix: array [0..realFli, array[0..maxSli, PBhdr]]
-  
-const
-  minBlockSize = sizeof(TFreePtr)
-  bhdrOverhead = sizeof(Tbhdr) - minBlockSize
-  tlsfSignature = 0x2A59FA59
-  ptrMask = sizeof(pointer) - 1
-  blockSize = 0xFFFFFFFF - ptrMask
-  memAlign = blockAlign - 1
-  blockState = 0x1
-  prevState = 0x2
-
-  freeBlock = 0x1 # bit 0 of the block size
-  usedBlock = 0x0
-
-  prevFree = 0x2 # bit 1 of the block size
-  prevUsed = 0x0
-  
-  defaultAreaSize = 64*1024 # 1024*10
-  pageSize = if defined(cpu32): 4096 else: 4096*2
-  
-
-proc getNextBlock(adr: pointer, r: int): PBhdr {.inline.} = 
-  return cast[PBhdr](cast[TAddress](adr) +% r)
-
-proc roundupSize(r: int): int = return (r +% memAlign) and not memAlign
-proc rounddownSize(r: int): int = return r and not memAlign
-proc roundup(x, v: int): int = return (((not x)+%1) and (v-%1)) +% x
-
-proc addSize(s: PTLSF, b: Pbhdr) =
-  inc(s.usedSize, (b.size and blockSize) + bhdrOverhead)
-  s.maxSize = max(s.maxSize, s.usedSize)
-
-proc removeSize(s: PTLSF, b: Pbhdr) =
-  dec(s.usedSize, (b.size and blockSize) + bhdrOverhead)
-
-# ------------ platform specific code -----------------------------------------
-
-when defined(posix): 
-  const # XXX: make these variables for portability?
-    PROT_READ  = 1             # page can be read 
-    PROT_WRITE = 2             # page can be written 
-    PROT_EXEC  = 4             # page can be executed 
-    PROT_NONE  = 0             # page can not be accessed 
-
-    MAP_SHARED    = 1          # Share changes 
-    MAP_PRIVATE   = 2          # Changes are private 
-    MAP_TYPE      = 0xf        # Mask for type of mapping 
-    MAP_FIXED     = 0x10       # Interpret addr exactly 
-    MAP_ANONYMOUS = 0x20       # don't use a file 
-
-    MAP_GROWSDOWN  = 0x100     # stack-like segment 
-    MAP_DENYWRITE  = 0x800     # ETXTBSY 
-    MAP_EXECUTABLE = 0x1000    # mark it as an executable 
-    MAP_LOCKED     = 0x2000    # pages are locked 
-    MAP_NORESERVE  = 0x4000    # don't check for reservations 
-
-  proc mmap(adr: pointer, len: int, prot, flags, fildes: cint,
-            off: int): pointer {.header: "<sys/mman.h>".}
-
-  proc getNewArea(size: var int): pointer {.inline.} = 
-    size = roundup(size, PageSize)
-    result = mmap(0, size, PROT_READ or PROT_WRITE, 
-                           MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
-    if result == nil or result == cast[pointer](-1):
-      raiseOutOfMem()
-  
-elif defined(windows): 
-  const
-    MEM_RESERVE = 0x2000 
-    MEM_COMMIT = 0x1000
-    MEM_TOP_DOWN = 0x100000
-    PAGE_READWRITE = 0x04
-
-  proc VirtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
-                    flProtect: int32): pointer {.
-                    header: "<windows.h>", stdcall.}
-  
-  proc getNewArea(size: var int): pointer {.inline.} = 
-    size = roundup(size, PageSize)
-    result = VirtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT or MEM_TOP_DOWN,
-                          PAGE_READWRITE)
-    if result == nil: raiseOutOfMem()
-
-else: 
-  {.warning: "Generic code for allocating pages is used".}
-  # generic implementation relying on malloc:
-  proc malloc(size: int): pointer {.nodecl, importc.}
-  
-  proc getNewArea(size: var int): pointer {.inline.} = 
-    size = roundup(size, PageSize)
-    result = malloc(size)
-    if result == nil: raiseOutOfMem()
-
-# ---------------------------------------------------------------------------
-# small fixed size allocator:
-
-# Design: We manage pages. A page is of constant size, but not necessarily
-# the OS's page size. Pages are managed in a hash table taking advantage of
-# the fact that the OS is likely to give us pages with contingous numbers. 
-# A page contains either small fixed size objects of the same size or 
-# variable length objects. An object's size is always aligned at 16 byte
-# boundary. Huge objects are dealt with the TLSF algorithm. 
-# The design supports iterating over any object in a fast way. 
-
-# A bitset contains any page that starts an allocated page. The page may be
-# empty however. This bitset can be used to quickly determine if a given
-# page belongs to the GC heap. The design of the memory allocator makes it 
-# simple to return unused pages back to the OS.
-
-
-# Small bocks 
-# -----------
-#
-# If we use a list in the free object's space. Allocation and deallocation are
-# O(1). Since any object is of the same size, iteration is quite efficient too.
-# However, pointer detection is easy too: Just check if the type-field is nil.
-# Deallocation sets it to nil.
-# Algorithm:
-
-# i = 0
-# f = b.f # first free address
-# while i < max: 
-#  if a[i] == f: # not a valid block
-#    f = f.next  # next free address
-#  else:
-#    a[i] is a valid object of size s
-#  inc(i)
-
-# The zero count table is an array. Since we know that the RC is zero, we can
-# use the bits for an index into this array. Thus multiple ZCT tables are not
-# difficult to support and insertion and removal is O(1). We use negative
-# indexes for this. This makes it even fast enough (and necessary!) to do a ZCT
-# removal if the RC is incremented. 
-# 
-
-# Huge blocks
-# -----------
-#
-# Huge blocks are always rounded up to a multiple of the page size. These are
-# called *strides*. We also need to keep an index structure 
-# of (stridesize, pagelist). 
-# 
-
-const
-  MemAlign = 8
-  PageShift = if sizeof(int) == 4: 12 else: 13
-  PageSize = 1 shl PageShift
-type
-  TFreeList {.final.} = object
-    next, prev: ptr TFreeList
-
-  TPageDesc {.final.} = object  # the start of a stride always starts with this!
-    size: int                   # lowest bit is set, if it is a huge block
-    free: ptr TFreeList         # only used if it manages multiple cells
-    snext, sprev: ptr TPageDesc # next and prev pagedescs with the same size
-
-  TCellArray {.final.} = object
-    i: int # length
-    d: ptr array [0..1000_000, TCell]
-
-  TPageManager = table[page, ptr TPageDesc]
-
-  TGcHeap {.final.} = object
-    # structure that manages the garbage collected heap
-    zct: TCellArray
-    stackCells: TCellArray
-    smallBlocks: array [PageSize div MemAlign, ptr TPageDesc]
-    freeLists: array [PageSize div MemAlign, ptr TFreeList]
-    pages: TPageManager
-    usedPages: TPageList
-    freePages: TPageList
-
-# small blocks: 
-proc allocSmall(var h: TGcHeap, size: int): pointer = 
-  var s = align(size)
-  var f = h.freeLists[s]
-  if f != nil: 
-    f.prev = f.next # remove from list
-    f.next.prev = f.prev
-    return f
-  var p = h.smallBlocks[s]
-  if p == nil or p.free == nil:
-    p = newSmallBlock(s, p)
-    h.smallBlocks[s] = p
-  
-
-
-proc decRef(cell: PCell) {.inline.} =
-  assert(cell in ct.AT)
-  assert(cell.refcount > 0) # this should be the case!
-  assert(seqCheck(cell))
-  dec(cell.refcount)
-  if cell.refcount == 0:
-    # add to zero count table:
-    zct.d[zct.i] = cell
-    cell.recfcount = -zct.i
-    inc(zct.i)
-
-proc incRef(cell: PCell) {.inline.} =
-  assert(seqCheck(cell))
-  if cell.refcount < 0: 
-    # remove from zero count table:
-    zct.d[-cell.refcount] = zct.d[zct.i-1]
-    dec(zct.i) 
-    cell.refcount = 1
-  else:
-    inc(cell.refcount)
-
-proc asgnRef(dest: ppointer, src: pointer) =
-  # the code generator calls this proc!
-  assert(not isOnStack(dest))
-  # BUGFIX: first incRef then decRef!
-  if src != nil: incRef(usrToCell(src))
-  if dest^ != nil: decRef(usrToCell(dest^))
-  dest^ = src
-
-
-# ----------------------------------------------------------------------------
-#     helpers
-
-const
-  table: array[0..255, int8] = [
-      -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
-      4, 4, 4, 4, 4, 4, 4, 4, 4,
-      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
-      5, 5, 5, 5, 5, 5, 5, 5,
-      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-      6, 6, 6, 6, 6, 6, 6, 6,
-      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
-      6, 6, 6, 6, 6, 6, 6, 6,
-      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-      7, 7, 7, 7, 7, 7, 7, 7
-    ]
-
-proc ls_bit(i: int32): int {.inline.} = 
-  var 
-    a: int = 0
-    x: int = i and -i
-  if x <=% 0xffff:
-    if x <=% ff: a = 0
-    else: a = 8
-  elif x <=% 0xffffff: a = 16
-  else: a = 24
-  return table[x shr a] + a
-
-proc ms_bit(i: int): int {.inline.} = 
-  var
-    a = if i <=% 0xffff: (if i <=% 0xff: 0 else: 8) elif 
-           i <=% 0xffffff: 16 else: 24
-  return table[i shr a] + a
-
-proc set_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} =
-  adr[nr shr 5] = adr[nr shr 5] or (1 shl (nr and 0x1f))
-
-proc clear_bit[IX](nr: int, adr: var array[IX, int32]) {.inline.} =
-  adr[nr shr 5] = adr[nr shr 5] and not (1 shl (nr and 0x1f))
-
-proc mappingSearch(r, fl, sl: var int) {.inline.} = 
-  if r < smallBlock: 
-    fl = 0
-    sl = r div (smallBlock div maxSli)
-  else:
-    var t = (1 shl (ms_bit(r) - maxLog2Sli)) - 1
-    r = r + t
-    fl = ms_bit(r)
-    sl = (r shl (fl - maxLog2Sli)) - maxSli
-    fl = fl - fliOffset
-    r = r and not t
-
-proc mappingInsert(r: int, fl, sl: var int) {.inline.} = 
-  if r < smallBlock:
-    fl = 0
-    sl = r div (smallBlock div maxSli)
-  else:
-    fl = ms_bit(r)
-    sl = (r shr (fl - maxLog2Sli)) - maxSli
-    fl = fl - fliOffset
-
-proc findSuitableBlock(t: var TLSF, fl, sl: var int): Pbhdr =
-  var tmp = t.slBitmap[fl] and ((not 0) shl sl)
-  if tmp != 0:
-    sl = ls_bit(tmp)
-    result = t.matrix[fl][sl]
-  else:
-    fl = ls_bit(t.flBitmap and (not 0 shl (fl + 1)))
-    if fl > 0: # likely
-      sl = ls_bit(t.slBitmap[fl])
-      result = t.matrix[fl][sl]
-
-proc extractBlockHdr(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = 
-  t.matrix[fl][sl] = b.freePtr.next
-  if t.matrix[fl][sl] != nil:
-    t.matrix[fl][sl].freePtr.prev = nil
-  else:
-    clear_bit(sl, t.slBitmap[fl])
-    if t.slBitmap[fl] == 0:
-      clear_bit(fl, t.flBitmap)
-  b.freePtr.prev = nil
-  b.freePtr.next = nil
-
-proc extractBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} =
-  if b.freePtr.next != nil:
-    b.freePtr.next.freePtr.prev = b.freePtr.prev
-  if b.freePtr.prev != nil:
-    b.freePtr.prev.freePtr.next = b.freePtr.next
-  if t.matrix[fl][sl] == b:
-    t.matrix[fl][sl] = b.freePtr.next
-    if t.matrix[fl][sl] == nil:
-      clear_bit(sl, t.slBitmap[fl])
-      if t.slBitmap[fl] == 0:
-        clear_bit(fl, t.flBitmap)
-  b.freePtr.prev = nil
-  b.freePtr.next = nil
-
-proc insertBlock(b: Pbhdr, t: var TLSF, fl, sl: int) {.inline.} = 
-  b.freePtr.prev = nil
-  b.freePtr.next = t.matrix[fl][sl] 
-  if t.matrix[fl][sl] != nil:
-    t.matrix[fl][sl].freePtr.prev = b		
-  t.matrix[fl][sl] = b
-  set_bit(sl, t.slBitmap[fl])
-  set_bit(fl, t.flBitmap)
-
-proc getBuffer(b: Pbhdr): pointer {.inline.} = 
-  result = cast[pointer](addr(b.freePtr))
-
-proc processArea(area: pointer, size: int): Pbhdr =
-  var 
-    b, lb, ib: Pbhdr
-    ai: PAreaInfo
-  ib = cast[Pbhdr](area)
-  if sizeof(TAreaInfo) < minBlockSize:
-    ib.size = minBlockSize or usedBlock or prevUsed
-  else
-    ib.size = roundupSize(sizeof(TAreaInfo)) or usedBlock or prevUsed
-  b = getNextBlock(getBuffer(ib), ib.size and blockSize)
-  b.size = rounddownSize(size - 3 * bhdrOverhead - (ib.size and blockSize)) or
-           usedBlock or prevUsed
-  b.freePtr.prev = nil
-  b.freePtr.next = nil
-  lb = getNextBlock(getBuffer(b), b.size and blockSize)
-  lb.prevHdr = b
-  lb.size = 0 or usedBlock or prevFree
-  ai = cast[PAreaInfo](getBuffer(ib))
-  ai.next = nil
-  ai.theEnd = lb
-  return ib
-
-# ----------------------------------------------------------------------------
-#                  Begin of the allocator code
-
-proc initMemoryPool(memPoolSize: int, memPool: pointer): int = 
-  var
-    t: PLSF
-    b, ib: Pbhdr
-
-  if memPool == nil or memPoolSize < sizeof(TLSF) + bhdrOverhead * 8:
-    writeToStdErr("initMemoryPool(): memory_pool invalid\n")
-    return -1
-
-  if (cast[TAddress](memPool) and ptrMask) != 0:
-    writeToStdErr("initMemoryPool(): memPool must be aligned to a word\n")
-    return -1
-  t = cast[PLSF](memPool)
-  # Check if already initialised
-  if t.signature == tlsfSignature:
-    b = getNextBlock(memPool, roundupSize(sizeof(TLSF)))
-    return b.size and blockSize
-  zeroMem(memPool, sizeof(TLSF))
-
-  t.signature = tlsfSignature
-  ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), 
-                   rounddownSize(memPoolSize - sizeof(TLSF)))
-  b = getNextBlock(getBuffer(ib), ib.size and blockSize)
-  freeEx(getBuffer(b), t)
-  t.areaHead = cast[PAreaInfo](getBuffer(ib))
-
-  t.used_size = memPoolSize - (b.size and blockSize)
-  t.max_size = t.used_size
-  return b.size and blockSize
-
-
-proc addNewArea(area: pointer, areaSize: int, t: var TLSF): int = 
-  var
-    p, ptrPrev, ai: PAreaInfo
-    ib0, b0, lb0, ib1, b1, lb1, nextB: Pbhdr
-
-  zeroMem(area, areaSize)
-  p = t.areaHead
-  ptrPrev = 0
-
-  ib0 = processArea(area, areaSize)
-  b0 = getNextBlock(getBuffer(ib0), ib0.size and blockSize)
-  lb0 = getNextBlock(getBuffer(b0), b0.size and blockSize)
-
-  # Before inserting the new area, we have to merge this area with the
-  # already existing ones
-  while p != nil:
-    ib1 = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead) 
-    b1 = getNextBlock(getBuffer(ib1), ib1.size and blockSize)
-    lb1 = p.theEnd
-
-    # Merging the new area with the next physically contigous one
-    if cast[TAddress](ib1) == cast[TAddress](lb0) +% bhdrOverhead:
-      if t.areaHead == p:
-        t.areaHead = p.next
-        p = p.next
-      else:
-        ptrPrev.next = p.next
-        p = p.next
-      b0.size = rounddownSize((b0.size and blockSize) +
-                         (ib1.size and blockSize) + 2 * bhdrOverhead) or
-                         usedBlock or prevUsed
-      b1.prevHdr = b0
-      lb0 = lb1
-      continue
-
-    # Merging the new area with the previous physically contigous one
-    if getBuffer(lb1) == pointer(ib0):
-      if t.areaHead == p:
-        t.areaHead = p.next
-        p = p.next
-      else:
-        ptrPrev.next = p.next
-        p = p.next
-      lb1->size = rounddownSize((b0.size and blockSize) +
-                   (ib0.size and blockSize) + 2 * bhdrOverhead) or
-                   usedBlock or (lb1.size and prevState)
-      nextB = getNextBlock(getBuffer(lb1), lb1.size and blockSize)
-      nextB.prevHdr = lb1
-      b0 = lb1
-      ib0 = ib1
-      continue
-    ptrPrev = p
-    p = p.next
-
-  # Inserting the area in the list of linked areas 
-  ai = cast[PAreaInfo](getBuffer(ib0))
-  ai.next = t.areaHead
-  ai.theEnd = lb0
-  t.areaHead = ai
-  freeEx(getBuffer(b0), memPool)
-  return (b0.size and blockSize)
-
-proc mallocEx(asize: int, t: var TLSF): pointer = 
-  var
-    b, b2, nextB: Pbhdr
-    fl, sl, tmpSize, size: int
-
-  size = if asize < minBlockSize: minBlockSize else: roundupSize(asize)
-
-  # Rounding up the requested size and calculating fl and sl
-  mappingSearch(size, fl, sl)
-
-  # Searching a free block, recall that this function changes the values
-  # of fl and sl, so they are not longer valid when the function fails
-  b = findSuitableBlock(tlsf, fl, sl)
-  if b == nil: 
-    # Growing the pool size when needed 
-    # size plus enough room for the required headers:
-    var areaSize = max(size + bhdrOverhead * 8, defaultAreaSize)
-    var area = getNewArea(areaSize)
-    addNewArea(area, areaSize, t)
-    # Rounding up the requested size and calculating fl and sl
-    mappingSearch(size, fl, sl)
-    # Searching a free block
-    b = findSuitableBlock(t, fl, sl)
-    if b == nil: 
-      raiseOutOfMem()
-
-  extractBlockHdr(b, t, fl, sl)
-
-  #-- found:
-  nextB = getNextBlock(getBuffer(b), b.size and blockSize)
-  # Should the block be split?
-  tmpSize = (b.size and blockSize) - size
-  if tmpSize >= sizeof(Tbhdr):
-    dec(tmpSize, bhdrOverhead)
-    b2 = getNextBlock(getBuffer(b), size)
-    b2.size = tmpSize or freeBlock or prevUsed
-    nextB.prevHdr = b2
-    mappingInsert(tmpSize, fl, sl)
-    insertBlock(b2, t, fl, sl)
-
-    b.size = size or (b.size and prevState)
-  else:
-    nextB.size = nextB.size and not prevFree
-    b.size = b.size and not freeBlock # Now it's used
-
-  addSize(t, b)
-  return getBuffer(b)
-
-
-proc freeEx(p: pointer, t: var TLSF) =
-  var
-    fl = 0
-    sl = 0
-    b, tmpB: Pbhdr
-
-  assert(p != nil)
-  b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
-  b.size = b.size or freeBlock
-
-  removeSize(t, b)
-  b.freePtr.prev = nil
-  b.freePtr.next = nil
-  tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
-  if (tmpB.size and freeBlock) != 0:
-    mappingInsert(tmpB.size and blockSize, fl, sl)
-    extractBlock(tmpB, t, fl, sl)
-    inc(b.size, (tmpB.size and blockSize) + bhdrOverhead)
-  if (b.size and prevFree) != 0:
-    tmpB = b.prevHdr
-    mappingInsert(tmpB.size and blockSize, fl, sl)
-    extractBlock(tmpB, t, fl, sl)
-    inc(tmpB.size, (b.size and blockSize) + bhdrOverhead)
-    b = tmpB
-  mappingInsert(b.size and blockSize, fl, sl)
-  insertBlock(b, t, fl, sl)
-
-  tmpB = getNextBlock(getBuffer(b), b.size and blockSize)
-  tmpB.size = tmpB.size or prevFree
-  tmpB.prevHdr = b
-
-proc reallocEx(p: pointer, newSize: int, t: var TLSF): pointer = 
-  var
-    cpsize, fl, sl, tmpSize: int
-    b, tmpB, nextB: Pbhdr
-
-  assert(p != nil)
-  assert(newSize > 0)
-
-  b = cast[Pbhdr](cast[TAddress](p) -% bhdrOverhead)
-  nextB = getNextBlock(getBuffer(b), b.size and blockSize)
-  newSize = if newSize < minBlockSize: minBlockSize else: roundupSize(newSize)
-  tmpSize = b.size and blockSize
-  if newSize <= tmpSize:
-    removeSize(t, b)
-    if (nextB.size and freeBlock) != 0: 
-      mappingInsert(nextB.size and blockSize, fl, sl)
-      extractBlock(nextB, t, fl, sl)
-      inc(tmpSize, (nextB.size and blockSize) + bhdrOverhead)
-      nextB = getNextBlock(getBuffer(nextB), nextB.size and blockSize)
-      # We always reenter this free block because tmpSize will
-      # be greater then sizeof(Tbhdr)
-    dec(tmpSize, newSize)
-    if tmpSize >= sizeof(Tbhdr):
-      dec(tmpSize, bhdrOverhead)
-      tmpB = getNextBlock(getBuffer(b), newSize)
-      tmpB.size = tmpSize or freeBlock or prevUsed
-      nextB.prevHdr = tmpB
-      nextB.size = nextB.size or prevFree
-      mappingInsert(tmpSize, fl, sl)
-      insertBlock(tmpB, t, fl, sl)
-      b.size = newSize or (b.size and prevState)
-    addSize(t, b)
-    return getBuffer(b)
-  
-  if (nextB.size and freeBlock) != 0:
-    if newSize <= tmpSize + (nextB.size and blockSize):
-      removeSize(t, b)
-      mappingInsert(nextB.size and blockSize, fl, sl)
-      extractBlock(nextB, t, fl, sl)
-      inc(b.size, (nextB.size and blockSize) + bhdrOverhead)
-      nextB = getNextBlock(getBuffer(b), b.size and blockSize)
-      nextB.prevHdr = b
-      nextB.size = nextB.size and not prevFree
-      tmpSize = (b.size and blockSize) - newSize
-      if tmpSize >= sizeof(Tbhdr):
-        dec(tmpSize, bhdrOverhead)
-        tmpB = getNextBlock(getBuffer(b), newSize)
-        tmpB.size = tmpSize or freeBlock or prevUsed
-        nextB.prevHdr = tmpB
-        nextB.size = nextB.size or prevFree
-        mappingInsert(tmpSize, fl, sl)
-        insertBlock(tmpB, t, fl, sl)
-        b.size = newSize or (b.size and prevState)
-      addSize(t, b)
-      return getBuffer(b)
-
-  var ptrAux = mallocEx(newSize, t)
-  cpsize = if (b.size and blockSize) > newSize: newSize else:
-                                                (b.size and blockSize)
-  copyMem(ptrAux, p, cpsize)
-  freeEx(p, memPool)
-  return ptrAux
-
-
-proc ansiCrealloc(p: pointer, newSize: int, t: var TLSF): pointer = 
-  if p == nil: 
-    if newSize > 0: 
-      result = mallocEx(newSize, t)
-    else:
-      result = nil
-  elif newSize <= 0:
-    freeEx(p, t)
-    result = nil
-  else:
-    result = reallocEx(p, newSize, t)
-
-proc InitTLSF(t: var TLSF) = 
-  var areaSize = sizeof(TLSF) + BHDR_OVERHEAD * 8 # Just a safety constant
-  areaSize = max(areaSize, DEFAULT_areaSize)
-  var area = getNewArea(areaSize)
-  
-  
-  initMemoryPool(areaSize, area)
-
-  var
-    t: PLSF
-    b, ib: Pbhdr
-
-  t = cast[PLSF](memPool)
-  
-  zeroMem(area, areaSize)
-
-  t.signature = tlsfSignature
-  var ib = processArea(getNextBlock(memPool, roundupSize(sizeof(TLSF))), 
-                   rounddownSize(memPoolSize - sizeof(TLSF)))
-  var b = getNextBlock(getBuffer(ib), ib.size and blockSize)
-  freeEx(getBuffer(b), t)
-  t.areaHead = cast[PAreaInfo](getBuffer(ib))
-
-  t.used_size = memPoolSize - (b.size and blockSize)
-  t.max_size = t.used_size
-
-  # XXX
diff --git a/lib/mm.nim b/lib/mm.nim
new file mode 100644
index 000000000..5f16f7304
--- /dev/null
+++ b/lib/mm.nim
@@ -0,0 +1,187 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+# Nimrod high-level memory manager: It supports Boehm's GC, no GC and the
+# native Nimrod GC. The native Nimrod GC is the default.
+
+#{.push checks:on, assertions:on.}
+{.push checks:off.}
+
+const
+  debugGC = false # we wish to debug the GC...
+  logGC = false
+  traceGC = false # extensive debugging
+  reallyDealloc = true # for debugging purposes this can be set to false
+  cycleGC = true # (de)activate the cycle GC
+  stressGC = false
+  reallyOsDealloc = true
+  coalescRight = true
+  coalescLeft = true
+
+type
+  PPointer = ptr pointer
+  TByteArray = array[0..1000_0000, byte]
+  PByte = ptr TByteArray
+  PString = ptr string
+
+# Page size of the system; in most cases 4096 bytes. For exotic OS or
+# CPU this needs to be changed:
+const
+  PageShift = 12
+  PageSize = 1 shl PageShift
+  PageMask = PageSize-1
+
+  MemAlign = 8 # also minimal allocatable memory block
+
+  BitsPerPage = PageSize div MemAlign
+  UnitsPerPage = BitsPerPage div (sizeof(int)*8)
+    # how many ints do we need to describe a page:
+    # on 32 bit systems this is only 16 (!)
+
+  TrunkShift = 9
+  BitsPerTrunk = 1 shl TrunkShift # needs to be power of 2 and divisible by 64
+  TrunkMask = BitsPerTrunk - 1
+  IntsPerTrunk = BitsPerTrunk div (sizeof(int)*8)
+  IntShift = 5 + ord(sizeof(int) == 8) # 5 or 6, depending on int width
+  IntMask = 1 shl IntShift - 1
+
+var
+  gOutOfMem: ref EOutOfMemory
+
+proc raiseOutOfMem() {.noreturn.} =
+  if gOutOfMem == nil: quit("out of memory; cannot even throw an exception")
+  gOutOfMem.msg = "out of memory"
+  raise gOutOfMem
+
+when defined(boehmgc):
+  when defined(windows):
+    const boehmLib = "boehmgc.dll"
+  else:
+    const boehmLib = "/usr/lib/libgc.so.1"
+
+  proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} 
+  proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} 
+  proc boehmGCincremental {.
+    importc: "GC_enable_incremental", dynlib: boehmLib.} 
+  proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}  
+  proc boehmAlloc(size: int): pointer {.
+    importc: "GC_malloc", dynlib: boehmLib.}
+  proc boehmAllocAtomic(size: int): pointer {.
+    importc: "GC_malloc_atomic", dynlib: boehmLib.}
+  proc boehmRealloc(p: pointer, size: int): pointer {.
+    importc: "GC_realloc", dynlib: boehmLib.}
+  proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
+    
+  proc alloc(size: int): pointer =
+    result = boehmAlloc(size)
+    if result == nil: raiseOutOfMem()
+  proc alloc0(size: int): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+  proc realloc(p: Pointer, newsize: int): pointer =
+    result = boehmRealloc(p, newsize)
+    if result == nil: raiseOutOfMem()
+  proc dealloc(p: Pointer) =
+    boehmDealloc(p)
+
+  proc initGC() = nil
+  
+  #boehmGCincremental()
+
+  proc GC_disable() = boehmGC_disable()
+  proc GC_enable() = boehmGC_enable()
+  proc GC_fullCollect() = boehmGCfullCollect()
+  proc GC_setStrategy(strategy: TGC_Strategy) = nil
+  proc GC_enableMarkAndSweep() = nil
+  proc GC_disableMarkAndSweep() = nil
+  proc GC_getStatistics(): string = return ""
+  
+  proc getOccupiedMem(): int = return -1
+  proc getFreeMem(): int = return -1
+  proc getTotalMem(): int = return -1
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).space = len
+
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+
+  proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
+  
+  proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+
+  include cellsets
+elif defined(nogc):
+  proc alloc(size: int): pointer =
+    result = c_malloc(size)
+    if result == nil: raiseOutOfMem()
+  proc alloc0(size: int): pointer =
+    result = alloc(size)
+    zeroMem(result, size)
+  proc realloc(p: Pointer, newsize: int): pointer =
+    result = c_realloc(p, newsize)
+    if result == nil: raiseOutOfMem()
+  proc dealloc(p: Pointer) =
+    c_free(p)
+
+  proc initGC() = nil
+  proc GC_disable() = nil
+  proc GC_enable() = nil
+  proc GC_fullCollect() = nil
+  proc GC_setStrategy(strategy: TGC_Strategy) = nil
+  proc GC_enableMarkAndSweep() = nil
+  proc GC_disableMarkAndSweep() = nil
+  proc GC_getStatistics(): string = return ""
+  
+  proc getOccupiedMem(): int = return -1
+  proc getFreeMem(): int = return -1
+  proc getTotalMem(): int = return -1
+
+  proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
+    result = alloc0(size)
+  proc newSeq(typ: PNimType, len: int): pointer {.compilerproc.} =
+    result = newObj(typ, addInt(mulInt(len, typ.base.size), GenericSeqSize))
+    cast[PGenericSeq](result).len = len
+    cast[PGenericSeq](result).space = len
+  proc growObj(old: pointer, newsize: int): pointer =
+    result = realloc(old, newsize)
+    # XXX BUG: we need realloc0 here, but C does not support this...
+
+  proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil
+  proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
+  proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
+  
+  proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+  proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
+    dest^ = src
+
+  include cellsets
+else:
+  include alloc
+  include cellsets
+  assert(sizeof(TCell) == sizeof(TFreeCell))
+  include gc
+  
+{.pop.}
+
+  
diff --git a/lib/os.nim b/lib/os.nim
index b69002715..20e803ec0 100644
--- a/lib/os.nim
+++ b/lib/os.nim
@@ -546,7 +546,7 @@ proc getApplicationFilename(): string =
   # Solaris:
   # /proc/<pid>/object/a.out (filename only)
   # /proc/<pid>/path/a.out (complete pathname)
-  # *BSD (and maybe Darwing too):
+  # *BSD (and maybe Darwin too):
   # /proc/<pid>/file
   when defined(windows):
     result = newString(256)
diff --git a/lib/osproc.nim b/lib/osproc.nim
index 2282e802d..205460614 100644
--- a/lib/osproc.nim
+++ b/lib/osproc.nim
@@ -1,20 +1,21 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
 #
 
-## This module implements an advanced facility for executing OS processes.
-## On Windows this module is currently broken. Please help!
+## This module implements an advanced facility for executing OS processes
+## and process communication.
+## **On Windows this module does not work properly. Please help!**
 
 import
   os, strtabs, streams
 
 when defined(windows):
-  import windows
+  import winlean
 
 type
   TProcess = object of TObject
@@ -41,6 +42,10 @@ proc executeProcess*(command: string,
   ## A convience procedure that executes ``command`` with ``startProcess``
   ## and returns its output as a string.
 
+proc executeCommand*(command: string): int
+  ## Executes ``command`` and returns its error code. Standard input, output,
+  ## error streams are inherited from the calling process.
+
 proc startProcess*(command: string,
                    workingDir: string = "",
                    args: openarray[string] = [],
@@ -133,14 +138,14 @@ when defined(Windows):
 
   proc hsReadData(s: PFileHandleStream, buffer: pointer, bufLen: int): int =
     var br: int32
-    var a = windows.ReadFile(s.handle, buffer, bufLen, br, nil)
+    var a = winlean.ReadFile(s.handle, buffer, bufLen, br, nil)
     if a == 0: OSError()
     result = br
     #atEnd = bytesRead < bufLen
 
   proc hsWriteData(s: PFileHandleStream, buffer: pointer, bufLen: int) =
     var bytesWritten: int32
-    var a = windows.writeFile(s.handle, buffer, bufLen, bytesWritten, nil)
+    var a = winlean.writeFile(s.handle, buffer, bufLen, bytesWritten, nil)
     if a == 0: OSError()
 
   proc newFileHandleStream(handle: THandle): PFileHandleStream =
@@ -180,12 +185,12 @@ when defined(Windows):
   #  O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
   #  O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
 
-  proc CreatePipeHandles(Inhandle, OutHandle: ptr THandle) =
+  proc CreatePipeHandles(Inhandle, OutHandle: var THandle) =
     var piInheritablePipe: TSecurityAttributes
     piInheritablePipe.nlength = SizeOF(TSecurityAttributes)
-    piInheritablePipe.lpSecurityDescriptor = Nil
+    piInheritablePipe.lpSecurityDescriptor = nil
     piInheritablePipe.Binherithandle = 1
-    if CreatePipe(Inhandle, Outhandle, addr(piInheritablePipe), 0) == 0'i32:
+    if CreatePipe(Inhandle, Outhandle, piInheritablePipe, 0) == 0'i32:
       OSError()
 
   proc startProcess*(command: string,
@@ -201,15 +206,15 @@ when defined(Windows):
       hi, ho, he: THandle
     SI.cb = SizeOf(SI)
     SI.dwFlags = STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES
-    CreatePipeHandles(addr(SI.hStdInput), addr(HI))
-    CreatePipeHandles(addr(HO), addr(Si.hStdOutput))
+    CreatePipeHandles(SI.hStdInput, HI)
+    CreatePipeHandles(HO, Si.hStdOutput)
     #SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE())
     #SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE())
     if poStdErrToStdOut in options:
       SI.hStdError = SI.hStdOutput
       HE = HO
     else:
-      CreatePipeHandles(addr(HE), addr(Si.hStdError))
+      CreatePipeHandles(HE, Si.hStdError)
       #SI.hStdError = GetStdHandle(STD_ERROR_HANDLE())
     #result.inputHandle = open_osfhandle(HI, O_WRONLY)
     #if result.inputHandle == -1'i32: OSError()
@@ -224,16 +229,12 @@ when defined(Windows):
     var wd: cstring = nil
     if len(workingDir) > 0: wd = workingDir
     if env == nil:
-      success = Windows.CreateProcess(nil,
-        cmdl, nil, nil, 0,
-        NORMAL_PRIORITY_CLASS, nil, wd,
-        addr(SI), addr(ProcInfo))
+      success = winlean.CreateProcess(nil,
+        cmdl, nil, nil, 0, NORMAL_PRIORITY_CLASS, nil, wd, SI, ProcInfo)
     else:
       var e = buildEnv(env)
-      success = Windows.CreateProcess(nil,
-        cmdl, nil, nil, 0,
-        NORMAL_PRIORITY_CLASS, e, wd,
-        addr(SI), addr(ProcInfo))
+      success = winlean.CreateProcess(nil,
+        cmdl, nil, nil, 0, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
       dealloc(e)
     dealloc(cmdl)
     if success == 0:
@@ -249,7 +250,7 @@ when defined(Windows):
     discard ResumeThread(p.FThreadHandle)
 
   proc running(p: PProcess): bool =
-    var x = waitForSingleObject(p.FThreadHandle, 50)
+    var x = waitForSingleObject(p.FProcessHandle, 50)
     return x == WAIT_TIMEOUT
 
   proc terminate(p: PProcess) =
@@ -257,11 +258,11 @@ when defined(Windows):
       discard TerminateProcess(p.FProcessHandle, 0)
 
   proc waitForExit(p: PProcess): int =
-    discard WaitForSingleObject(p.FThreadHandle, Infinite)
-    var res: dword
+    discard CloseHandle(p.FThreadHandle)
+    discard WaitForSingleObject(p.FProcessHandle, Infinite)
+    var res: int32
     discard GetExitCodeProcess(p.FProcessHandle, res)
     result = res
-    discard CloseHandle(p.FThreadHandle)
     discard CloseHandle(p.FProcessHandle)
 
   proc inputStream(p: PProcess): PStream =
@@ -273,6 +274,29 @@ when defined(Windows):
   proc errorStream(p: PProcess): PStream =
     result = newFileHandleStream(p.errorHandle)
 
+  proc executeCommand(command: string): int = 
+    var
+      SI: TStartupInfo
+      ProcInfo: TProcessInformation
+      process: THandle
+      L: int32
+    SI.cb = SizeOf(SI)
+    SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
+    SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
+    SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
+    if winlean.CreateProcess(nil, command, nil, nil, 0,
+        NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo) == 0:
+      OSError()
+    else:
+      Process = ProcInfo.hProcess
+      discard CloseHandle(ProcInfo.hThread)
+      if WaitForSingleObject(Process, INFINITE) != -1:
+        discard GetExitCodeProcess(Process, L)
+        result = int(L)
+      else:
+        result = -1
+      discard CloseHandle(Process)
+
 else:
   import posix
 
@@ -321,15 +345,15 @@ else:
     if pid == 0:
       ## child process:
       discard close(p_stdin[writeIdx])
-      discard dup2(p_stdin[readIdx], readIdx)
+      if dup2(p_stdin[readIdx], readIdx) < 0: OSError()
       discard close(p_stdout[readIdx])
-      discard dup2(p_stdout[writeIdx], writeIdx)
+      if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError()
       if poStdErrToStdOut in options:
-        discard dup2(p_stdout[writeIdx], 2)
+        if dup2(p_stdout[writeIdx], 2) < 0: OSError()
       else:
         if pipe(p_stderr) != 0'i32: OSError("failed to create a pipe")
         discard close(p_stderr[readIdx])
-        discard dup2(p_stderr[writeIdx], 2)
+        if dup2(p_stderr[writeIdx], 2) < 0: OSError()
 
       if workingDir.len > 0:
         os.setCurrentDir(workingDir)
@@ -347,8 +371,7 @@ else:
         else:
           discard execve("/bin/sh", a, ToCStringArray(env))
       # too risky to raise an exception here:
-      echo("execve call failed: " & $strerror(errno))
-      quit(1)
+      quit("execve call failed: " & $strerror(errno))
     # Parent process. Copy process information.
     result.id = pid
 
@@ -376,6 +399,7 @@ else:
       if running(p): discard kill(p.id, SIGKILL)
 
   proc waitForExit(p: PProcess): int =
+    result = 1
     if waitPid(p.id, p.exitCode, 0) == int(p.id):
       result = p.exitCode
 
@@ -393,3 +417,11 @@ else:
     var f: TFile
     if not openFile(f, p.errorHandle, fmRead): OSError()
     result = newFileStream(f)
+
+  proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
+
+  proc executeCommand(command: string): int = 
+    result = csystem(command)
+
+when isMainModule:
+  echo executeCommand("gcc -v")
diff --git a/lib/parsecsv.nim b/lib/parsecsv.nim
new file mode 100644
index 000000000..7665c8287
--- /dev/null
+++ b/lib/parsecsv.nim
@@ -0,0 +1,176 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple high performance `CSV`:idx:
+## (`comma separated value`:idx:) parser. 
+##
+## Example: How to use the parser
+## ==============================
+##
+## .. code-block:: nimrod
+##   import os, parsecsv, streams
+##   var s = newFileStream(ParamStr(1), fmRead)
+##   if s == nil: quit("cannot open the file" & ParamStr(1))
+##   var x: TCsvParser
+##   open(x, s, ParamStr(1))
+##   while readRow(x):
+##     Echo "new row: "
+##     for val in items(x.row):
+##       Echo "##", val, "##"
+##   close(x)
+##
+
+import
+  lexbase, streams
+
+type
+  TCsvRow* = seq[string] ## a row in a CSV file
+  TCsvParser* = object of TBaseLexer ## the parser object.
+    row*: TCsvRow                    ## the current row
+    filename: string
+    sep, quote, esc: char
+    skipWhite: bool
+    currRow: int
+
+  EInvalidCsv* = object of EIO ## exception that is raised if
+                               ## a parsing error occurs
+
+proc raiseEInvalidCsv(filename: string, line, col: int, 
+                      msg: string) {.noreturn.} =
+  var e: ref EInvalidCsv
+  new(e)
+  e.msg = filename & "(" & $line & ", " & $col & ") Error: " & msg
+  raise e
+
+proc error(my: TCsvParser, pos: int, msg: string) = 
+  raiseEInvalidCsv(my.filename, my.LineNumber, getColNumber(my, pos), msg)
+
+proc open*(my: var TCsvParser, input: PStream, filename: string,
+           separator = ',', quote = '"', escape = '\0',
+           skipInitialSpace = false) =
+  ## initializes the parser with an input stream. `Filename` is only used
+  ## for nice error messages. The parser's behaviour can be controlled by
+  ## the diverse optional parameters:
+  ## - `separator`: character used to separate fields
+  ## - `quote`: Used to quote fields containing special characters like 
+  ##   `separator`, `quote` or new-line characters. '\0' disables the parsing
+  ##   of quotes.
+  ## - `escape`: removes any special meaning from the following character; 
+  ##   '\0' disables escaping; if escaping is disabled and `quote` is not '\0',
+  ##   two `quote` characters are parsed one literal `quote` character.
+  ## - `skipInitialSpace`: If true, whitespace immediately following the 
+  ##   `separator` is ignored.
+  lexbase.open(my, input)
+  my.filename = filename
+  my.sep = separator
+  my.quote = quote
+  my.esc = escape
+  my.skipWhite = skipInitialSpace
+  my.row = @[]
+  my.currRow = 0
+
+proc parseField(my: var TCsvParser, a: var string) = 
+  var pos = my.bufpos
+  var buf = my.buf
+  if my.skipWhite:
+    while buf[pos] in {' ', '\t'}: inc(pos)
+  setLen(a, 0) # reuse memory
+  if buf[pos] == my.quote and my.quote != '\0': 
+    inc(pos)
+    while true: 
+      var c = buf[pos]
+      if c == '\0':
+        my.bufpos = pos # can continue after exception?
+        error(my, pos, my.quote & " expected")
+        break
+      elif c == my.quote: 
+        if my.esc == '\0' and buf[pos+1] == my.quote:
+          add(a, my.quote)
+          inc(pos, 2)
+        else:
+          inc(pos)
+          break
+      elif c == my.esc:
+        add(a, buf[pos+1])
+        inc(pos, 2)
+      else:
+        case c
+        of '\c': 
+          pos = handleCR(my, pos)
+          add(a, "\n")
+        of '\l': 
+          pos = handleLF(my, pos)
+          add(a, "\n")
+        else:
+          add(a, c)
+          inc(pos)
+  else:
+    while true:
+      var c = buf[pos]
+      if c == my.sep: break
+      if c in {'\c', '\l', '\0'}: break
+      add(a, c)
+      inc(pos)
+  my.bufpos = pos
+
+proc processedRows*(my: var TCsvParser): int = 
+  ## returns number of the processed rows
+  return my.currRow
+
+proc readRow*(my: var TCsvParser, columns = 0): bool = 
+  ## reads the next row; if `columns` > 0, it expects the row to have
+  ## exactly this many columns. Returns false if the end of the file
+  ## has been encountered else true.
+  var col = 0 # current column
+  var oldpos = my.bufpos
+  while my.buf[my.bufpos] != '\0':
+    var oldlen = my.row.len
+    if oldlen < col+1:
+      setLen(my.row, col+1)
+      my.row[col] = ""
+    parseField(my, my.row[col])
+    inc(col)
+    if my.buf[my.bufpos] == my.sep: 
+      inc(my.bufpos)
+    else:
+      case my.buf[my.bufpos]
+      of '\c', '\l': 
+        # skip empty lines:
+        while true: 
+          case my.buf[my.bufpos]
+          of '\c': my.bufpos = handleCR(my, my.bufpos)
+          of '\l': my.bufpos = handleLF(my, my.bufpos)
+          else: break
+      of '\0': nil
+      else: error(my, my.bufpos, my.sep & " expected")
+      break
+  
+  setlen(my.row, col)
+  result = col > 0
+  if result and col != columns and columns > 0: 
+    error(my, oldpos+1, $columns & " columns expected, but found " & 
+          $col & " columns")
+  inc(my.currRow)
+  
+proc close*(my: var TCsvParser) {.inline.} = 
+  ## closes the parser `my` and its associated input stream.
+  lexbase.close(my)
+
+when isMainModule:
+  import os
+  var s = newFileStream(ParamStr(1), fmRead)
+  if s == nil: quit("cannot open the file" & ParamStr(1))
+  var x: TCsvParser
+  open(x, s, ParamStr(1))
+  while readRow(x):
+    Echo "new row: "
+    for val in items(x.row):
+      Echo "##", val, "##"
+  close(x)
+
diff --git a/lib/parsexml.nim b/lib/parsexml.nim
index 81b6da1de..78be404d1 100644
--- a/lib/parsexml.nim
+++ b/lib/parsexml.nim
@@ -22,7 +22,7 @@
 ## * Thus the checks would have been very difficult to implement properly with
 ##   little benefit, especially since they are simple to implement in the 
 ##   client. The client should use the `errorMsgExpected` proc to generate
-##   a nice error message that fits to the other error messages this library
+##   a nice error message that fits the other error messages this library
 ##   creates.
 ##
 ##
diff --git a/lib/ptrset.nim b/lib/ptrset.nim
deleted file mode 100644
index 95f01b16f..000000000
--- a/lib/ptrset.nim
+++ /dev/null
@@ -1,205 +0,0 @@
-# This implements a new pointer set. Access time O(1). For 32 bit systems, we
-# currently need 3 memory accesses. 
-
-const
-  PageSize = 1024 * sizeof(int)
-  MemAlignment = 8 # minimal memory block that can be allocated
-  BitsPerUnit = sizeof(int)*8 
-    # a "unit" is a word, i.e. 4 bytes
-    # on a 32 bit system; I do not use the term "word" because under 32-bit
-    # Windows it is sometimes only 16 bits
-
-  BitsPerPage = PageSize div MemAlignment
-  UnitsPerPage = BitsPerPage div BitsPerUnit
-    # how many units do we need to describe a page:
-    # on 32 bit systems this is only 16 (!)
-
-type
-  PPointer = ptr pointer
-
-  TCollectorData = int
-  TCell {.final.} = object
-    refcount: TCollectorData  # the refcount and bit flags
-    typ: PNimType                  
-    stackcount: int           # stack counter for debugging
-    drefc: int                # real reference counter for debugging
-
-  PCell = ptr TCell
-
-proc cellToUsr(cell: PCell): pointer {.inline.} =
-  # convert object (=pointer to refcount) to pointer to userdata
-  result = cast[pointer](cast[TAddress](cell)+%TAddress(sizeof(TCell)))
-
-proc usrToCell(usr: pointer): PCell {.inline.} =
-  # convert pointer to userdata to object (=pointer to refcount)
-  result = cast[PCell](cast[TAddress](usr)-%TAddress(sizeof(TCell)))
-
-proc gcAlloc(size: int): pointer =
-  result = alloc0(size)
-  if result == nil: raiseOutOfMem() 
-
-# ------------------ Zero count table (ZCT) and any table (AT) -------------
-
-# this that has to equals zero, otherwise we have to round up UnitsPerPage:
-when BitsPerPage mod BitsPerUnit != 0:
-  {.error: "(BitsPerPage mod BitsPerUnit) should be zero!".}
-
-# ------------------- cell set handling ------------------------------
-# A cellset consists of a hash table of page descriptors. A page
-# descriptor has a bit for
-# every Memalignment'th byte in the page.
-# However, only bits corresponding to addresses that start memory blocks
-# are set.
-# Page descriptors are also linked to a list; the list
-# is used for easy traversing of all page descriptors; this allows a
-# fast iterator.
-# We use a specialized hashing scheme; the formula is :
-# hash = Page bitand max
-# We use linear probing with the formular: (5*h)+1
-# Thus we likely get no collisions at all if the pages are given to us
-# in a sequential manner by the operating system!
-const
-  bitsPerNode = 10 # we use 10 bits per node; this means 3 memory accesses on
-                   # 32 bit systems
-
-type
-  PPageDesc = ptr TPageDesc
-
-  TBitIndex = range[0..UnitsPerPage-1]
-
-  TPageDesc {.final.} = object
-    next: PPageDesc # all nodes are connected with this pointer
-    key: TAddress   # start address at bit 0
-    bits: array[TBitIndex, int] # a bit vector
-
-  PPageDescArray = ptr array[0..1000_000, PPageDesc]
-  TCellSet {.final.} = object
-    counter, max: int
-    head: PPageDesc
-    data: PPageDescArray
-    
-  TSetNode {.final.} = object
-    n: array[0.. (1 shl bitsPerNode)-1, PSetNode]
-  PSetNode = ptr TSetNode
-
-const
-  InitCellSetSize = 1024 # must be a power of two!
-
-proc CellSetInit(s: var TCellSet) =
-  s.data = gcAlloc(InitCellSetSize * sizeof(PPageDesc))
-  s.max = InitCellSetSize-1
-  s.counter = 0
-  s.head = nil
-
-proc CellSetDeinit(s: var TCellSet) =
-  var it = s.head
-  while it != nil:
-    var n = it.next
-    dealloc(it)
-    it = n
-  s.head = nil # play it safe here
-  dealloc(s.data)
-  s.data = nil
-  s.counter = 0
-
-proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc =
-  var h = cast[int](key) and t.max
-  while t.data[h] != nil:
-    if t.data[h].key == key: return t.data[h]
-    h = nextTry(h, t.max)
-  return nil
-
-proc CellSetRawInsert(t: TCellSet, data: PPageDescArray,
-                      desc: PPageDesc) =
-  var h = cast[int](desc.key) and t.max
-  while data[h] != nil:
-    assert(data[h] != desc)
-    h = nextTry(h, t.max)
-  assert(data[h] == nil)
-  data[h] = desc
-
-proc CellSetEnlarge(t: var TCellSet) =
-  var
-    n: PPageDescArray
-    oldMax = t.max
-  t.max = ((t.max+1)*2)-1
-  n = gcAlloc((t.max + 1) * sizeof(PPageDesc))
-  for i in 0 .. oldmax:
-    if t.data[i] != nil:
-      CellSetRawInsert(t, n, t.data[i])
-  dealloc(t.data)
-  t.data = n
-
-proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
-  var h = cast[int](key) and t.max
-  while true:
-    var x = t.data[h]
-    if x == nil: break
-    if x.key == key: return x
-    h = nextTry(h, t.max)
-
-  if (t.max+1) * 2 < t.counter * 3: CellSetEnlarge(t)
-  inc(t.counter)
-  h = cast[int](key) and t.max
-  while t.data[h] != nil: h = nextTry(h, t.max)
-  assert(t.data[h] == nil)
-  # the new page descriptor goes into result
-  result = gcAlloc(sizeof(TPageDesc))
-  result.next = t.head
-  result.key = key
-  t.head = result
-  t.data[h] = result
-
-# ---------- slightly higher level procs ----------------------------------
-
-proc in_Operator(s: TCellSet, cell: PCell): bool =
-  var
-    u: TAddress
-    t: PPageDesc
-  u = cast[TAddress](cell)
-  t = CellSetGet(s, u /% PageSize)
-  if t != nil:
-    u = (u %% PageSize) /% MemAlignment
-    result = (t.bits[u /% BitsPerUnit] and (1 shl (u %% BitsPerUnit))) != 0
-  else:
-    result = false
-
-proc incl(s: var TCellSet, cell: PCell) =
-  var
-    u: TAddress
-    t: PPageDesc
-  u = cast[TAddress](cell)
-  t = CellSetPut(s, u /% PageSize)
-  u = (u %% PageSize) /% MemAlignment
-  t.bits[u /% BitsPerUnit] = t.bits[u /% BitsPerUnit] or 
-    (1 shl (u %% BitsPerUnit))
-
-proc excl(s: var TCellSet, cell: PCell) =
-  var
-    u: TAddress
-    t: PPageDesc
-  u = cast[TAddress](cell)
-  t = CellSetGet(s, u /% PageSize)
-  if t != nil:
-    u = (u %% PageSize) /% MemAlignment
-    t.bits[u %% BitsPerUnit] = (t.bits[u /% BitsPerUnit] and
-                                  not (1 shl (u %% BitsPerUnit)))
-
-iterator elements(t: TCellSet): PCell {.inline.} =
-  # while traversing it is forbidden to add pointers to the tree!
-  var r = t.head
-  while r != nil:
-    var i = 0
-    while i <= high(r.bits):
-      var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
-      # modifying operations are not allowed during traversation
-      var j = 0
-      while w != 0:         # test all remaining bits for zero
-        if (w and 1) != 0:  # the bit is set!
-          yield cast[PCell]((r.key *% PageSize) +%
-                              (i*%BitsPerUnit+%j) *% MemAlignment)
-        inc(j)
-        w = w shr 1
-      inc(i)
-    r = r.next
-
diff --git a/lib/repr.nim b/lib/repr.nim
index 35c5f9f42..765d66be0 100644
--- a/lib/repr.nim
+++ b/lib/repr.nim
@@ -104,7 +104,7 @@ proc reprSet(p: pointer, typ: PNimType): string {.compilerproc.} =
 type
   TReprClosure {.final.} = object # we cannot use a global variable here
                                   # as this wouldn't be thread-safe
-    marked: TCellSeq
+    marked: TCellSet
     recdepth: int       # do not recurse endless
     indent: int         # indentation
 
@@ -171,14 +171,14 @@ proc reprRecord(result: var string, p: pointer, typ: PNimType,
 proc reprRef(result: var string, p: pointer, typ: PNimType,
              cl: var TReprClosure) =
   # we know that p is not nil here:
-  when defined(boehmGC):
+  when defined(boehmGC) or defined(nogc):
     var cell = cast[PCell](p)
   else:
     var cell = usrToCell(p)
   add result, "ref " & reprPointer(p)
   if cell notin cl.marked:
     # only the address is shown:
-    add(cl.marked, cell)
+    incl(cl.marked, cell)
     add result, " --> "
     reprAux(result, p, typ.base, cl)
 
diff --git a/lib/strutils.nim b/lib/strutils.nim
index e3a412053..075e6b252 100644
--- a/lib/strutils.nim
+++ b/lib/strutils.nim
@@ -865,6 +865,15 @@ proc validEmailAddress*(s: string): bool =
      "aero", "jobs", "museum": return true
   return false
   
+proc validIdentifier*(s: string): bool = 
+  ## returns true if `s` is a valid identifier. A valid identifier starts
+  ## with a character of the set `IdentStartChars` and is followed by any
+  ## number of characters of the set `IdentChars`.
+  if s[0] in IdentStartChars:
+    for i in 1..s.len-1:
+      if s[i] notin IdentChars: return false
+    return true
+  
 proc editDistance*(a, b: string): int =
   ## returns the edit distance between `a` and `b`. This uses the Levenshtein
   ## distance algorithm with only a linear memory overhead. This implementation
diff --git a/lib/sysio.nim b/lib/sysio.nim
index d79b5e287..bd52ef5ea 100644
--- a/lib/sysio.nim
+++ b/lib/sysio.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -54,7 +54,12 @@ proc readLine(f: TFile): string =
   rawReadLine(f, result)
 
 proc write(f: TFile, s: string) = fputs(s, f)
-proc write(f: TFile, i: int) = fprintf(f, "%ld", i)
+proc write(f: TFile, i: int) = 
+  when sizeof(int) == 8:
+    fprintf(f, "%lld", i)
+  else:
+    fprintf(f, "%ld", i)
+    
 proc write(f: TFile, b: bool) =
   if b: write(f, "true")
   else: write(f, "false")
diff --git a/lib/sysstr.nim b/lib/sysstr.nim
index ea46fa503..783bce6af 100644
--- a/lib/sysstr.nim
+++ b/lib/sysstr.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2006 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -37,27 +37,20 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
 proc rawNewString(space: int): NimString {.compilerProc.} =
   var s = space
   if s < 8: s = 7
-  when defined(boehmGC):
-    result = cast[NimString](boehmAllocAtomic(
-      sizeof(TGenericSeq) + (s+1) * sizeof(char)))
-    result.len = 0
-    result.data[0] = '\0'
-  else:
-    result = cast[NimString](newObj(addr(strDesc), sizeof(TGenericSeq) +
-                            (s+1) * sizeof(char)))
+  result = cast[NimString](newObj(addr(strDesc), sizeof(TGenericSeq) +
+                           (s+1) * sizeof(char)))
   result.space = s
 
 proc mnewString(len: int): NimString {.exportc.} =
+  #c_fprintf(c_stdout, "[NEWSTRING] len: %ld\n", len)
   result = rawNewString(len)
   result.len = len
-  when defined(boehmGC):
-    result.data[len] = '\0'
 
 proc toNimStr(str: CString, len: int): NimString {.compilerProc.} =
   result = rawNewString(len)
   result.len = len
   c_memcpy(result.data, str, (len+1) * sizeof(Char))
-  result.data[len] = '\0' # IO.readline relies on this!
+  result.data[len] = '\0' # readline relies on this!
 
 proc cstrToNimstr(str: CString): NimString {.compilerProc.} =
   return toNimstr(str, c_strlen(str))
@@ -184,9 +177,9 @@ proc setLengthStr(s: NimString, newLen: int): NimString {.compilerProc.} =
 
 proc incrSeq(seq: PGenericSeq, elemSize: int): PGenericSeq {.compilerProc.} =
   # increments the length by one:
-  # this is needed for supporting the &= operator;
+  # this is needed for supporting ``add``;
   #
-  #  add seq x  generates:
+  #  add(seq, x)  generates:
   #  seq = incrSeq(seq, sizeof(x));
   #  seq[seq->len-1] = x;
   when false:
@@ -229,7 +222,7 @@ proc setLengthSeq(seq: PGenericSeq, elemSize, newLen: int): PGenericSeq {.
                                  GenericSeqSize))
     elif newLen < result.len:
       # we need to decref here, otherwise the GC leaks!
-      when not defined(boehmGC):
+      when not defined(boehmGC) and not defined(nogc):
         for i in newLen..result.len-1:
           forAllChildrenAux(cast[pointer](cast[TAddress](result) +% 
                             GenericSeqSize +% (i*%elemSize)),
diff --git a/lib/system.nim b/lib/system.nim
index 67a4221f1..23dbfc816 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nimrod's Runtime Library
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -415,11 +415,11 @@ proc `<=` *(x, y: int32): bool {.magic: "LeI", noSideEffect.}
 proc `<=` *(x, y: int64): bool {.magic: "LeI64", noSideEffect.}
   ## Returns true iff `x` is less than or equal to `y`.
 
-proc `<`  *(x, y: int): bool {.magic: "LtI", noSideEffect.}
-proc `<`  *(x, y: int8): bool {.magic: "LtI", noSideEffect.}
-proc `<`  *(x, y: int16): bool {.magic: "LtI", noSideEffect.}
-proc `<`  *(x, y: int32): bool {.magic: "LtI", noSideEffect.}
-proc `<`  *(x, y: int64): bool {.magic: "LtI64", noSideEffect.}
+proc `<` *(x, y: int): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int8): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int16): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int32): bool {.magic: "LtI", noSideEffect.}
+proc `<` *(x, y: int64): bool {.magic: "LtI64", noSideEffect.}
   ## Returns true iff `x` is less than `y`.
 
 proc abs*(x: int): int {.magic: "AbsI", noSideEffect.}
@@ -790,9 +790,10 @@ proc addQuitProc*(QuitProc: proc {.noconv.}) {.importc: "atexit", nodecl.}
 # In case of an unhandled exeption the exit handlers should
 # not be called explicitly! The user may decide to do this manually though.
 
-proc copy*(s: string, first = 0): string {.importc: "copyStr", noSideEffect.}
-proc copy*(s: string, first, last: int): string {.importc: "copyStrLast",
-                                                  noSideEffect.}
+proc copy*(s: string, first = 0): string {.
+  magic: "CopyStr", importc: "copyStr", noSideEffect.}
+proc copy*(s: string, first, last: int): string {.
+  magic: "CopyStrLast", importc: "copyStrLast", noSideEffect.}
   ## copies a slice of `s` into a new string and returns this new
   ## string. The bounds `first` and `last` denote the indices of
   ## the first and last characters that shall be copied. If ``last``
@@ -803,7 +804,8 @@ proc setLen*(s: var string, newlen: int) {.magic: "SetLengthStr".}
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated.
 
-proc newString*(len: int): string {.importc: "mnewString", noSideEffect.}
+proc newString*(len: int): string {.
+  magic: "NewString", importc: "mnewString", noSideEffect.}
   ## returns a new string of length ``len`` but with uninitialized
   ## content. One needs to fill the string character after character
   ## with the index operator ``s[i]``. This procedure exists only for
@@ -835,30 +837,23 @@ proc equalMem*(a, b: Pointer, size: int): bool {.
   ## otherwise. Like any procedure dealing with raw memory this is
   ## *unsafe*.
 
-const
-  mallocHeader = "<stdlib.h>"
-
-proc alloc*(size: int): pointer {.
-  importc: "malloc", header: mallocHeader, noconv.}
+proc alloc*(size: int): pointer {.noconv.}
   ## allocates a new memory block with at least ``size`` bytes. The
   ## block has to be freed with ``realloc(block, 0)`` or
   ## ``dealloc(block)``. The block is not initialized, so reading
   ## from it before writing to it is undefined behaviour!
-proc alloc0*(size: int): pointer {.
-  importc: "ALLOC_0", header: mallocHeader, noconv.}
+proc alloc0*(size: int): pointer {.noconv.}
   ## allocates a new memory block with at least ``size`` bytes. The
   ## block has to be freed with ``realloc(block, 0)`` or
   ## ``dealloc(block)``. The block is initialized with all bytes
   ## containing zero, so it is somewhat safer than ``alloc``.
-proc realloc*(p: Pointer, newsize: int): pointer {.
-  importc: "realloc", header: mallocHeader, noconv.}
+proc realloc*(p: Pointer, newsize: int): pointer {.noconv.}
   ## grows or shrinks a given memory block. If p is **nil** then a new
   ## memory block is returned. In either way the block has at least
   ## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
   ## ``realloc`` calls ``dealloc(p)``. In other cases the block has to
   ## be freed with ``dealloc``.
-proc dealloc*(p: Pointer) {.
-  importc: "free", header: mallocHeader, noconv.}
+proc dealloc*(p: Pointer) {.noconv.}
   ## frees the memory allocated with ``alloc``, ``alloc0`` or
   ## ``realloc``. This procedure is dangerous! If one forgets to
   ## free the memory a leak occurs; if one tries to access freed
@@ -1436,66 +1431,7 @@ when not defined(EcmaScript) and not defined(NimrodVM):
     else:
       result = n.sons[n.len]
 
-  when defined(boehmgc):
-    const
-      boehmLib = "/opt/lib/libgc.so"
-  
-    proc boehmGC_disable {.importc: "GC_disable", dynlib: boehmLib.} 
-    proc boehmGC_enable {.importc: "GC_enable", dynlib: boehmLib.} 
-    proc boehmGCincremental {.
-      importc: "GC_enable_incremental", dynlib: boehmLib.} 
-    proc boehmGCfullCollect {.importc: "GC_gcollect", dynlib: boehmLib.}  
-    proc boehmAlloc(size: int): pointer {.
-      importc: "GC_malloc", dynlib: boehmLib.}
-    proc boehmAllocAtomic(size: int): pointer {.
-      importc: "GC_malloc_atomic", dynlib: boehmLib.}
-    proc boehmRealloc(p: pointer, size: int): pointer {.
-      importc: "GC_realloc", dynlib: boehmLib.}
-    proc boehmDealloc(p: pointer) {.importc: "GC_free", dynlib: boehmLib.}
-      
-  include cellsets
-  
-  when defined(boehmGC):
-    proc initGC() = nil
-    
-    #boehmGCincremental()
-
-    proc GC_disable() = boehmGC_disable()
-    proc GC_enable() = boehmGC_enable()
-    proc GC_fullCollect() = boehmGCfullCollect()
-    proc GC_setStrategy(strategy: TGC_Strategy) = nil
-    proc GC_enableMarkAndSweep() = nil
-    proc GC_disableMarkAndSweep() = nil
-    proc GC_getStatistics(): string = return ""
-    
-    proc getOccupiedMem(): int = return -1
-    proc getFreeMem(): int = return -1
-    proc getTotalMem(): int = return -1
-      
-    proc growObj(old: pointer, newsize: int): pointer {.inline.} = 
-      result = boehmRealloc(old, newsize)
-    proc newObj(size: int): pointer {.compilerproc.} =
-      result = boehmAlloc(size)      
-    proc newSeq(baseSize, len: int): pointer {.compilerproc.} =
-      # XXX: overflow checks!
-      result = newObj(len * baseSize + GenericSeqSize)
-      cast[PGenericSeq](result).len = len
-      cast[PGenericSeq](result).space = len
-
-    proc setStackBottom(theStackBottom: pointer) {.compilerproc.} = nil
-    proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
-    proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
-    
-    proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
-      dest^ = src
-    proc asgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
-      dest^ = src
-    proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerproc, inline.} =
-      dest^ = src
-
-  elif not defined(nogc):
-    include gc
-
+  include mm
   include sysstr
   include assign
   include repr
diff --git a/lib/windows/windows.nim b/lib/windows/windows.nim
index ea650e80a..1865f3369 100644
--- a/lib/windows/windows.nim
+++ b/lib/windows/windows.nim
@@ -3879,7 +3879,7 @@ const
   SW_SHOWNORMAL* = 1
   WPF_RESTORETOMAXIMIZED* = 2
   WPF_SETMINPOSITION* = 1     # Sleep
-  INFINITE* = 0xFFFFFFFF      # SystemParametersInfo
+  INFINITE* = -1'i32      # SystemParametersInfo
   SPI_GETBEEP* = 1
   SPI_SETBEEP* = 2
   SPI_GETMOUSE* = 3
diff --git a/lib/winlean.nim b/lib/winlean.nim
new file mode 100644
index 000000000..747ce7db5
--- /dev/null
+++ b/lib/winlean.nim
@@ -0,0 +1,108 @@
+#

+#

+#            Nimrod's Runtime Library

+#        (c) Copyright 2009 Andreas Rumpf

+#

+#    See the file "copying.txt", included in this

+#    distribution, for details about the copyright.

+#

+

+## This module implements a small wrapper for some needed Win API procedures,

+## so that the Nimrod compiler does not depend on the huge Windows module.

+

+type

+  THandle* = int

+  WINBOOL* = int32

+

+  TSECURITY_ATTRIBUTES* {.final, pure.} = object

+    nLength*: int32

+    lpSecurityDescriptor*: pointer

+    bInheritHandle*: WINBOOL

+  

+  TSTARTUPINFO* {.final, pure.} = object

+    cb*: int32

+    lpReserved*: cstring

+    lpDesktop*: cstring

+    lpTitle*: cstring

+    dwX*: int32

+    dwY*: int32

+    dwXSize*: int32

+    dwYSize*: int32

+    dwXCountChars*: int32

+    dwYCountChars*: int32

+    dwFillAttribute*: int32

+    dwFlags*: int32

+    wShowWindow*: int16

+    cbReserved2*: int16

+    lpReserved2*: pointer

+    hStdInput*: THANDLE

+    hStdOutput*: THANDLE

+    hStdError*: THANDLE

+

+  TPROCESS_INFORMATION* {.final, pure.} = object

+    hProcess*: THANDLE

+    hThread*: THANDLE

+    dwProcessId*: int32

+    dwThreadId*: int32

+

+const

+  STARTF_USESHOWWINDOW* = 1'i32

+  STARTF_USESTDHANDLES* = 256'i32

+  HIGH_PRIORITY_CLASS* = 128'i32

+  IDLE_PRIORITY_CLASS* = 64'i32

+  NORMAL_PRIORITY_CLASS* = 32'i32

+  REALTIME_PRIORITY_CLASS* = 256'i32

+  WAIT_TIMEOUT* = 0x00000102'i32

+  INFINITE* = -1'i32

+

+  STD_INPUT_HANDLE* = -10'i32

+  STD_OUTPUT_HANDLE* = -11'i32

+  STD_ERROR_HANDLE* = -12'i32

+

+proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",

+    importc: "CloseHandle".}

+    

+proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,

+               lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "ReadFile".}

+    

+proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,

+                lpNumberOfBytesWritten: var int32, 

+                lpOverlapped: pointer): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "WriteFile".}

+

+proc CreatePipe*(hReadPipe, hWritePipe: var THandle,

+                 lpPipeAttributes: var TSECURITY_ATTRIBUTES, 

+                 nSize: int32): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreatePipe".}

+    

+proc CreateProcess*(lpApplicationName, lpCommandLine: cstring,

+                    lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,

+                    lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,

+                    bInheritHandles: WINBOOL, dwCreationFlags: int32,

+                    lpEnvironment: pointer, lpCurrentDirectory: cstring,

+                    lpStartupInfo: var TSTARTUPINFO,

+                    lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.

+    stdcall, dynlib: "kernel32", importc: "CreateProcessA".}

+

+proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",

+    importc: "SuspendThread".}

+proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",

+    importc: "ResumeThread".}

+

+proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {.

+    stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}

+

+proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall,

+    dynlib: "kernel32", importc: "TerminateProcess".}

+

+proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {.

+    stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}

+

+proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32",

+    importc: "GetStdHandle".}

+proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall,

+    dynlib: "kernel32", importc: "SetStdHandle".}

+proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",

+    importc: "FlushFileBuffers".}

+

diff --git a/lib/wz_jsgraphics.js b/lib/wz_jsgraphics.js
deleted file mode 100644
index f4ba47b53..000000000
--- a/lib/wz_jsgraphics.js
+++ /dev/null
@@ -1,1107 +0,0 @@
-/* This notice must be untouched at all times.

-

-wz_jsgraphics.js    v. 3.03

-The latest version is available at

-http://www.walterzorn.com

-or http://www.devira.com

-or http://www.walterzorn.de

-

-Copyright (c) 2002-2004 Walter Zorn. All rights reserved.

-Created 3. 11. 2002 by Walter Zorn (Web: http://www.walterzorn.com )

-Last modified: 28. 1. 2008

-

-Performance optimizations for Internet Explorer

-by Thomas Frank and John Holdsworth.

-fillPolygon method implemented by Matthieu Haller.

-

-High Performance JavaScript Graphics Library.

-Provides methods

-- to draw lines, rectangles, ellipses, polygons

-  with specifiable line thickness,

-- to fill rectangles, polygons, ellipses and arcs

-- to draw text.

-NOTE: Operations, functions and branching have rather been optimized

-to efficiency and speed than to shortness of source code.

-

-LICENSE: LGPL

-

-This library is free software; you can redistribute it and/or

-modify it under the terms of the GNU Lesser General Public

-License (LGPL) as published by the Free Software Foundation; either

-version 2.1 of the License, or (at your option) any later version.

-

-This library is distributed in the hope that it will be useful,

-but WITHOUT ANY WARRANTY; without even the implied warranty of

-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

-Lesser General Public License for more details.

-

-You should have received a copy of the GNU Lesser General Public

-License along with this library; if not, write to the Free Software

-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA,

-or see http://www.gnu.org/copyleft/lesser.html

-*/

-

-

-var jg_ok, jg_ie, jg_fast, jg_dom, jg_moz;

-

-

-function _chkDHTM(x, i)

-{

-  x = document.body || null;

-  jg_ie = x && typeof x.insertAdjacentHTML != "undefined" && document.createElement;

-  jg_dom = (x && !jg_ie &&

-    typeof x.appendChild != "undefined" &&

-    typeof document.createRange != "undefined" &&

-    typeof (i = document.createRange()).setStartBefore != "undefined" &&

-    typeof i.createContextualFragment != "undefined");

-  jg_fast = jg_ie && document.all && !window.opera;

-  jg_moz = jg_dom && typeof x.style.MozOpacity != "undefined";

-  jg_ok = !!(jg_ie || jg_dom);

-}

-

-function _pntCnvDom()

-{

-  var x = this.wnd.document.createRange();

-  x.setStartBefore(this.cnv);

-  x = x.createContextualFragment(jg_fast? this._htmRpc() : this.htm);

-  if(this.cnv) this.cnv.appendChild(x);

-  this.htm = "";

-}

-

-function _pntCnvIe()

-{

-  if(this.cnv) this.cnv.insertAdjacentHTML("BeforeEnd", jg_fast? this._htmRpc() : this.htm);

-  this.htm = "";

-}

-

-function _pntDoc()

-{

-  this.wnd.document.write(jg_fast? this._htmRpc() : this.htm);

-  this.htm = '';

-}

-

-function _pntN()

-{

-  ;

-}

-

-function _mkDiv(x, y, w, h)

-{

-  this.htm += '<div style="position:absolute;'+

-    'left:' + x + 'px;'+

-    'top:' + y + 'px;'+

-    'width:' + w + 'px;'+

-    'height:' + h + 'px;'+

-    'clip:rect(0,'+w+'px,'+h+'px,0);'+

-    'background-color:' + this.color +

-    (!jg_moz? ';overflow:hidden' : '')+

-    ';"><\/div>';

-}

-

-function _mkDivIe(x, y, w, h)

-{

-  this.htm += '%%'+this.color+';'+x+';'+y+';'+w+';'+h+';';

-}

-

-function _mkDivPrt(x, y, w, h)

-{

-  this.htm += '<div style="position:absolute;'+

-    'border-left:' + w + 'px solid ' + this.color + ';'+

-    'left:' + x + 'px;'+

-    'top:' + y + 'px;'+

-    'width:0px;'+

-    'height:' + h + 'px;'+

-    'clip:rect(0,'+w+'px,'+h+'px,0);'+

-    'background-color:' + this.color +

-    (!jg_moz? ';overflow:hidden' : '')+

-    ';"><\/div>';

-}

-

-var _regex =  /%%([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);/g;

-function _htmRpc()

-{

-  return this.htm.replace(

-    _regex,

-    '<div style="overflow:hidden;position:absolute;background-color:'+

-    '$1;left:$2;top:$3;width:$4;height:$5"></div>\n');

-}

-

-function _htmPrtRpc()

-{

-  return this.htm.replace(

-    _regex,

-    '<div style="overflow:hidden;position:absolute;background-color:'+

-    '$1;left:$2;top:$3;width:$4;height:$5;border-left:$4px solid $1"></div>\n');

-}

-

-function _mkLin(x1, y1, x2, y2)

-{

-  if(x1 > x2)

-  {

-    var _x2 = x2;

-    var _y2 = y2;

-    x2 = x1;

-    y2 = y1;

-    x1 = _x2;

-    y1 = _y2;

-  }

-  var dx = x2-x1, dy = Math.abs(y2-y1),

-  x = x1, y = y1,

-  yIncr = (y1 > y2)? -1 : 1;

-

-  if(dx >= dy)

-  {

-    var pr = dy<<1,

-    pru = pr - (dx<<1),

-    p = pr-dx,

-    ox = x;

-    while(dx > 0)

-    {--dx;

-      ++x;

-      if(p > 0)

-      {

-        this._mkDiv(ox, y, x-ox, 1);

-        y += yIncr;

-        p += pru;

-        ox = x;

-      }

-      else p += pr;

-    }

-    this._mkDiv(ox, y, x2-ox+1, 1);

-  }

-

-  else

-  {

-    var pr = dx<<1,

-    pru = pr - (dy<<1),

-    p = pr-dy,

-    oy = y;

-    if(y2 <= y1)

-    {

-      while(dy > 0)

-      {--dy;

-        if(p > 0)

-        {

-          this._mkDiv(x++, y, 1, oy-y+1);

-          y += yIncr;

-          p += pru;

-          oy = y;

-        }

-        else

-        {

-          y += yIncr;

-          p += pr;

-        }

-      }

-      this._mkDiv(x2, y2, 1, oy-y2+1);

-    }

-    else

-    {

-      while(dy > 0)

-      {--dy;

-        y += yIncr;

-        if(p > 0)

-        {

-          this._mkDiv(x++, oy, 1, y-oy);

-          p += pru;

-          oy = y;

-        }

-        else p += pr;

-      }

-      this._mkDiv(x2, oy, 1, y2-oy+1);

-    }

-  }

-}

-

-function _mkLin2D(x1, y1, x2, y2)

-{

-  if(x1 > x2)

-  {

-    var _x2 = x2;

-    var _y2 = y2;

-    x2 = x1;

-    y2 = y1;

-    x1 = _x2;

-    y1 = _y2;

-  }

-  var dx = x2-x1, dy = Math.abs(y2-y1),

-  x = x1, y = y1,

-  yIncr = (y1 > y2)? -1 : 1;

-

-  var s = this.stroke;

-  if(dx >= dy)

-  {

-    if(dx > 0 && s-3 > 0)

-    {

-      var _s = (s*dx*Math.sqrt(1+dy*dy/(dx*dx))-dx-(s>>1)*dy) / dx;

-      _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;

-    }

-    else var _s = s;

-    var ad = Math.ceil(s/2);

-

-    var pr = dy<<1,

-    pru = pr - (dx<<1),

-    p = pr-dx,

-    ox = x;

-    while(dx > 0)

-    {--dx;

-      ++x;

-      if(p > 0)

-      {

-        this._mkDiv(ox, y, x-ox+ad, _s);

-        y += yIncr;

-        p += pru;

-        ox = x;

-      }

-      else p += pr;

-    }

-    this._mkDiv(ox, y, x2-ox+ad+1, _s);

-  }

-

-  else

-  {

-    if(s-3 > 0)

-    {

-      var _s = (s*dy*Math.sqrt(1+dx*dx/(dy*dy))-(s>>1)*dx-dy) / dy;

-      _s = (!(s-4)? Math.ceil(_s) : Math.round(_s)) + 1;

-    }

-    else var _s = s;

-    var ad = Math.round(s/2);

-

-    var pr = dx<<1,

-    pru = pr - (dy<<1),

-    p = pr-dy,

-    oy = y;

-    if(y2 <= y1)

-    {

-      ++ad;

-      while(dy > 0)

-      {--dy;

-        if(p > 0)

-        {

-          this._mkDiv(x++, y, _s, oy-y+ad);

-          y += yIncr;

-          p += pru;

-          oy = y;

-        }

-        else

-        {

-          y += yIncr;

-          p += pr;

-        }

-      }

-      this._mkDiv(x2, y2, _s, oy-y2+ad);

-    }

-    else

-    {

-      while(dy > 0)

-      {--dy;

-        y += yIncr;

-        if(p > 0)

-        {

-          this._mkDiv(x++, oy, _s, y-oy+ad);

-          p += pru;

-          oy = y;

-        }

-        else p += pr;

-      }

-      this._mkDiv(x2, oy, _s, y2-oy+ad+1);

-    }

-  }

-}

-

-function _mkLinDott(x1, y1, x2, y2)

-{

-  if(x1 > x2)

-  {

-    var _x2 = x2;

-    var _y2 = y2;

-    x2 = x1;

-    y2 = y1;

-    x1 = _x2;

-    y1 = _y2;

-  }

-  var dx = x2-x1, dy = Math.abs(y2-y1),

-  x = x1, y = y1,

-  yIncr = (y1 > y2)? -1 : 1,

-  drw = true;

-  if(dx >= dy)

-  {

-    var pr = dy<<1,

-    pru = pr - (dx<<1),

-    p = pr-dx;

-    while(dx > 0)

-    {--dx;

-      if(drw) this._mkDiv(x, y, 1, 1);

-      drw = !drw;

-      if(p > 0)

-      {

-        y += yIncr;

-        p += pru;

-      }

-      else p += pr;

-      ++x;

-    }

-  }

-  else

-  {

-    var pr = dx<<1,

-    pru = pr - (dy<<1),

-    p = pr-dy;

-    while(dy > 0)

-    {--dy;

-      if(drw) this._mkDiv(x, y, 1, 1);

-      drw = !drw;

-      y += yIncr;

-      if(p > 0)

-      {

-        ++x;

-        p += pru;

-      }

-      else p += pr;

-    }

-  }

-  if(drw) this._mkDiv(x, y, 1, 1);

-}

-

-function _mkOv(left, top, width, height)

-{

-  var a = (++width)>>1, b = (++height)>>1,

-  wod = width&1, hod = height&1,

-  cx = left+a, cy = top+b,

-  x = 0, y = b,

-  ox = 0, oy = b,

-  aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

-  st = (aa2>>1)*(1-(b<<1)) + bb2,

-  tt = (bb2>>1) - aa2*((b<<1)-1),

-  w, h;

-  while(y > 0)

-  {

-    if(st < 0)

-    {

-      st += bb2*((x<<1)+3);

-      tt += bb4*(++x);

-    }

-    else if(tt < 0)

-    {

-      st += bb2*((x<<1)+3) - aa4*(y-1);

-      tt += bb4*(++x) - aa2*(((y--)<<1)-3);

-      w = x-ox;

-      h = oy-y;

-      if((w&2) && (h&2))

-      {

-        this._mkOvQds(cx, cy, x-2, y+2, 1, 1, wod, hod);

-        this._mkOvQds(cx, cy, x-1, y+1, 1, 1, wod, hod);

-      }

-      else this._mkOvQds(cx, cy, x-1, oy, w, h, wod, hod);

-      ox = x;

-      oy = y;

-    }

-    else

-    {

-      tt -= aa2*((y<<1)-3);

-      st -= aa4*(--y);

-    }

-  }

-  w = a-ox+1;

-  h = (oy<<1)+hod;

-  y = cy-oy;

-  this._mkDiv(cx-a, y, w, h);

-  this._mkDiv(cx+ox+wod-1, y, w, h);

-}

-

-function _mkOv2D(left, top, width, height)

-{

-  var s = this.stroke;

-  width += s+1;

-  height += s+1;

-  var a = width>>1, b = height>>1,

-  wod = width&1, hod = height&1,

-  cx = left+a, cy = top+b,

-  x = 0, y = b,

-  aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

-  st = (aa2>>1)*(1-(b<<1)) + bb2,

-  tt = (bb2>>1) - aa2*((b<<1)-1);

-

-  if(s-4 < 0 && (!(s-2) || width-51 > 0 && height-51 > 0))

-  {

-    var ox = 0, oy = b,

-    w, h,

-    pxw;

-    while(y > 0)

-    {

-      if(st < 0)

-      {

-        st += bb2*((x<<1)+3);

-        tt += bb4*(++x);

-      }

-      else if(tt < 0)

-      {

-        st += bb2*((x<<1)+3) - aa4*(y-1);

-        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

-        w = x-ox;

-        h = oy-y;

-

-        if(w-1)

-        {

-          pxw = w+1+(s&1);

-          h = s;

-        }

-        else if(h-1)

-        {

-          pxw = s;

-          h += 1+(s&1);

-        }

-        else pxw = h = s;

-        this._mkOvQds(cx, cy, x-1, oy, pxw, h, wod, hod);

-        ox = x;

-        oy = y;

-      }

-      else

-      {

-        tt -= aa2*((y<<1)-3);

-        st -= aa4*(--y);

-      }

-    }

-    this._mkDiv(cx-a, cy-oy, s, (oy<<1)+hod);

-    this._mkDiv(cx+a+wod-s, cy-oy, s, (oy<<1)+hod);

-  }

-

-  else

-  {

-    var _a = (width-(s<<1))>>1,

-    _b = (height-(s<<1))>>1,

-    _x = 0, _y = _b,

-    _aa2 = (_a*_a)<<1, _aa4 = _aa2<<1, _bb2 = (_b*_b)<<1, _bb4 = _bb2<<1,

-    _st = (_aa2>>1)*(1-(_b<<1)) + _bb2,

-    _tt = (_bb2>>1) - _aa2*((_b<<1)-1),

-

-    pxl = new Array(),

-    pxt = new Array(),

-    _pxb = new Array();

-    pxl[0] = 0;

-    pxt[0] = b;

-    _pxb[0] = _b-1;

-    while(y > 0)

-    {

-      if(st < 0)

-      {

-        pxl[pxl.length] = x;

-        pxt[pxt.length] = y;

-        st += bb2*((x<<1)+3);

-        tt += bb4*(++x);

-      }

-      else if(tt < 0)

-      {

-        pxl[pxl.length] = x;

-        st += bb2*((x<<1)+3) - aa4*(y-1);

-        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

-        pxt[pxt.length] = y;

-      }

-      else

-      {

-        tt -= aa2*((y<<1)-3);

-        st -= aa4*(--y);

-      }

-

-      if(_y > 0)

-      {

-        if(_st < 0)

-        {

-          _st += _bb2*((_x<<1)+3);

-          _tt += _bb4*(++_x);

-          _pxb[_pxb.length] = _y-1;

-        }

-        else if(_tt < 0)

-        {

-          _st += _bb2*((_x<<1)+3) - _aa4*(_y-1);

-          _tt += _bb4*(++_x) - _aa2*(((_y--)<<1)-3);

-          _pxb[_pxb.length] = _y-1;

-        }

-        else

-        {

-          _tt -= _aa2*((_y<<1)-3);

-          _st -= _aa4*(--_y);

-          _pxb[_pxb.length-1]--;

-        }

-      }

-    }

-

-    var ox = -wod, oy = b,

-    _oy = _pxb[0],

-    l = pxl.length,

-    w, h;

-    for(var i = 0; i < l; i++)

-    {

-      if(typeof _pxb[i] != "undefined")

-      {

-        if(_pxb[i] < _oy || pxt[i] < oy)

-        {

-          x = pxl[i];

-          this._mkOvQds(cx, cy, x, oy, x-ox, oy-_oy, wod, hod);

-          ox = x;

-          oy = pxt[i];

-          _oy = _pxb[i];

-        }

-      }

-      else

-      {

-        x = pxl[i];

-        this._mkDiv(cx-x, cy-oy, 1, (oy<<1)+hod);

-        this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);

-        ox = x;

-        oy = pxt[i];

-      }

-    }

-    this._mkDiv(cx-a, cy-oy, 1, (oy<<1)+hod);

-    this._mkDiv(cx+ox+wod, cy-oy, 1, (oy<<1)+hod);

-  }

-}

-

-function _mkOvDott(left, top, width, height)

-{

-  var a = (++width)>>1, b = (++height)>>1,

-  wod = width&1, hod = height&1, hodu = hod^1,

-  cx = left+a, cy = top+b,

-  x = 0, y = b,

-  aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

-  st = (aa2>>1)*(1-(b<<1)) + bb2,

-  tt = (bb2>>1) - aa2*((b<<1)-1),

-  drw = true;

-  while(y > 0)

-  {

-    if(st < 0)

-    {

-      st += bb2*((x<<1)+3);

-      tt += bb4*(++x);

-    }

-    else if(tt < 0)

-    {

-      st += bb2*((x<<1)+3) - aa4*(y-1);

-      tt += bb4*(++x) - aa2*(((y--)<<1)-3);

-    }

-    else

-    {

-      tt -= aa2*((y<<1)-3);

-      st -= aa4*(--y);

-    }

-    if(drw && y >= hodu) this._mkOvQds(cx, cy, x, y, 1, 1, wod, hod);

-    drw = !drw;

-  }

-}

-

-function _mkRect(x, y, w, h)

-{

-  var s = this.stroke;

-  this._mkDiv(x, y, w, s);

-  this._mkDiv(x+w, y, s, h);

-  this._mkDiv(x, y+h, w+s, s);

-  this._mkDiv(x, y+s, s, h-s);

-}

-

-function _mkRectDott(x, y, w, h)

-{

-  this.drawLine(x, y, x+w, y);

-  this.drawLine(x+w, y, x+w, y+h);

-  this.drawLine(x, y+h, x+w, y+h);

-  this.drawLine(x, y, x, y+h);

-}

-

-function jsgFont()

-{

-  this.PLAIN = 'font-weight:normal;';

-  this.BOLD = 'font-weight:bold;';

-  this.ITALIC = 'font-style:italic;';

-  this.ITALIC_BOLD = this.ITALIC + this.BOLD;

-  this.BOLD_ITALIC = this.ITALIC_BOLD;

-}

-var Font = new jsgFont();

-

-function jsgStroke()

-{

-  this.DOTTED = -1;

-}

-var Stroke = new jsgStroke();

-

-function jsGraphics(cnv, wnd)

-{

-  this.setColor = function(x)

-  {

-    this.color = x.toLowerCase();

-  };

-

-  this.setStroke = function(x)

-  {

-    this.stroke = x;

-    if(!(x+1))

-    {

-      this.drawLine = _mkLinDott;

-      this._mkOv = _mkOvDott;

-      this.drawRect = _mkRectDott;

-    }

-    else if(x-1 > 0)

-    {

-      this.drawLine = _mkLin2D;

-      this._mkOv = _mkOv2D;

-      this.drawRect = _mkRect;

-    }

-    else

-    {

-      this.drawLine = _mkLin;

-      this._mkOv = _mkOv;

-      this.drawRect = _mkRect;

-    }

-  };

-

-  this.setPrintable = function(arg)

-  {

-    this.printable = arg;

-    if(jg_fast)

-    {

-      this._mkDiv = _mkDivIe;

-      this._htmRpc = arg? _htmPrtRpc : _htmRpc;

-    }

-    else this._mkDiv = arg? _mkDivPrt : _mkDiv;

-  };

-

-  this.setFont = function(fam, sz, sty)

-  {

-    this.ftFam = fam;

-    this.ftSz = sz;

-    this.ftSty = sty || Font.PLAIN;

-  };

-

-  this.drawPolyline = this.drawPolyLine = function(x, y)

-  {

-    for (var i=x.length - 1; i;)

-    {--i;

-      this.drawLine(x[i], y[i], x[i+1], y[i+1]);

-    }

-  };

-

-  this.fillRect = function(x, y, w, h)

-  {

-    this._mkDiv(x, y, w, h);

-  };

-

-  this.drawPolygon = function(x, y)

-  {

-    this.drawPolyline(x, y);

-    this.drawLine(x[x.length-1], y[x.length-1], x[0], y[0]);

-  };

-

-  this.drawEllipse = this.drawOval = function(x, y, w, h)

-  {

-    this._mkOv(x, y, w, h);

-  };

-

-  this.fillEllipse = this.fillOval = function(left, top, w, h)

-  {

-    var a = w>>1, b = h>>1,

-    wod = w&1, hod = h&1,

-    cx = left+a, cy = top+b,

-    x = 0, y = b, oy = b,

-    aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

-    st = (aa2>>1)*(1-(b<<1)) + bb2,

-    tt = (bb2>>1) - aa2*((b<<1)-1),

-    xl, dw, dh;

-    if(w) while(y > 0)

-    {

-      if(st < 0)

-      {

-        st += bb2*((x<<1)+3);

-        tt += bb4*(++x);

-      }

-      else if(tt < 0)

-      {

-        st += bb2*((x<<1)+3) - aa4*(y-1);

-        xl = cx-x;

-        dw = (x<<1)+wod;

-        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

-        dh = oy-y;

-        this._mkDiv(xl, cy-oy, dw, dh);

-        this._mkDiv(xl, cy+y+hod, dw, dh);

-        oy = y;

-      }

-      else

-      {

-        tt -= aa2*((y<<1)-3);

-        st -= aa4*(--y);

-      }

-    }

-    this._mkDiv(cx-a, cy-oy, w, (oy<<1)+hod);

-  };

-

-  this.fillArc = function(iL, iT, iW, iH, fAngA, fAngZ)

-  {

-    var a = iW>>1, b = iH>>1,

-    iOdds = (iW&1) | ((iH&1) << 16),

-    cx = iL+a, cy = iT+b,

-    x = 0, y = b, ox = x, oy = y,

-    aa2 = (a*a)<<1, aa4 = aa2<<1, bb2 = (b*b)<<1, bb4 = bb2<<1,

-    st = (aa2>>1)*(1-(b<<1)) + bb2,

-    tt = (bb2>>1) - aa2*((b<<1)-1),

-    // Vars for radial boundary lines

-    xEndA, yEndA, xEndZ, yEndZ,

-    iSects = (1 << (Math.floor((fAngA %= 360.0)/180.0) << 3))

-        | (2 << (Math.floor((fAngZ %= 360.0)/180.0) << 3))

-        | ((fAngA >= fAngZ) << 16),

-    aBndA = new Array(b+1), aBndZ = new Array(b+1);

-    

-    // Set up radial boundary lines

-    fAngA *= Math.PI/180.0;

-    fAngZ *= Math.PI/180.0;

-    xEndA = cx+Math.round(a*Math.cos(fAngA));

-    yEndA = cy+Math.round(-b*Math.sin(fAngA));

-    _mkLinVirt(aBndA, cx, cy, xEndA, yEndA);

-    xEndZ = cx+Math.round(a*Math.cos(fAngZ));

-    yEndZ = cy+Math.round(-b*Math.sin(fAngZ));

-    _mkLinVirt(aBndZ, cx, cy, xEndZ, yEndZ);

-

-    while(y > 0)

-    {

-      if(st < 0) // Advance x

-      {

-        st += bb2*((x<<1)+3);

-        tt += bb4*(++x);

-      }

-      else if(tt < 0) // Advance x and y

-      {

-        st += bb2*((x<<1)+3) - aa4*(y-1);

-        ox = x;

-        tt += bb4*(++x) - aa2*(((y--)<<1)-3);

-        this._mkArcDiv(ox, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);

-        oy = y;

-      }

-      else // Advance y

-      {

-        tt -= aa2*((y<<1)-3);

-        st -= aa4*(--y);

-        if(y && (aBndA[y] != aBndA[y-1] || aBndZ[y] != aBndZ[y-1]))

-        {

-          this._mkArcDiv(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);

-          ox = x;

-          oy = y;

-        }

-      }

-    }

-    this._mkArcDiv(x, 0, oy, cx, cy, iOdds, aBndA, aBndZ, iSects);

-    if(iOdds >> 16) // Odd height

-    {

-      if(iSects >> 16) // Start-angle > end-angle

-      {

-        var xl = (yEndA <= cy || yEndZ > cy)? (cx - x) : cx;

-        this._mkDiv(xl, cy, x + cx - xl + (iOdds & 0xffff), 1);

-      }

-      else if((iSects & 0x01) && yEndZ > cy)

-        this._mkDiv(cx - x, cy, x, 1);

-    }

-  };

-

-/* fillPolygon method, implemented by Matthieu Haller.

-This javascript function is an adaptation of the gdImageFilledPolygon for Walter Zorn lib.

-C source of GD 1.8.4 found at http://www.boutell.com/gd/

-

-THANKS to Kirsten Schulz for the polygon fixes!

-

-The intersection finding technique of this code could be improved

-by remembering the previous intertersection, and by using the slope.

-That could help to adjust intersections to produce a nice

-interior_extrema. */

-  this.fillPolygon = function(array_x, array_y)

-  {

-    var i;

-    var y;

-    var miny, maxy;

-    var x1, y1;

-    var x2, y2;

-    var ind1, ind2;

-    var ints;

-

-    var n = array_x.length;

-    if(!n) return;

-

-    miny = array_y[0];

-    maxy = array_y[0];

-    for(i = 1; i < n; i++)

-    {

-      if(array_y[i] < miny)

-        miny = array_y[i];

-

-      if(array_y[i] > maxy)

-        maxy = array_y[i];

-    }

-    for(y = miny; y <= maxy; y++)

-    {

-      var polyInts = new Array();

-      ints = 0;

-      for(i = 0; i < n; i++)

-      {

-        if(!i)

-        {

-          ind1 = n-1;

-          ind2 = 0;

-        }

-        else

-        {

-          ind1 = i-1;

-          ind2 = i;

-        }

-        y1 = array_y[ind1];

-        y2 = array_y[ind2];

-        if(y1 < y2)

-        {

-          x1 = array_x[ind1];

-          x2 = array_x[ind2];

-        }

-        else if(y1 > y2)

-        {

-          y2 = array_y[ind1];

-          y1 = array_y[ind2];

-          x2 = array_x[ind1];

-          x1 = array_x[ind2];

-        }

-        else continue;

-

-         //  Modified 11. 2. 2004 Walter Zorn

-        if((y >= y1) && (y < y2))

-          polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

-

-        else if((y == maxy) && (y > y1) && (y <= y2))

-          polyInts[ints++] = Math.round((y-y1) * (x2-x1) / (y2-y1) + x1);

-      }

-      polyInts.sort(_CompInt);

-      for(i = 0; i < ints; i+=2)

-        this._mkDiv(polyInts[i], y, polyInts[i+1]-polyInts[i]+1, 1);

-    }

-  };

-

-  this.drawString = function(txt, x, y)

-  {

-    this.htm += '<div style="position:absolute;white-space:nowrap;'+

-      'left:' + x + 'px;'+

-      'top:' + y + 'px;'+

-      'font-family:' +  this.ftFam + ';'+

-      'font-size:' + this.ftSz + ';'+

-      'color:' + this.color + ';' + this.ftSty + '">'+

-      txt +

-      '<\/div>';

-  };

-

-/* drawStringRect() added by Rick Blommers.

-Allows to specify the size of the text rectangle and to align the

-text both horizontally (e.g. right) and vertically within that rectangle */

-  this.drawStringRect = function(txt, x, y, width, halign)

-  {

-    this.htm += '<div style="position:absolute;overflow:hidden;'+

-      'left:' + x + 'px;'+

-      'top:' + y + 'px;'+

-      'width:'+width +'px;'+

-      'text-align:'+halign+';'+

-      'font-family:' +  this.ftFam + ';'+

-      'font-size:' + this.ftSz + ';'+

-      'color:' + this.color + ';' + this.ftSty + '">'+

-      txt +

-      '<\/div>';

-  };

-

-  this.drawImage = function(imgSrc, x, y, w, h, a)

-  {

-    this.htm += '<div style="position:absolute;'+

-      'left:' + x + 'px;'+

-      'top:' + y + 'px;'+

-      // w (width) and h (height) arguments are now optional.

-      // Added by Mahmut Keygubatli, 14.1.2008

-      (w? ('width:' +  w + 'px;') : '') +

-      (h? ('height:' + h + 'px;'):'')+'">'+

-      '<img src="' + imgSrc +'"'+ (w ? (' width="' + w + '"'):'')+ (h ? (' height="' + h + '"'):'') + (a? (' '+a) : '') + '>'+

-      '<\/div>';

-  };

-

-  this.clear = function()

-  {

-    this.htm = "";

-    if(this.cnv) this.cnv.innerHTML = "";

-  };

-

-  this._mkOvQds = function(cx, cy, x, y, w, h, wod, hod)

-  {

-    var xl = cx - x, xr = cx + x + wod - w, yt = cy - y, yb = cy + y + hod - h;

-    if(xr > xl+w)

-    {

-      this._mkDiv(xr, yt, w, h);

-      this._mkDiv(xr, yb, w, h);

-    }

-    else

-      w = xr - xl + w;

-    this._mkDiv(xl, yt, w, h);

-    this._mkDiv(xl, yb, w, h);

-  };

-  

-  this._mkArcDiv = function(x, y, oy, cx, cy, iOdds, aBndA, aBndZ, iSects)

-  {

-    var xrDef = cx + x + (iOdds & 0xffff), y2, h = oy - y, xl, xr, w;

-

-    if(!h) h = 1;

-    x = cx - x;

-

-    if(iSects & 0xff0000) // Start-angle > end-angle

-    {

-      y2 = cy - y - h;

-      if(iSects & 0x00ff)

-      {

-        if(iSects & 0x02)

-        {

-          xl = Math.max(x, aBndZ[y]);

-          w = xrDef - xl;

-          if(w > 0) this._mkDiv(xl, y2, w, h);

-        }

-        if(iSects & 0x01)

-        {

-          xr = Math.min(xrDef, aBndA[y]);

-          w = xr - x;

-          if(w > 0) this._mkDiv(x, y2, w, h);

-        }

-      }

-      else

-        this._mkDiv(x, y2, xrDef - x, h);

-      y2 = cy + y + (iOdds >> 16);

-      if(iSects & 0xff00)

-      {

-        if(iSects & 0x0100)

-        {

-          xl = Math.max(x, aBndA[y]);

-          w = xrDef - xl;

-          if(w > 0) this._mkDiv(xl, y2, w, h);

-        }

-        if(iSects & 0x0200)

-        {

-          xr = Math.min(xrDef, aBndZ[y]);

-          w = xr - x;

-          if(w > 0) this._mkDiv(x, y2, w, h);

-        }

-      }

-      else

-        this._mkDiv(x, y2, xrDef - x, h);

-    }

-    else

-    {

-      if(iSects & 0x00ff)

-      {

-        if(iSects & 0x02)

-          xl = Math.max(x, aBndZ[y]);

-        else

-          xl = x;

-        if(iSects & 0x01)

-          xr = Math.min(xrDef, aBndA[y]);

-        else

-          xr = xrDef;

-        y2 = cy - y - h;

-        w = xr - xl;

-        if(w > 0) this._mkDiv(xl, y2, w, h);

-      }

-      if(iSects & 0xff00)

-      {

-        if(iSects & 0x0100)

-          xl = Math.max(x, aBndA[y]);

-        else

-          xl = x;

-        if(iSects & 0x0200)

-          xr = Math.min(xrDef, aBndZ[y]);

-        else

-          xr = xrDef;

-        y2 = cy + y + (iOdds >> 16);

-        w = xr - xl;

-        if(w > 0) this._mkDiv(xl, y2, w, h);

-      }

-    }

-  };

-

-  this.setStroke(1);

-  this.setFont("verdana,geneva,helvetica,sans-serif", "12px", Font.PLAIN);

-  this.color = "#000000";

-  this.htm = "";

-  this.wnd = wnd || window;

-

-  if(!jg_ok) _chkDHTM();

-  if(jg_ok)

-  {

-    if(cnv)

-    {

-      if(typeof(cnv) == "string")

-        this.cont = document.all? (this.wnd.document.all[cnv] || null)

-          : document.getElementById? (this.wnd.document.getElementById(cnv) || null)

-          : null;

-      else if(cnv == window.document)

-        this.cont = document.getElementsByTagName("body")[0];

-      // If cnv is a direct reference to a canvas DOM node

-      // (option suggested by Andreas Luleich)

-      else this.cont = cnv;

-      // Create new canvas inside container DIV. Thus the drawing and clearing

-      // methods won't interfere with the container's inner html.

-      // Solution suggested by Vladimir.

-      this.cnv = this.wnd.document.createElement("div");

-      this.cnv.style.fontSize=0;

-      this.cont.appendChild(this.cnv);

-      this.paint = jg_dom? _pntCnvDom : _pntCnvIe;

-    }

-    else

-      this.paint = _pntDoc;

-  }

-  else

-    this.paint = _pntN;

-

-  this.setPrintable(false);

-}

-

-function _mkLinVirt(aLin, x1, y1, x2, y2)

-{

-  var dx = Math.abs(x2-x1), dy = Math.abs(y2-y1),

-  x = x1, y = y1,

-  xIncr = (x1 > x2)? -1 : 1,

-  yIncr = (y1 > y2)? -1 : 1,

-  p,

-  i = 0;

-  if(dx >= dy)

-  {

-    var pr = dy<<1,

-    pru = pr - (dx<<1);

-    p = pr-dx;

-    while(dx > 0)

-    {--dx;

-      if(p > 0)    //  Increment y

-      {

-        aLin[i++] = x;

-        y += yIncr;

-        p += pru;

-      }

-      else p += pr;

-      x += xIncr;

-    }

-  }

-  else

-  {

-    var pr = dx<<1,

-    pru = pr - (dy<<1);

-    p = pr-dy;

-    while(dy > 0)

-    {--dy;

-      y += yIncr;

-      aLin[i++] = x;

-      if(p > 0)    //  Increment x

-      {

-        x += xIncr;

-        p += pru;

-      }

-      else p += pr;

-    }

-  }

-  for(var len = aLin.length, i = len-i; i;)

-    aLin[len-(i--)] = x;

-};

-

-function _CompInt(x, y)

-{

-  return(x - y);

-}

-

diff --git a/lib/xmlgen.nim b/lib/xmlgen.nim
new file mode 100644
index 000000000..79a782252
--- /dev/null
+++ b/lib/xmlgen.nim
@@ -0,0 +1,406 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module implements a simple `XML`:idx: and `HTML`:idx: code 
+## generator. Each commonly used HTML tag has a corresponding macro
+## that generates a string with its HTML representation.
+##
+## Example:
+##
+## .. code-block:: nimrod
+##   var nim = "Nimrod"
+##   echo h1(a(href="http://force7.de/nimrod", nim))
+##  
+## Writes the string::
+##   
+##   <h1><a href="http://force7.de/nimrod">Nimrod</a></h1>
+##
+
+import
+  macros, strutils
+
+const
+  coreAttr* = " id class title style "
+  eventAttr* = " onclick ondblclick onmousedown onmouseup " &
+    "onmouseover onmousemove onmouseout onkeypress onkeydown onkeyup "
+  commonAttr* = coreAttr & eventAttr
+
+proc getIdent(e: PNimrodNode): string {.compileTime.} = 
+  case e.kind
+  of nnkIdent: result = normalize($e.ident)
+  of nnkAccQuoted: result = getIdent(e[0])
+  else: error("cannot extract identifier from node: " & toStrLit(e).strVal)
+
+proc delete[T](s: var seq[T], attr: T): bool = 
+  var idx = find(s, attr)
+  if idx >= 0:
+    var L = s.len
+    s[idx] = s[L-1]
+    setLen(s, L-1)
+    result = true
+
+proc xmlCheckedTag*(e: PNimrodNode, tag: string,
+    optAttr = "", reqAttr = "",
+    isLeaf = false): PNimrodNode {.compileTime.} =
+  ## use this procedure to define a new XML tag
+  
+  # copy the attributes; when iterating over them these lists
+  # will be modified, so that each attribute is only given one value
+  var req = splitSeq(reqAttr)
+  var opt = splitSeq(optAttr)
+  result = newNimNode(nnkBracket, e)
+  result.add(newStrLitNode("<"))
+  result.add(newStrLitNode(tag))
+  # first pass over attributes:
+  for i in 1..e.len-1:
+    if e[i].kind == nnkExprEqExpr: 
+      var name = getIdent(e[i][0])
+      if delete(req, name) or delete(opt, name):
+        result.add(newStrLitNode(" "))
+        result.add(newStrLitNode(name))
+        result.add(newStrLitNode("=\""))
+        result.add(e[i][1])
+        result.add(newStrLitNode("\""))
+      else:
+        error("invalid attribute for '" & tag & "' element: " & name)
+  # check each required attribute exists:
+  if req.len > 0:
+    error(req[0] & " attribute for '" & tag & "' element expected")
+  if isLeaf:
+    for i in 1..e.len-1:
+      if e[i].kind != nnkExprEqExpr: 
+        error("element " & tag & " cannot be nested")
+    result.add(newStrLitNode(" />"))
+  else:
+    result.add(newStrLitNode(">"))
+    # second pass over elements:
+    for i in 1..e.len-1:
+      if e[i].kind != nnkExprEqExpr: result.add(e[i])
+    result.add(newStrLitNode("</"))
+    result.add(newStrLitNode(tag))
+    result.add(newStrLitNode(">"))
+  result = NestList(!"&", result)
+
+
+macro a*(e: expr): expr = 
+  ## generates the HTML ``a`` element.
+  result = xmlCheckedTag(e, "a", "href charset type hreflang rel rev " &
+    "accesskey tabindex" & commonAttr)
+
+macro acronym*(e: expr): expr = 
+  ## generates the HTML ``acronym`` element.
+  result = xmlCheckedTag(e, "acronym", commonAttr)
+
+macro address*(e: expr): expr = 
+  ## generates the HTML ``address`` element.
+  result = xmlCheckedTag(e, "address", commonAttr)
+
+macro area*(e: expr): expr = 
+  ## generates the HTML ``area`` element.
+  result = xmlCheckedTag(e, "area", "shape coords href nohref" &
+    " accesskey tabindex" & commonAttr, "alt", true)
+
+macro b*(e: expr): expr = 
+  ## generates the HTML ``b`` element.
+  result = xmlCheckedTag(e, "b", commonAttr)
+
+macro base*(e: expr): expr = 
+  ## generates the HTML ``base`` element.
+  result = xmlCheckedTag(e, "base", "", "href", true)
+
+macro big*(e: expr): expr = 
+  ## generates the HTML ``big`` element.
+  result = xmlCheckedTag(e, "big", commonAttr)
+
+macro blockquote*(e: expr): expr = 
+  ## generates the HTML ``blockquote`` element.
+  result = xmlCheckedTag(e, "blockquote", " cite" & commonAttr)
+
+macro body*(e: expr): expr = 
+  ## generates the HTML ``body`` element.
+  result = xmlCheckedTag(e, "body", commonAttr)
+
+macro br*(e: expr): expr = 
+  ## generates the HTML ``br`` element.
+  result = xmlCheckedTag(e, "br", "", "", true)
+
+macro button*(e: expr): expr = 
+  ## generates the HTML ``button`` element.
+  result = xmlCheckedTag(e, "button", "accesskey tabindex " &
+    "disabled name type value" & commonAttr)
+
+macro caption*(e: expr): expr = 
+  ## generates the HTML ``caption`` element.
+  result = xmlCheckedTag(e, "caption", commonAttr)
+
+macro cite*(e: expr): expr = 
+  ## generates the HTML ``cite`` element.
+  result = xmlCheckedTag(e, "cite", commonAttr)
+
+macro code*(e: expr): expr = 
+  ## generates the HTML ``code`` element.
+  result = xmlCheckedTag(e, "code", commonAttr)
+
+macro col*(e: expr): expr = 
+  ## generates the HTML ``col`` element.
+  result = xmlCheckedTag(e, "col", "span align valign" & commonAttr, "", true)
+
+macro colgroup*(e: expr): expr = 
+  ## generates the HTML ``colgroup`` element.
+  result = xmlCheckedTag(e, "colgroup", "span align valign" & commonAttr)
+
+macro dd*(e: expr): expr = 
+  ## generates the HTML ``dd`` element.
+  result = xmlCheckedTag(e, "dd", commonAttr)
+
+macro del*(e: expr): expr = 
+  ## generates the HTML ``del`` element.
+  result = xmlCheckedTag(e, "del", "cite datetime" & commonAttr)
+
+macro dfn*(e: expr): expr = 
+  ## generates the HTML ``dfn`` element.
+  result = xmlCheckedTag(e, "dfn", commonAttr)
+
+macro `div`*(e: expr): expr = 
+  ## generates the HTML ``div`` element.
+  result = xmlCheckedTag(e, "div", commonAttr)
+
+macro dl*(e: expr): expr = 
+  ## generates the HTML ``dl`` element.
+  result = xmlCheckedTag(e, "dl", commonAttr)
+
+macro dt*(e: expr): expr = 
+  ## generates the HTML ``dt`` element.
+  result = xmlCheckedTag(e, "dt", commonAttr)
+
+macro em*(e: expr): expr = 
+  ## generates the HTML ``em`` element.
+  result = xmlCheckedTag(e, "em", commonAttr)
+
+macro fieldset*(e: expr): expr = 
+  ## generates the HTML ``fieldset`` element.
+  result = xmlCheckedTag(e, "fieldset", commonAttr)
+
+macro form*(e: expr): expr = 
+  ## generates the HTML ``form`` element.
+  result = xmlCheckedTag(e, "form", "method encype accept accept-charset" & 
+    commonAttr, "action")
+
+macro h1*(e: expr): expr = 
+  ## generates the HTML ``h1`` element.
+  result = xmlCheckedTag(e, "h1", commonAttr)
+
+macro h2*(e: expr): expr = 
+  ## generates the HTML ``h2`` element.
+  result = xmlCheckedTag(e, "h2", commonAttr)
+
+macro h3*(e: expr): expr = 
+  ## generates the HTML ``h3`` element.
+  result = xmlCheckedTag(e, "h3", commonAttr)
+
+macro h4*(e: expr): expr = 
+  ## generates the HTML ``h4`` element.
+  result = xmlCheckedTag(e, "h4", commonAttr)
+
+macro h5*(e: expr): expr = 
+  ## generates the HTML ``h5`` element.
+  result = xmlCheckedTag(e, "h5", commonAttr)
+
+macro h6*(e: expr): expr = 
+  ## generates the HTML ``h6`` element.
+  result = xmlCheckedTag(e, "h6", commonAttr)
+
+macro head*(e: expr): expr = 
+  ## generates the HTML ``head`` element.
+  result = xmlCheckedTag(e, "head", "profile")
+
+macro html*(e: expr): expr = 
+  ## generates the HTML ``html`` element.
+  result = xmlCheckedTag(e, "html", "", "xmlns")
+
+macro hr*(e: expr): expr = 
+  ## generates the HTML ``hr`` element.
+  result = xmlCheckedTag(e, "hr", commonAttr, "", true)
+
+macro i*(e: expr): expr = 
+  ## generates the HTML ``i`` element.
+  result = xmlCheckedTag(e, "i", commonAttr)
+
+macro img*(e: expr): expr = 
+  ## generates the HTML ``img`` element.
+  result = xmlCheckedTag(e, "img", "longdesc height width", "src alt", true)
+
+macro input*(e: expr): expr = 
+  ## generates the HTML ``input`` element.
+  result = xmlCheckedTag(e, "input", "name type value checked maxlength src" &
+    " alt accept disabled readonly accesskey tabindex" & commonAttr, "", true)
+
+macro ins*(e: expr): expr = 
+  ## generates the HTML ``ins`` element.
+  result = xmlCheckedTag(e, "ins", "cite datetime" & commonAttr)
+
+macro kbd*(e: expr): expr = 
+  ## generates the HTML ``kbd`` element.
+  result = xmlCheckedTag(e, "kbd", commonAttr)
+
+macro label*(e: expr): expr = 
+  ## generates the HTML ``label`` element.
+  result = xmlCheckedTag(e, "label", "for accesskey" & commonAttr)
+
+macro legend*(e: expr): expr = 
+  ## generates the HTML ``legend`` element.
+  result = xmlCheckedTag(e, "legend", "accesskey" & commonAttr)
+
+macro li*(e: expr): expr = 
+  ## generates the HTML ``li`` element.
+  result = xmlCheckedTag(e, "li", commonAttr)
+
+macro link*(e: expr): expr = 
+  ## generates the HTML ``link`` element.
+  result = xmlCheckedTag(e, "link", "href charset hreflang type rel rev media" & 
+    commonAttr, "", true)
+
+macro map*(e: expr): expr = 
+  ## generates the HTML ``map`` element.
+  result = xmlCheckedTag(e, "map", "class title" & eventAttr, "id", false)
+
+macro meta*(e: expr): expr = 
+  ## generates the HTML ``meta`` element.
+  result = xmlCheckedTag(e, "meta", "name http-equiv scheme", "content", true)
+
+macro noscript*(e: expr): expr = 
+  ## generates the HTML ``noscript`` element.
+  result = xmlCheckedTag(e, "noscript", commonAttr)
+
+macro `object`*(e: expr): expr = 
+  ## generates the HTML ``object`` element.
+  result = xmlCheckedTag(e, "object", "classid data codebase declare type " &
+    "codetype archive standby width height name tabindex" & commonAttr)
+
+macro ol*(e: expr): expr = 
+  ## generates the HTML ``ol`` element.
+  result = xmlCheckedTag(e, "ol", commonAttr)
+
+macro optgroup*(e: expr): expr = 
+  ## generates the HTML ``optgroup`` element.
+  result = xmlCheckedTag(e, "optgroup", "disabled" & commonAttr, "label", false)
+
+macro option*(e: expr): expr = 
+  ## generates the HTML ``option`` element.
+  result = xmlCheckedTag(e, "option", "selected value" & commonAttr)
+
+macro p*(e: expr): expr = 
+  ## generates the HTML ``p`` element.
+  result = xmlCheckedTag(e, "p", commonAttr)
+
+macro param*(e: expr): expr = 
+  ## generates the HTML ``param`` element.
+  result = xmlCheckedTag(e, "param", "value id type valuetype", "name", true)
+
+macro pre*(e: expr): expr = 
+  ## generates the HTML ``pre`` element.
+  result = xmlCheckedTag(e, "pre", commonAttr)
+
+macro q*(e: expr): expr = 
+  ## generates the HTML ``q`` element.
+  result = xmlCheckedTag(e, "q", "cite" & commonAttr)
+
+macro samp*(e: expr): expr = 
+  ## generates the HTML ``samp`` element.
+  result = xmlCheckedTag(e, "samp", commonAttr)
+
+macro script*(e: expr): expr = 
+  ## generates the HTML ``script`` element.
+  result = xmlCheckedTag(e, "script", "src charset defer", "type", false)
+
+macro select*(e: expr): expr = 
+  ## generates the HTML ``select`` element.
+  result = xmlCheckedTag(e, "select", "name size multiple disabled tabindex" & 
+    commonAttr)
+
+macro small*(e: expr): expr = 
+  ## generates the HTML ``small`` element.
+  result = xmlCheckedTag(e, "small", commonAttr)
+
+macro span*(e: expr): expr = 
+  ## generates the HTML ``span`` element.
+  result = xmlCheckedTag(e, "span", commonAttr)
+
+macro strong*(e: expr): expr = 
+  ## generates the HTML ``strong`` element.
+  result = xmlCheckedTag(e, "strong", commonAttr)
+
+macro style*(e: expr): expr = 
+  ## generates the HTML ``style`` element.
+  result = xmlCheckedTag(e, "style", "media title", "type")
+
+macro sub*(e: expr): expr = 
+  ## generates the HTML ``sub`` element.
+  result = xmlCheckedTag(e, "sub", commonAttr)
+
+macro sup*(e: expr): expr = 
+  ## generates the HTML ``sup`` element.
+  result = xmlCheckedTag(e, "sup", commonAttr)
+
+macro table*(e: expr): expr = 
+  ## generates the HTML ``table`` element.
+  result = xmlCheckedTag(e, "table", "summary border cellpadding cellspacing" &
+    " frame rules width" & commonAttr)
+
+macro tbody*(e: expr): expr = 
+  ## generates the HTML ``tbody`` element.
+  result = xmlCheckedTag(e, "tbody", "align valign" & commonAttr)
+
+macro td*(e: expr): expr = 
+  ## generates the HTML ``td`` element.
+  result = xmlCheckedTag(e, "td", "colspan rowspan abbr axis headers scope" &
+    " align valign" & commonAttr)
+
+macro textarea*(e: expr): expr = 
+  ## generates the HTML ``textarea`` element.
+  result = xmlCheckedTag(e, "textarea", " name disabled readonly accesskey" &
+    " tabindex" & commonAttr, "rows cols", false)
+
+macro tfoot*(e: expr): expr = 
+  ## generates the HTML ``tfoot`` element.
+  result = xmlCheckedTag(e, "tfoot", "align valign" & commonAttr)
+
+macro th*(e: expr): expr = 
+  ## generates the HTML ``th`` element.
+  result = xmlCheckedTag(e, "th", "colspan rowspan abbr axis headers scope" &
+    " align valign" & commonAttr)
+
+macro thead*(e: expr): expr = 
+  ## generates the HTML ``thead`` element.
+  result = xmlCheckedTag(e, "thead", "align valign" & commonAttr)
+
+macro title*(e: expr): expr = 
+  ## generates the HTML ``title`` element.
+  result = xmlCheckedTag(e, "title")
+
+macro tr*(e: expr): expr = 
+  ## generates the HTML ``tr`` element.
+  result = xmlCheckedTag(e, "tr", "align valign" & commonAttr)
+
+macro tt*(e: expr): expr = 
+  ## generates the HTML ``tt`` element.
+  result = xmlCheckedTag(e, "tt", commonAttr)
+
+macro ul*(e: expr): expr = 
+  ## generates the HTML ``ul`` element.
+  result = xmlCheckedTag(e, "ul", commonAttr)
+
+macro `var`*(e: expr): expr = 
+  ## generates the HTML ``var`` element.
+  result = xmlCheckedTag(e, "var", commonAttr)
+
+when isMainModule:
+  var nim = "Nimrod"
+  echo h1(a(href="http://force7.de/nimrod", nim))
+
diff --git a/nim/ast.pas b/nim/ast.pas
index a57632468..0c3137b2b 100644
--- a/nim/ast.pas
+++ b/nim/ast.pas
@@ -15,7 +15,7 @@ interface
 {$include 'config.inc'}

 

 uses

-  nsystem, charsets, msgs, hashes,

+  nsystem, charsets, msgs, nhashes,

   nversion, options, strutils, crc, ropes, idents, lists;

 

 const

@@ -245,18 +245,18 @@ type
     mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT, 
     mSlice, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq, mInRange, 
     mInSet, mAsgn, mRepr, mExit, mSetLengthStr, mSetLengthSeq, 
-    mAssert, mSwap, mIsNil, mArrToSeq, mArray, mOpenArray, 
-    mRange, mSet, mSeq, mInt, mInt8, mInt16, 
-    mInt32, mInt64, mFloat, mFloat32, mFloat64, mBool, 
-    mChar, mString, mCstring, mPointer, mAnyEnum, mEmptySet, 
-    mIntSetBaseType, mNil, mIsMainModule, mCompileDate, mCompileTime, mNimrodVersion, 
-    mNimrodMajor, mNimrodMinor, mNimrodPatch, mCpuEndian, mHostOS, mHostCPU, 
-    mNaN, mInf, mNegInf, mNLen, mNChild, mNSetChild, 
-    mNAdd, mNAddMultiple, mNDel, mNKind, mNIntVal, mNFloatVal, 
-    mNSymbol, mNIdent, mNGetType, mNStrVal, mNSetIntVal, mNSetFloatVal, 
-    mNSetSymbol, mNSetIdent, mNSetType, mNSetStrVal, mNNewNimNode, mNCopyNimNode, 
-    mNCopyNimTree, mStrToIdent, mIdentToStr, mEqIdent, mNHint, mNWarning, 
-    mNError
+    mAssert, mSwap, mIsNil, mArrToSeq, mCopyStr, mCopyStrLast, 
+    mNewString, mArray, mOpenArray, mRange, mSet, mSeq, 
+    mInt, mInt8, mInt16, mInt32, mInt64, mFloat, 
+    mFloat32, mFloat64, mBool, mChar, mString, mCstring, 
+    mPointer, mAnyEnum, mEmptySet, mIntSetBaseType, mNil, mIsMainModule, 
+    mCompileDate, mCompileTime, mNimrodVersion, mNimrodMajor, mNimrodMinor, mNimrodPatch, 
+    mCpuEndian, mHostOS, mHostCPU, mNaN, mInf, mNegInf, 
+    mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, 
+    mNKind, mNIntVal, mNFloatVal, mNSymbol, mNIdent, mNGetType, 
+    mNStrVal, mNSetIntVal, mNSetFloatVal, mNSetSymbol, mNSetIdent, mNSetType, 
+    mNSetStrVal, mNNewNimNode, mNCopyNimNode, mNCopyNimTree, mStrToIdent, mIdentToStr, 
+    mEqIdent, mNHint, mNWarning, mNError
     //[[[end]]]

   );

 

@@ -327,7 +327,7 @@ type
   );

 

   TLocFlag = (

-    lfIndirect,    // backend introduced a pointer
+    lfIndirect,    // backend introduced a pointer

     lfParamCopy,   // backend introduced a parameter copy (LLVM)

     lfNoDeepCopy,  // no need for a deep copy

     lfNoDecl,      // do not declare it in C

@@ -504,18 +504,18 @@ const // "MagicToStr" array:
     'SymDiffSet', 'ConStrStr', 'ConArrArr', 'ConArrT', 'ConTArr', 'ConTT', 
     'Slice', 'AppendStrCh', 'AppendStrStr', 'AppendSeqElem', 'AppendSeqSeq', 'InRange', 
     'InSet', 'Asgn', 'Repr', 'Exit', 'SetLengthStr', 'SetLengthSeq', 
-    'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'Array', 'OpenArray', 
-    'Range', 'Set', 'Seq', 'Int', 'Int8', 'Int16', 
-    'Int32', 'Int64', 'Float', 'Float32', 'Float64', 'Bool', 
-    'Char', 'String', 'Cstring', 'Pointer', 'AnyEnum', 'EmptySet', 
-    'IntSetBaseType', 'Nil', 'IsMainModule', 'CompileDate', 'CompileTime', 'NimrodVersion', 
-    'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 'CpuEndian', 'HostOS', 'HostCPU', 
-    'NaN', 'Inf', 'NegInf', 'NLen', 'NChild', 'NSetChild', 
-    'NAdd', 'NAddMultiple', 'NDel', 'NKind', 'NIntVal', 'NFloatVal', 
-    'NSymbol', 'NIdent', 'NGetType', 'NStrVal', 'NSetIntVal', 'NSetFloatVal', 
-    'NSetSymbol', 'NSetIdent', 'NSetType', 'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 
-    'NCopyNimTree', 'StrToIdent', 'IdentToStr', 'EqIdent', 'NHint', 'NWarning', 
-    'NError'
+    'Assert', 'Swap', 'IsNil', 'ArrToSeq', 'CopyStr', 'CopyStrLast', 
+    'NewString', 'Array', 'OpenArray', 'Range', 'Set', 'Seq', 
+    'Int', 'Int8', 'Int16', 'Int32', 'Int64', 'Float', 
+    'Float32', 'Float64', 'Bool', 'Char', 'String', 'Cstring', 
+    'Pointer', 'AnyEnum', 'EmptySet', 'IntSetBaseType', 'Nil', 'IsMainModule', 
+    'CompileDate', 'CompileTime', 'NimrodVersion', 'NimrodMajor', 'NimrodMinor', 'NimrodPatch', 
+    'CpuEndian', 'HostOS', 'HostCPU', 'NaN', 'Inf', 'NegInf', 
+    'NLen', 'NChild', 'NSetChild', 'NAdd', 'NAddMultiple', 'NDel', 
+    'NKind', 'NIntVal', 'NFloatVal', 'NSymbol', 'NIdent', 'NGetType', 
+    'NStrVal', 'NSetIntVal', 'NSetFloatVal', 'NSetSymbol', 'NSetIdent', 'NSetType', 
+    'NSetStrVal', 'NNewNimNode', 'NCopyNimNode', 'NCopyNimTree', 'StrToIdent', 'IdentToStr', 
+    'EqIdent', 'NHint', 'NWarning', 'NError'
     //[[[end]]]

   );

 

diff --git a/nim/astalgo.pas b/nim/astalgo.pas
index f7b6f651d..e5475ddd1 100644
--- a/nim/astalgo.pas
+++ b/nim/astalgo.pas
@@ -17,7 +17,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, ast, hashes, charsets, strutils, options, msgs, ropes, idents;
+  nsystem, ast, nhashes, charsets, strutils, options, msgs, ropes, idents;
 
 function hashNode(p: PObject): THash;
 
diff --git a/nim/ccgexprs.pas b/nim/ccgexprs.pas
index 03de5c4de..bd0c520d2 100644
--- a/nim/ccgexprs.pas
+++ b/nim/ccgexprs.pas
@@ -1254,15 +1254,9 @@ begin
   refType := skipVarGenericRange(e.sons[1].typ);
   InitLocExpr(p, e.sons[1], a);
   initLoc(b, locExpr, a.t, OnHeap);
-  
-  if optBoehmGC in gGlobalOptions then 
-    b.r := ropef('($1) newObj(sizeof($2))',
-      [getTypeDesc(p.module, reftype), 
-      getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))])  
-  else
-    b.r := ropef('($1) newObj($2, sizeof($3))',
-      [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType),
-      getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
+  b.r := ropef('($1) newObj($2, sizeof($3))',
+    [getTypeDesc(p.module, reftype), genTypeInfo(p.module, refType),
+    getTypeDesc(p.module, skipGenericRange(reftype.sons[0]))]);
   genAssignment(p, a, b, {@set}[]);
   // set the object type:
   bt := skipGenericRange(refType.sons[0]);
@@ -1279,16 +1273,10 @@ begin
   InitLocExpr(p, e.sons[1], a);
   InitLocExpr(p, e.sons[2], b);
   initLoc(c, locExpr, a.t, OnHeap);
-  if optBoehmGC in gGlobalOptions then 
-    c.r := ropef('($1) newSeq(sizeof($2), $3)',
-      [getTypeDesc(p.module, seqtype), 
-       getTypeDesc(p.module, skipGenericRange(seqtype.sons[0])),
-       rdLoc(b)])
-  else
-    c.r := ropef('($1) newSeq($2, $3)',
-      [getTypeDesc(p.module, seqtype),
-       genTypeInfo(p.module, seqType),
-       rdLoc(b)]);
+  c.r := ropef('($1) newSeq($2, $3)', 
+    [getTypeDesc(p.module, seqtype),
+    genTypeInfo(p.module, seqType),
+    rdLoc(b)]);
   genAssignment(p, a, c, {@set}[]);
 end;
 
@@ -1945,6 +1933,7 @@ begin
     mSetLengthSeq: genSetLengthSeq(p, e, d);
     mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet,
     mMinusSet, mInSet: genSetOp(p, e, d, op);
+    mNewString, mCopyStr, mCopyStrLast: genCall(p, e, d);
     mExit: genCall(p, e, d);
     mArrToSeq: genArrToSeq(p, e, d);
     mNLen..mNError:
diff --git a/nim/ccgstmts.pas b/nim/ccgstmts.pas
index 7588f7e15..f3fcdf518 100644
--- a/nim/ccgstmts.pas
+++ b/nim/ccgstmts.pas
@@ -878,7 +878,7 @@ var
   i: int;
   prc: PSym;
 begin
-  assert(t <> nil);
+  //assert(t <> nil);
   if inCheckpoint(t.info) then
     MessageOut(renderTree(t));
   case t.kind of
@@ -913,7 +913,7 @@ begin
     nkRaiseStmt: genRaiseStmt(p, t);
     nkTypeSection: begin
       // we have to emit the type information for object types here to support
-      // seperate compilation:
+      // separate compilation:
       genTypeSection(p.module, t);
     end;
     nkCommentStmt, nkNilLit, nkIteratorDef, nkIncludeStmt, nkImportStmt,
diff --git a/nim/ccgutils.pas b/nim/ccgutils.pas
index 56eff6c9e..49c1a8cee 100644
--- a/nim/ccgutils.pas
+++ b/nim/ccgutils.pas
@@ -16,7 +16,7 @@ interface
 
 uses
   charsets, nsystem,
-  ast, astalgo, ropes, lists, hashes, strutils, types, msgs;
+  ast, astalgo, ropes, lists, nhashes, strutils, types, msgs;
 
 function toCChar(c: Char): string;
 function makeCString(const s: string): PRope;
diff --git a/nim/cgen.pas b/nim/cgen.pas
index 5dcb7f50b..df8431a30 100644
--- a/nim/cgen.pas
+++ b/nim/cgen.pas
@@ -16,7 +16,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, ast, astalgo, strutils, hashes, trees, platform, magicsys,
+  nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys,
   extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
   lists, types, ccgutils, nos, ntime, ropes, nmath, passes, rodread,
   wordrecg, rnimsyn, treetab;
diff --git a/nim/commands.pas b/nim/commands.pas
index 8a4435eb0..fde2d26c7 100644
--- a/nim/commands.pas
+++ b/nim/commands.pas
@@ -1,61 +1,61 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-
-unit commands;
-
-// This module handles the parsing of command line arguments.
-
-interface
-
-{$include 'config.inc'}
-
-uses
-  nsystem, charsets, nos, msgs, options, nversion, condsyms, strutils, extccomp, 
-  platform, lists, wordrecg;
-
-procedure writeCommandLineUsage;
-
-type
-  TCmdLinePass = (
-    passCmd1,                // first pass over the command line
-    passCmd2,                // second pass over the command line
-    passPP                   // preprocessor called ProcessCommand()
-  );
-
-procedure ProcessCommand(const switch: string; pass: TCmdLinePass);
-procedure processSwitch(const switch, arg: string; pass: TCmdlinePass;
-                        const info: TLineInfo);
-
-implementation
-
-{@ignore}
-const
-{$ifdef fpc}
-  compileDate = {$I %date%};
-{$else}
-  compileDate = '2009-0-0';
-{$endif}
-{@emit}
-
-const
-  HelpMessage = 'Nimrod Compiler Version $1 (' +{&}
-    compileDate +{&} ') [$2: $3]' +{&} nl +{&}
-    'Copyright (c) 2004-2009 by Andreas Rumpf' +{&} nl;
-
-const
-  Usage = ''
-//[[[cog
-//from string import replace
-//def f(x): return "+{&} '" + replace(x, "'", "''")[:-1] + "' +{&} nl"
-//for line in open("data/basicopt.txt").readlines():
-//  cog.outl(f(line))
-//]]]
+//

+//

+//           The Nimrod Compiler

+//        (c) Copyright 2008 Andreas Rumpf

+//

+//    See the file "copying.txt", included in this

+//    distribution, for details about the copyright.

+//

+

+unit commands;

+

+// This module handles the parsing of command line arguments.

+

+interface

+

+{$include 'config.inc'}

+

+uses

+  nsystem, charsets, nos, msgs, options, nversion, condsyms, strutils, extccomp, 

+  platform, lists, wordrecg;

+

+procedure writeCommandLineUsage;

+

+type

+  TCmdLinePass = (

+    passCmd1,                // first pass over the command line

+    passCmd2,                // second pass over the command line

+    passPP                   // preprocessor called ProcessCommand()

+  );

+

+procedure ProcessCommand(const switch: string; pass: TCmdLinePass);

+procedure processSwitch(const switch, arg: string; pass: TCmdlinePass;

+                        const info: TLineInfo);

+

+implementation

+

+{@ignore}

+const

+{$ifdef fpc}

+  compileDate = {$I %date%};

+{$else}

+  compileDate = '2009-0-0';

+{$endif}

+{@emit}

+

+const

+  HelpMessage = 'Nimrod Compiler Version $1 (' +{&}

+    compileDate +{&} ') [$2: $3]' +{&} nl +{&}

+    'Copyright (c) 2004-2009 by Andreas Rumpf' +{&} nl;

+

+const

+  Usage = ''

+//[[[cog

+//from string import replace

+//def f(x): return "+{&} '" + replace(x, "'", "''")[:-1] + "' +{&} nl"

+//for line in open("data/basicopt.txt").readlines():

+//  cog.outl(f(line))

+//]]]

 +{&} 'Usage::' +{&} nl
 +{&} '  nimrod command [options] inputfile [arguments]' +{&} nl
 +{&} 'Command::' +{&} nl
@@ -88,14 +88,14 @@ const
 +{&} '  -r, --run                 run the compiled program with given arguments' +{&} nl
 +{&} '  --advanced                show advanced command line switches' +{&} nl
 +{&} '  -h, --help                show this help' +{&} nl
-//[[[end]]]
-  ;
-
-  AdvancedUsage = ''
-//[[[cog
-//for line in open("data/advopt.txt").readlines():
-//  cog.outl(f(line))
-//]]]
+//[[[end]]]

+  ;

+

+  AdvancedUsage = ''

+//[[[cog

+//for line in open("data/advopt.txt").readlines():

+//  cog.outl(f(line))

+//]]]

 +{&} 'Advanced commands::' +{&} nl
 +{&} '  pas                       convert a Pascal file to Nimrod syntax' +{&} nl
 +{&} '  pretty                    pretty print the inputfile' +{&} nl
@@ -125,401 +125,454 @@ const
 +{&} '  --checkpoints:on|off      turn on|off checkpoints; for debugging Nimrod' +{&} nl
 +{&} '  --skip_cfg                do not read the general configuration file' +{&} nl
 +{&} '  --skip_proj_cfg           do not read the project''s configuration file' +{&} nl
++{&} '  --gc:refc|boehm           use Nimrod''s native GC|Boehm GC' +{&} nl
 +{&} '  --index:FILE              use FILE to generate a documenation index file' +{&} nl
 +{&} '  --putenv:key=value        set an environment variable' +{&} nl
 +{&} '  --list_cmd                list the commands used to execute external programs' +{&} nl
 +{&} '  --verbosity:0|1|2|3       set Nimrod''s verbosity level (0 is default)' +{&} nl
 +{&} '  -v, --version             show detailed version information' +{&} nl
-//[[[end]]]
-  ;
-
-function getCommandLineDesc: string;
-begin
-  result := format(HelpMessage, [VersionAsString, 
-    platform.os[platform.hostOS].name, cpu[platform.hostCPU].name]) +{&} Usage
-end;
-
-var
-  helpWritten: boolean;  // BUGFIX 19
-  versionWritten: boolean;
-  advHelpWritten: boolean;
-
-procedure HelpOnError(pass: TCmdLinePass);
-begin
-  if (pass = passCmd1) and not helpWritten then begin
-    // BUGFIX 19
-    MessageOut(getCommandLineDesc());
-    helpWritten := true
-  end
-end;
-
-procedure writeAdvancedUsage(pass: TCmdLinePass);
-begin
-  if (pass = passCmd1) and not advHelpWritten then begin
-    // BUGFIX 19
-    MessageOut(format(HelpMessage, [VersionAsString, 
-                                    platform.os[platform.hostOS].name,
-                                    cpu[platform.hostCPU].name]) +{&}
-                                    AdvancedUsage);
-    advHelpWritten := true;
-    helpWritten := true;
-    halt(0);
-  end
-end;
-
-procedure writeVersionInfo(pass: TCmdLinePass);
-begin
-  if (pass = passCmd1) and not versionWritten then begin
-    versionWritten := true;
-    helpWritten := true;
-    messageOut(format(HelpMessage, [VersionAsString, 
-                                    platform.os[platform.hostOS].name,
-                                    cpu[platform.hostCPU].name]))
-  end
-end;
-
-procedure writeCommandLineUsage;
-begin
-  if not helpWritten then begin
-    messageOut(getCommandLineDesc());
-    helpWritten := true
-  end
-end;
-
-procedure InvalidCmdLineOption(pass: TCmdLinePass; const switch: string;
-                               const info: TLineInfo);
-begin
-  liMessage(info, errInvalidCmdLineOption, switch)
-end;
-
-procedure splitSwitch(const switch: string; out cmd, arg: string;
-                      pass: TCmdLinePass; const info: TLineInfo);
-var
-  i: int;
-begin
-  cmd := '';
-  i := strStart;
-  if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i);
-  if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i);
-  while i < length(switch) + strStart do begin
-    case switch[i] of
-      'a'..'z', 'A'..'Z', '0'..'9', '_', '.':
-        addChar(cmd, switch[i]);
-      else break;
-    end;
-    inc(i);
-  end;
-  if i >= length(switch) + strStart then
-    arg := ''
-  else if switch[i] in [':', '=', '['] then
-    arg := ncopy(switch, i + 1)
-  else
-    InvalidCmdLineOption(pass, switch, info)
-end;
-
-procedure ProcessOnOffSwitch(const op: TOptions; const arg: string;
-                             pass: TCmdlinePass; const info: TLineInfo);
-begin
-  case whichKeyword(arg) of
-    wOn:  gOptions := gOptions + op;
-    wOff: gOptions := gOptions - op;
-    else  liMessage(info, errOnOrOffExpectedButXFound, arg)
-  end
-end;
-
-procedure ProcessOnOffSwitchG(const op: TGlobalOptions; const arg: string;
-                              pass: TCmdlinePass; const info: TLineInfo);
-begin
-  case whichKeyword(arg) of
-    wOn:  gGlobalOptions := gGlobalOptions + op;
-    wOff: gGlobalOptions := gGlobalOptions - op;
-    else  liMessage(info, errOnOrOffExpectedButXFound, arg)
-  end
-end;
-
-procedure ExpectArg(const switch, arg: string; pass: TCmdLinePass;
-                    const info: TLineInfo);
-begin
-  if (arg = '') then
-    liMessage(info, errCmdLineArgExpected, switch)
-end;
-
-procedure ProcessSpecificNote(const arg: string; state: TSpecialWord;
-                              pass: TCmdlinePass; const info: TLineInfo);
-var
-  i, x: int;
-  n: TNoteKind;
-  id: string;
-begin
-  id := '';
-  // arg = "X]:on|off"
-  i := strStart;
-  n := hintMin;
-  while (i < length(arg)+strStart) and (arg[i] <> ']') do begin
-    addChar(id, arg[i]);
-    inc(i)
-  end;
-  if (i < length(arg)+strStart) and (arg[i] = ']') then
-    inc(i)
-  else
-    InvalidCmdLineOption(pass, arg, info);
-  if (i < length(arg)+strStart) and (arg[i] in [':', '=']) then
-    inc(i)
-  else
-    InvalidCmdLineOption(pass, arg, info);
-  if state = wHint then begin
-    x := findStr(msgs.HintsToStr, id);
-    if x >= 0 then
-      n := TNoteKind(x + ord(hintMin))
-    else
-      InvalidCmdLineOption(pass, arg, info)
-  end
-  else begin
-    x := findStr(msgs.WarningsToStr, id);
-    if x >= 0 then
-      n := TNoteKind(x + ord(warnMin))
-    else
-      InvalidCmdLineOption(pass, arg, info)
-  end;
-  case whichKeyword(ncopy(arg, i)) of
-    wOn: include(gNotes, n);
-    wOff: exclude(gNotes, n);
-    else liMessage(info, errOnOrOffExpectedButXFound, arg)
-  end
-end;
-
-function processPath(const path: string): string;
-begin
-  result := UnixToNativePath(format(path,
-    ['nimrod', getPrefixDir(), 'lib', libpath]))
-end;
-
-procedure processCompile(const filename: string);
-var
-  found, trunc, ext: string;
-begin
-  found := findFile(filename);
-  if found = '' then found := filename;
-  splitFilename(found, trunc, ext);
-  extccomp.addExternalFileToCompile(trunc);
-  extccomp.addFileToLink(completeCFilePath(trunc, false));
-end;
-
-procedure processSwitch(const switch, arg: string; pass: TCmdlinePass;
-                        const info: TLineInfo);
-var
-  theOS: TSystemOS;
-  cpu: TSystemCPU;
-  key, val, path: string;
-begin
-  case whichKeyword(switch) of
-    wPath, wP: begin
-      expectArg(switch, arg, pass, info);
-      path := processPath(arg);
-      {@discard} lists.IncludeStr(options.searchPaths, path)
-    end;
-    wOut, wO: begin
-      expectArg(switch, arg, pass, info);
-      options.outFile := arg;
-    end;
-    wDefine, wD: begin
-      expectArg(switch, arg, pass, info);
-      DefineSymbol(arg)
-    end;
-    wUndef, wU: begin
-      expectArg(switch, arg, pass, info);
-      UndefSymbol(arg)
-    end;
-    wCompile: begin
-      expectArg(switch, arg, pass, info);
-      if pass in {@set}[passCmd2, passPP] then
-        processCompile(arg);
-    end;
-    wLink: begin
-      expectArg(switch, arg, pass, info);
-      if pass in {@set}[passCmd2, passPP] then
-        addFileToLink(arg);
-    end;
-    wDebuginfo: include(gGlobalOptions, optCDebug);
-    wCompileOnly, wC: include(gGlobalOptions, optCompileOnly);
-    wNoLinking: include(gGlobalOptions, optNoLinking);
-    wForceBuild, wF: include(gGlobalOptions, optForceFullMake);
-    wGC: begin
-      case whichKeyword(arg) of
-        wBoehm: begin
-          include(gGlobalOptions, optBoehmGC);
-          exclude(gGlobalOptions, optRefcGC);
-          DefineSymbol('boehmgc');
-        end;
-        wRefc: begin
-          exclude(gGlobalOptions, optBoehmGC);
-          include(gGlobalOptions, optRefcGC)
-        end;
-        wNone: begin
-          exclude(gGlobalOptions, optRefcGC);
-          exclude(gGlobalOptions, optBoehmGC);
-          defineSymbol('nogc');
-        end
-        else
-          liMessage(info, errNoneBoehmRefcExpectedButXFound, arg)
-      end
-    end;
-    wWarnings, wW: ProcessOnOffSwitch({@set}[optWarns], arg, pass, info);
-    wWarning: ProcessSpecificNote(arg, wWarning, pass, info);
-    wHint: ProcessSpecificNote(arg, wHint, pass, info);
-    wHints: ProcessOnOffSwitch({@set}[optHints], arg, pass, info);
-    wCheckpoints: ProcessOnOffSwitch({@set}[optCheckpoints], arg, pass, info);
-    wStackTrace: ProcessOnOffSwitch({@set}[optStackTrace], arg, pass, info);
-    wLineTrace: ProcessOnOffSwitch({@set}[optLineTrace], arg, pass, info);
-    wDebugger: begin
-      ProcessOnOffSwitch({@set}[optEndb], arg, pass, info);
-      if optEndb in gOptions then
-        DefineSymbol('endb')
-      else
-        UndefSymbol('endb')
-    end;
-    wProfiler: begin
-      ProcessOnOffSwitch({@set}[optProfiler], arg, pass, info);
-      if optProfiler in gOptions then DefineSymbol('profiler')
-      else UndefSymbol('profiler')
-    end;
-    wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info);
-    wObjChecks: ProcessOnOffSwitch({@set}[optObjCheck], arg, pass, info);
-    wFieldChecks: ProcessOnOffSwitch({@set}[optFieldCheck], arg, pass, info);
-    wRangeChecks: ProcessOnOffSwitch({@set}[optRangeCheck], arg, pass, info);
-    wBoundChecks: ProcessOnOffSwitch({@set}[optBoundsCheck], arg, pass, info);
-    wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info);
-    wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info);
-    wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info);
-    wDeadCodeElim: ProcessOnOffSwitchG({@set}[optDeadCodeElim], arg, pass, info);
-    wOpt: begin
-      case whichKeyword(arg) of
-        wSpeed: begin
-          include(gOptions, optOptimizeSpeed);
-          exclude(gOptions, optOptimizeSize)
-        end;
-        wSize: begin
-          exclude(gOptions, optOptimizeSpeed);
-          include(gOptions, optOptimizeSize)
-        end;
-        wNone: begin
-          exclude(gOptions, optOptimizeSpeed);
-          exclude(gOptions, optOptimizeSize)
-        end
-        else
-          liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg)
-      end
-    end;
-    wApp: begin
-      case whichKeyword(arg) of
-        wGui: begin
-          include(gGlobalOptions, optGenGuiApp);
-          defineSymbol('guiapp')
-        end;
-        wConsole:
-          exclude(gGlobalOptions, optGenGuiApp);
-        wLib: begin
-          include(gGlobalOptions, optGenDynLib);
-          exclude(gGlobalOptions, optGenGuiApp);
-          defineSymbol('library')
-        end;
-        else
-          liMessage(info, errGuiConsoleOrLibExpectedButXFound, arg)
-      end
-    end;
-    wListDef: begin
-      if pass in {@set}[passCmd2, passPP] then
-        condsyms.listSymbols();
-    end;
-    wPassC, wT: begin
-      expectArg(switch, arg, pass, info);
-      if pass in {@set}[passCmd2, passPP] then
-        extccomp.addCompileOption(arg)
-    end;
-    wPassL, wL: begin
-      expectArg(switch, arg, pass, info);
-      if pass in {@set}[passCmd2, passPP] then
-        extccomp.addLinkOption(arg)
-    end;
-    wIndex: begin
-      expectArg(switch, arg, pass, info);
-      if pass in {@set}[passCmd2, passPP] then
-        gIndexFile := arg
-    end;
-    wImport: begin
-      expectArg(switch, arg, pass, info);
-      options.addImplicitMod(arg);
-    end;
-    wListCmd: include(gGlobalOptions, optListCmd);
-    wGenMapping: include(gGlobalOptions, optGenMapping);
-    wOS: begin
-      if (pass = passCmd1) then begin
-        theOS := platform.NameToOS(arg);
-        if theOS = osNone then
-          liMessage(info, errUnknownOS, arg);
-        if theOS <> platform.hostOS then begin
-          setTarget(theOS, targetCPU);
-          include(gGlobalOptions, optCompileOnly);
-          condsyms.InitDefines()
-        end
-      end
-    end;
-    wCPU: begin
-      if (pass = passCmd1) then begin
-        cpu := platform.NameToCPU(arg);
-        if cpu = cpuNone then
-          liMessage(info, errUnknownCPU, arg);
-        if cpu <> platform.hostCPU then begin
-          setTarget(targetOS, cpu);
-          include(gGlobalOptions, optCompileOnly);
-          condsyms.InitDefines()
-        end
-      end
-    end;
-    wRun, wR: include(gGlobalOptions, optRun);
-    wVerbosity: begin
-      expectArg(switch, arg, pass, info);
-      gVerbosity := parseInt(arg);
-    end;
-    wVersion, wV: writeVersionInfo(pass);
-    wAdvanced: writeAdvancedUsage(pass);
-    wHelp, wH: helpOnError(pass);
-    wSymbolFiles: ProcessOnOffSwitchG({@set}[optSymbolFiles], arg, pass, info);
-    wSkipCfg: include(gGlobalOptions, optSkipConfigFile);
-    wSkipProjCfg: include(gGlobalOptions, optSkipProjConfigFile);
-    wGenScript: include(gGlobalOptions, optGenScript);
-    wLib: begin
-      expectArg(switch, arg, pass, info);
-      libpath := processPath(arg)
-    end;
-    wPutEnv: begin
-      expectArg(switch, arg, pass, info);
-      splitSwitch(arg, key, val, pass, info);
-      nos.putEnv(key, val);
-    end;
-    wCC: begin
-      expectArg(switch, arg, pass, info);
-      setCC(arg)
-    end;
-    wMaxErr: begin
-      expectArg(switch, arg, pass, info);
-      gErrorMax := parseInt(arg);
-    end;
-    else if strutils.find(switch, '.') >= strStart then
-      options.setConfigVar(switch, arg)
-    else
-      InvalidCmdLineOption(pass, switch, info)
-  end
-end;
-
-procedure ProcessCommand(const switch: string; pass: TCmdLinePass);
-var
-  cmd, arg: string;
-  info: TLineInfo;
-begin
-  info := newLineInfo('command line', 1, 1);
-  splitSwitch(switch, cmd, arg, pass, info);
-  ProcessSwitch(cmd, arg, pass, info)
-end;
-
-end.
+//[[[end]]]

+  ;

+

+function getCommandLineDesc: string;

+begin

+  result := format(HelpMessage, [VersionAsString, 

+    platform.os[platform.hostOS].name, cpu[platform.hostCPU].name]) +{&} Usage

+end;

+

+var

+  helpWritten: boolean;  // BUGFIX 19

+  versionWritten: boolean;

+  advHelpWritten: boolean;

+

+procedure HelpOnError(pass: TCmdLinePass);

+begin

+  if (pass = passCmd1) and not helpWritten then begin

+    // BUGFIX 19

+    MessageOut(getCommandLineDesc());

+    helpWritten := true

+  end

+end;

+

+procedure writeAdvancedUsage(pass: TCmdLinePass);

+begin

+  if (pass = passCmd1) and not advHelpWritten then begin

+    // BUGFIX 19

+    MessageOut(format(HelpMessage, [VersionAsString, 

+                                    platform.os[platform.hostOS].name,

+                                    cpu[platform.hostCPU].name]) +{&}

+                                    AdvancedUsage);

+    advHelpWritten := true;

+    helpWritten := true;

+    halt(0);

+  end

+end;

+

+procedure writeVersionInfo(pass: TCmdLinePass);

+begin

+  if (pass = passCmd1) and not versionWritten then begin

+    versionWritten := true;

+    helpWritten := true;

+    messageOut(format(HelpMessage, [VersionAsString, 

+                                    platform.os[platform.hostOS].name,

+                                    cpu[platform.hostCPU].name]))

+  end

+end;

+

+procedure writeCommandLineUsage;

+begin

+  if not helpWritten then begin

+    messageOut(getCommandLineDesc());

+    helpWritten := true

+  end

+end;

+

+procedure InvalidCmdLineOption(pass: TCmdLinePass; const switch: string;

+                               const info: TLineInfo);

+begin

+  liMessage(info, errInvalidCmdLineOption, switch)

+end;

+

+procedure splitSwitch(const switch: string; out cmd, arg: string;

+                      pass: TCmdLinePass; const info: TLineInfo);

+var

+  i: int;

+begin

+  cmd := '';

+  i := strStart;

+  if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i);

+  if (i < length(switch)+strStart) and (switch[i] = '-') then inc(i);

+  while i < length(switch) + strStart do begin

+    case switch[i] of

+      'a'..'z', 'A'..'Z', '0'..'9', '_', '.':

+        addChar(cmd, switch[i]);

+      else break;

+    end;

+    inc(i);

+  end;

+  if i >= length(switch) + strStart then

+    arg := ''

+  else if switch[i] in [':', '=', '['] then

+    arg := ncopy(switch, i + 1)

+  else

+    InvalidCmdLineOption(pass, switch, info)

+end;

+

+procedure ProcessOnOffSwitch(const op: TOptions; const arg: string;

+                             pass: TCmdlinePass; const info: TLineInfo);

+begin

+  case whichKeyword(arg) of

+    wOn:  gOptions := gOptions + op;

+    wOff: gOptions := gOptions - op;

+    else  liMessage(info, errOnOrOffExpectedButXFound, arg)

+  end

+end;

+

+procedure ProcessOnOffSwitchG(const op: TGlobalOptions; const arg: string;

+                              pass: TCmdlinePass; const info: TLineInfo);

+begin

+  case whichKeyword(arg) of

+    wOn:  gGlobalOptions := gGlobalOptions + op;

+    wOff: gGlobalOptions := gGlobalOptions - op;

+    else  liMessage(info, errOnOrOffExpectedButXFound, arg)

+  end

+end;

+

+procedure ExpectArg(const switch, arg: string; pass: TCmdLinePass;

+                    const info: TLineInfo);

+begin

+  if (arg = '') then

+    liMessage(info, errCmdLineArgExpected, switch)

+end;

+

+procedure ExpectNoArg(const switch, arg: string; pass: TCmdLinePass;

+                      const info: TLineInfo);

+begin

+  if (arg <> '') then

+    liMessage(info, errCmdLineNoArgExpected, switch)

+end;

+

+procedure ProcessSpecificNote(const arg: string; state: TSpecialWord;

+                              pass: TCmdlinePass; const info: TLineInfo);

+var

+  i, x: int;

+  n: TNoteKind;

+  id: string;

+begin

+  id := '';

+  // arg = "X]:on|off"

+  i := strStart;

+  n := hintMin;

+  while (i < length(arg)+strStart) and (arg[i] <> ']') do begin

+    addChar(id, arg[i]);

+    inc(i)

+  end;

+  if (i < length(arg)+strStart) and (arg[i] = ']') then

+    inc(i)

+  else

+    InvalidCmdLineOption(pass, arg, info);

+  if (i < length(arg)+strStart) and (arg[i] in [':', '=']) then

+    inc(i)

+  else

+    InvalidCmdLineOption(pass, arg, info);

+  if state = wHint then begin

+    x := findStr(msgs.HintsToStr, id);

+    if x >= 0 then

+      n := TNoteKind(x + ord(hintMin))

+    else

+      InvalidCmdLineOption(pass, arg, info)

+  end

+  else begin

+    x := findStr(msgs.WarningsToStr, id);

+    if x >= 0 then

+      n := TNoteKind(x + ord(warnMin))

+    else

+      InvalidCmdLineOption(pass, arg, info)

+  end;

+  case whichKeyword(ncopy(arg, i)) of

+    wOn: include(gNotes, n);

+    wOff: exclude(gNotes, n);

+    else liMessage(info, errOnOrOffExpectedButXFound, arg)

+  end

+end;

+

+function processPath(const path: string): string;

+begin

+  result := UnixToNativePath(format(path,

+    ['nimrod', getPrefixDir(), 'lib', libpath]))

+end;

+

+procedure processCompile(const filename: string);

+var

+  found, trunc, ext: string;

+begin

+  found := findFile(filename);

+  if found = '' then found := filename;

+  splitFilename(found, trunc, ext);

+  extccomp.addExternalFileToCompile(trunc);

+  extccomp.addFileToLink(completeCFilePath(trunc, false));

+end;

+

+procedure processSwitch(const switch, arg: string; pass: TCmdlinePass;

+                        const info: TLineInfo);

+var

+  theOS: TSystemOS;

+  cpu: TSystemCPU;

+  key, val, path: string;

+begin

+  case whichKeyword(switch) of

+    wPath, wP: begin

+      expectArg(switch, arg, pass, info);

+      path := processPath(arg);

+      {@discard} lists.IncludeStr(options.searchPaths, path)

+    end;

+    wOut, wO: begin

+      expectArg(switch, arg, pass, info);

+      options.outFile := arg;

+    end;

+    wDefine, wD: begin

+      expectArg(switch, arg, pass, info);

+      DefineSymbol(arg)

+    end;

+    wUndef, wU: begin

+      expectArg(switch, arg, pass, info);

+      UndefSymbol(arg)

+    end;

+    wCompile: begin

+      expectArg(switch, arg, pass, info);

+      if pass in {@set}[passCmd2, passPP] then

+        processCompile(arg);

+    end;

+    wLink: begin

+      expectArg(switch, arg, pass, info);

+      if pass in {@set}[passCmd2, passPP] then

+        addFileToLink(arg);

+    end;

+    wDebuginfo: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optCDebug);

+    end;

+    wCompileOnly, wC: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optCompileOnly);

+    end;

+    wNoLinking: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optNoLinking);

+    end;

+    wForceBuild, wF: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optForceFullMake);

+    end;

+    wGC: begin

+      expectArg(switch, arg, pass, info);

+      case whichKeyword(arg) of

+        wBoehm: begin

+          include(gGlobalOptions, optBoehmGC);

+          exclude(gGlobalOptions, optRefcGC);

+          DefineSymbol('boehmgc');

+        end;

+        wRefc: begin

+          exclude(gGlobalOptions, optBoehmGC);

+          include(gGlobalOptions, optRefcGC)

+        end;

+        wNone: begin

+          exclude(gGlobalOptions, optRefcGC);

+          exclude(gGlobalOptions, optBoehmGC);

+          defineSymbol('nogc');

+        end

+        else

+          liMessage(info, errNoneBoehmRefcExpectedButXFound, arg)

+      end

+    end;

+    wWarnings, wW: ProcessOnOffSwitch({@set}[optWarns], arg, pass, info);

+    wWarning: ProcessSpecificNote(arg, wWarning, pass, info);

+    wHint: ProcessSpecificNote(arg, wHint, pass, info);

+    wHints: ProcessOnOffSwitch({@set}[optHints], arg, pass, info);

+    wCheckpoints: ProcessOnOffSwitch({@set}[optCheckpoints], arg, pass, info);

+    wStackTrace: ProcessOnOffSwitch({@set}[optStackTrace], arg, pass, info);

+    wLineTrace: ProcessOnOffSwitch({@set}[optLineTrace], arg, pass, info);

+    wDebugger: begin

+      ProcessOnOffSwitch({@set}[optEndb], arg, pass, info);

+      if optEndb in gOptions then

+        DefineSymbol('endb')

+      else

+        UndefSymbol('endb')

+    end;

+    wProfiler: begin

+      ProcessOnOffSwitch({@set}[optProfiler], arg, pass, info);

+      if optProfiler in gOptions then DefineSymbol('profiler')

+      else UndefSymbol('profiler')

+    end;

+    wChecks, wX: ProcessOnOffSwitch(checksOptions, arg, pass, info);

+    wObjChecks: ProcessOnOffSwitch({@set}[optObjCheck], arg, pass, info);

+    wFieldChecks: ProcessOnOffSwitch({@set}[optFieldCheck], arg, pass, info);

+    wRangeChecks: ProcessOnOffSwitch({@set}[optRangeCheck], arg, pass, info);

+    wBoundChecks: ProcessOnOffSwitch({@set}[optBoundsCheck], arg, pass, info);

+    wOverflowChecks: ProcessOnOffSwitch({@set}[optOverflowCheck], arg, pass, info);

+    wLineDir: ProcessOnOffSwitch({@set}[optLineDir], arg, pass, info);

+    wAssertions, wA: ProcessOnOffSwitch({@set}[optAssert], arg, pass, info);

+    wDeadCodeElim: ProcessOnOffSwitchG({@set}[optDeadCodeElim], arg, pass, info);

+    wOpt: begin

+      expectArg(switch, arg, pass, info);

+      case whichKeyword(arg) of

+        wSpeed: begin

+          include(gOptions, optOptimizeSpeed);

+          exclude(gOptions, optOptimizeSize)

+        end;

+        wSize: begin

+          exclude(gOptions, optOptimizeSpeed);

+          include(gOptions, optOptimizeSize)

+        end;

+        wNone: begin

+          exclude(gOptions, optOptimizeSpeed);

+          exclude(gOptions, optOptimizeSize)

+        end

+        else

+          liMessage(info, errNoneSpeedOrSizeExpectedButXFound, arg)

+      end

+    end;

+    wApp: begin

+      expectArg(switch, arg, pass, info);

+      case whichKeyword(arg) of

+        wGui: begin

+          include(gGlobalOptions, optGenGuiApp);

+          defineSymbol('guiapp')

+        end;

+        wConsole:

+          exclude(gGlobalOptions, optGenGuiApp);

+        wLib: begin

+          include(gGlobalOptions, optGenDynLib);

+          exclude(gGlobalOptions, optGenGuiApp);

+          defineSymbol('library')

+        end;

+        else

+          liMessage(info, errGuiConsoleOrLibExpectedButXFound, arg)

+      end

+    end;

+    wListDef: begin

+      expectNoArg(switch, arg, pass, info);

+      if pass in {@set}[passCmd2, passPP] then

+        condsyms.listSymbols();

+    end;

+    wPassC, wT: begin

+      expectArg(switch, arg, pass, info);

+      if pass in {@set}[passCmd2, passPP] then

+        extccomp.addCompileOption(arg)

+    end;

+    wPassL, wL: begin

+      expectArg(switch, arg, pass, info);

+      if pass in {@set}[passCmd2, passPP] then

+        extccomp.addLinkOption(arg)

+    end;

+    wIndex: begin

+      expectArg(switch, arg, pass, info);

+      if pass in {@set}[passCmd2, passPP] then

+        gIndexFile := arg

+    end;

+    wImport: begin

+      expectArg(switch, arg, pass, info);

+      options.addImplicitMod(arg);

+    end;

+    wListCmd: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optListCmd);

+    end;

+    wGenMapping: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optGenMapping);

+    end;

+    wOS: begin

+      expectArg(switch, arg, pass, info);

+      if (pass = passCmd1) then begin

+        theOS := platform.NameToOS(arg);

+        if theOS = osNone then

+          liMessage(info, errUnknownOS, arg);

+        if theOS <> platform.hostOS then begin

+          setTarget(theOS, targetCPU);

+          include(gGlobalOptions, optCompileOnly);

+          condsyms.InitDefines()

+        end

+      end

+    end;

+    wCPU: begin

+      expectArg(switch, arg, pass, info);

+      if (pass = passCmd1) then begin

+        cpu := platform.NameToCPU(arg);

+        if cpu = cpuNone then

+          liMessage(info, errUnknownCPU, arg);

+        if cpu <> platform.hostCPU then begin

+          setTarget(targetOS, cpu);

+          include(gGlobalOptions, optCompileOnly);

+          condsyms.InitDefines()

+        end

+      end

+    end;

+    wRun, wR: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optRun);

+    end;

+    wVerbosity: begin

+      expectArg(switch, arg, pass, info);

+      gVerbosity := parseInt(arg);

+    end;

+    wVersion, wV: begin

+      expectNoArg(switch, arg, pass, info);

+      writeVersionInfo(pass);

+    end;

+    wAdvanced: begin

+      expectNoArg(switch, arg, pass, info);

+      writeAdvancedUsage(pass);

+    end;

+    wHelp, wH: begin

+      expectNoArg(switch, arg, pass, info);

+      helpOnError(pass);

+    end;

+    wSymbolFiles: ProcessOnOffSwitchG({@set}[optSymbolFiles], arg, pass, info);

+    wSkipCfg: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optSkipConfigFile);

+    end;

+    wSkipProjCfg: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optSkipProjConfigFile);

+    end;

+    wGenScript: begin

+      expectNoArg(switch, arg, pass, info);

+      include(gGlobalOptions, optGenScript);

+    end;

+    wLib: begin

+      expectArg(switch, arg, pass, info);

+      libpath := processPath(arg)

+    end;

+    wPutEnv: begin

+      expectArg(switch, arg, pass, info);

+      splitSwitch(arg, key, val, pass, info);

+      nos.putEnv(key, val);

+    end;

+    wCC: begin

+      expectArg(switch, arg, pass, info);

+      setCC(arg)

+    end;

+    wMaxErr: begin

+      expectArg(switch, arg, pass, info);

+      gErrorMax := parseInt(arg);

+    end;

+    else if strutils.find(switch, '.') >= strStart then

+      options.setConfigVar(switch, arg)

+    else

+      InvalidCmdLineOption(pass, switch, info)

+  end

+end;

+

+procedure ProcessCommand(const switch: string; pass: TCmdLinePass);

+var

+  cmd, arg: string;

+  info: TLineInfo;

+begin

+  info := newLineInfo('command line', 1, 1);

+  splitSwitch(switch, cmd, arg, pass, info);

+  ProcessSwitch(cmd, arg, pass, info)

+end;

+

+end.

diff --git a/nim/condsyms.pas b/nim/condsyms.pas
index 9c5d64d4b..1df513bbc 100644
--- a/nim/condsyms.pas
+++ b/nim/condsyms.pas
@@ -15,7 +15,7 @@ unit condsyms;
 interface
 
 uses
-  nsystem, ast, astalgo, msgs, hashes, platform, strutils, idents;
+  nsystem, ast, astalgo, msgs, nhashes, platform, strutils, idents;
 
 var
   gSymbols: TStrTable;
diff --git a/nim/docgen.pas b/nim/docgen.pas
index 15969f51d..784ab6c6c 100644
--- a/nim/docgen.pas
+++ b/nim/docgen.pas
@@ -18,7 +18,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, charsets, ast, astalgo, strutils, hashes, options, nversion, msgs,
+  nsystem, charsets, ast, astalgo, strutils, nhashes, options, nversion, msgs,
   nos, ropes, idents, wordrecg, nmath, pnimsyn, rnimsyn, scanner, rst, ntime,
   highlite;
 
@@ -722,6 +722,16 @@ begin
   end
 end;
 
+function renderContainer(d: PDoc; n: PRstNode): PRope;
+var
+  arg: PRope;
+begin
+  result := renderRstToHtml(d, n.sons[2]);
+  arg := toRope(strip(getArgument(n)));
+  if arg = nil then result := ropef('<div>$1</div>', [result])
+  else result := ropef('<div class="$1">$2</div>', [arg, result])  
+end;
+
 function renderRstToHtml(d: PDoc; n: PRstNode): PRope;
 var
   outer, inner: string;
@@ -811,6 +821,10 @@ begin
       result := renderCodeBlock(d, n);
       exit
     end;
+    rnContainer: begin 
+      result := renderContainer(d, n);
+      exit
+    end;
     rnSubstitutionReferences, rnSubstitutionDef: outer := '|$1|';
     rnDirective: outer := '';
 
diff --git a/nim/ecmasgen.pas b/nim/ecmasgen.pas
index c9dfcfe25..2eecfba71 100644
--- a/nim/ecmasgen.pas
+++ b/nim/ecmasgen.pas
@@ -17,7 +17,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, ast, astalgo, strutils, hashes, trees, platform, magicsys,
+  nsystem, ast, astalgo, strutils, nhashes, trees, platform, magicsys,
   extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents,
   lists, types, nos, ntime, ropes, nmath, passes, ccgutils, wordrecg, rnimsyn,
   rodread;
diff --git a/nim/evals.pas b/nim/evals.pas
index f9ca85c8f..218046c7e 100644
--- a/nim/evals.pas
+++ b/nim/evals.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -157,7 +157,7 @@ begin
 end;
 
 var
-  gWhileCounter: int;  // Use a counter to prevend endless loops!
+  gWhileCounter: int;  // Use a counter to prevent endless loops!
                        // We make this counter global, because otherwise
                        // nested loops could make the compiler extremely slow.
   gNestedEvals: int;   // count the recursive calls to ``evalAux`` to prevent
@@ -390,7 +390,7 @@ begin
         stackTrace(c, n, errIndexOutOfBounds);
     end;
     else
-      stackTrace(c, n, errIndexNoIntType);
+      stackTrace(c, n, errNilAccess);
   end
 end;
 
@@ -506,7 +506,8 @@ begin
       result := emptyNode
     end
   end;
-  if result = nil then InternalError(n.info, 'evalSym: ' + n.sym.name.s);
+  if result = nil then 
+    stackTrace(c, n, errCannotInterpretNodeX, n.sym.name.s);
 end;
 
 function evalIncDec(c: PEvalContext; n: PNode; sign: biggestInt): PNode;
@@ -563,8 +564,12 @@ function evalDeref(c: PEvalContext; n: PNode): PNode;
 begin
   result := evalAux(c, n.sons[0]);
   if result.kind = nkExceptBranch then exit;
-  if result.kind <> nkRefTy then InternalError(n.info, 'evalDeref');
-  result := result.sons[0];
+  case result.kind of
+    nkExceptBranch: exit;
+    nkNilLit: stackTrace(c, n, errNilAccess);
+    nkRefTy: result := result.sons[0];
+    else InternalError(n.info, 'evalDeref ' + nodeKindToStr[result.kind]);
+  end;
 end;
 
 function evalAddr(c: PEvalContext; n: PNode): PNode;
@@ -574,7 +579,6 @@ var
 begin
   result := evalAux(c, n.sons[0]);
   if result.kind = nkExceptBranch then exit;
-  if result.kind <> nkRefTy then InternalError(n.info, 'evalDeref');
   a := result;
   t := newType(tyPtr, c.module);
   addSon(t, a.typ);
@@ -732,6 +736,7 @@ end;
 function evalSetLengthSeq(c: PEvalContext; n: PNode): PNode;
 var
   a, b: PNode;
+  newLen, oldLen, i: int;
 begin
   result := evalAux(c, n.sons[1]);
   if result.kind = nkExceptBranch then exit;
@@ -739,8 +744,12 @@ begin
   result := evalAux(c, n.sons[2]);
   if result.kind = nkExceptBranch then exit;
   b := result;
-  if a.kind = nkBracket then setLength(a.sons, int(getOrdValue(b)))
-  else InternalError(n.info, 'evalSetLengthSeq');
+  if a.kind <> nkBracket then InternalError(n.info, 'evalSetLengthSeq');
+  newLen := int(getOrdValue(b));
+  oldLen := sonsLen(a);
+  setLength(a.sons, newLen);
+  for i := oldLen to newLen-1 do
+    a.sons[i] := getNullValue(skipVarGeneric(n.sons[1].typ), n.info);
   result := emptyNode
 end;
 
@@ -758,10 +767,13 @@ begin
   b := result;
 
   t := skipVarGeneric(n.sons[1].typ);
-  result := newNodeIT(nkBracket, n.info, t);
+  if a.kind = nkEmpty then InternalError(n.info, 'first parameter is empty');
+  a.kind := nkBracket;
+  a.info := n.info;
+  a.typ := t;
   for i := 0 to int(getOrdValue(b))-1 do
-    addSon(result, getNullValue(t.sons[0], n.info));
-  // XXX: assign to `a`? result := emptyNode
+    addSon(a, getNullValue(t.sons[0], n.info));
+  result := emptyNode
 end;
 
 function evalAssert(c: PEvalContext; n: PNode): PNode;
@@ -907,7 +919,7 @@ end;
 function evalMagicOrCall(c: PEvalContext; n: PNode): PNode;
 var
   m: TMagic;
-  a, b: PNode;
+  a, b, cc: PNode;
   k: biggestInt;
   i: int;
 begin
@@ -1179,22 +1191,35 @@ begin
     mNError: begin
       result := evalAux(c, n.sons[1]);
       if result.kind = nkExceptBranch then exit;
-      liMessage(n.info, errUser, getStrValue(result));
+      stackTrace(c, n, errUser, getStrValue(result));
       result := emptyNode
     end;
     mConStrStr: result := evalConStrStr(c, n);
     mRepr: result := evalRepr(c, n);
+    mNewString: begin
+      result := evalAux(c, n.sons[1]);
+      if result.kind = nkExceptBranch then exit;
+      a := result;
+      result := newNodeIT(nkStrLit, n.info, n.typ);
+      result.strVal := newString(int(getOrdValue(a)));
+    end;
     else begin
       result := evalAux(c, n.sons[1]);
       if result.kind = nkExceptBranch then exit;
       a := result;
+      b := nil;
+      cc := nil;
       if sonsLen(n) > 2 then begin
         result := evalAux(c, n.sons[2]);
         if result.kind = nkExceptBranch then exit;
-      end
-      else
-        result := nil;
-      result := evalOp(m, n, a, result);
+        b := result;
+        if sonsLen(n) > 3 then begin
+          result := evalAux(c, n.sons[3]);
+          if result.kind = nkExceptBranch then exit;
+          cc := result;
+        end
+      end;
+      result := evalOp(m, n, a, b, cc);
     end
   end
 end;
@@ -1213,7 +1238,7 @@ begin
     nkNilLit: result := n; // end of atoms
 
     nkCall, nkHiddenCallConv, nkMacroStmt: result := evalMagicOrCall(c, n);
-    nkCurly, nkBracket: begin
+    nkCurly, nkBracket, nkRange: begin
       result := copyNode(n);
       for i := 0 to sonsLen(n)-1 do addSon(result, evalAux(c, n.sons[i]));
     end;
diff --git a/nim/extccomp.pas b/nim/extccomp.pas
index f51e5f690..a53ad1c10 100644
--- a/nim/extccomp.pas
+++ b/nim/extccomp.pas
@@ -15,8 +15,8 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, charsets, lists, ropes, nos, strutils, platform, condsyms, options,
-  msgs;
+  nsystem, charsets, lists, ropes, nos, strutils, osproc, platform, condsyms, 
+  options, msgs;
 
 // some things are read in from the configuration file
 
@@ -387,7 +387,7 @@ procedure execExternalProgram(const cmd: string);
 begin
   if (optListCmd in gGlobalOptions) or (gVerbosity > 0) then
     MessageOut('Executing: ' +{&} nl +{&} cmd);
-  if executeShellCommand(cmd) <> 0 then
+  if executeCommand(cmd) <> 0 then
     rawMessage(errExecutionOfProgramFailed);
 end;
 
diff --git a/nim/hashtest.pas b/nim/hashtest.pas
index ba7a62372..7e93ca5bf 100644
--- a/nim/hashtest.pas
+++ b/nim/hashtest.pas
@@ -3,7 +3,7 @@ program hashtest;
 {$include 'config.inc'}
 
 uses
-  hashes;
+  nhashes;
 
 begin
   writeln(output, getNormalizedHash(ParamStr(1)));
diff --git a/nim/highlite.pas b/nim/highlite.pas
index 5ef4acc12..ad7a6f724 100644
--- a/nim/highlite.pas
+++ b/nim/highlite.pas
@@ -17,7 +17,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  charsets, nsystem, sysutils, hashes, options, msgs, strutils, platform,
+  charsets, nsystem, sysutils, nhashes, options, msgs, strutils, platform,
   idents, lexbase, wordrecg, scanner;
 
 type
diff --git a/nim/idents.pas b/nim/idents.pas
index c0e4c994f..c1c1755e9 100644
--- a/nim/idents.pas
+++ b/nim/idents.pas
@@ -17,7 +17,7 @@ unit idents;
 interface
 
 uses
-  hashes, nsystem, strutils;
+  nhashes, nsystem, strutils;
 
 type
   TIdObj = object(NObject)
diff --git a/nim/interact.pas b/nim/interact.pas
index ac238107f..aab3c7fc2 100644
--- a/nim/interact.pas
+++ b/nim/interact.pas
@@ -15,7 +15,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, llstream, strutils, charsets, ropes, strtabs, msgs;
+  nsystem, llstream, strutils, charsets, ropes, nstrtabs, msgs;
 
 implementation
 
diff --git a/nim/magicsys.pas b/nim/magicsys.pas
index 7a717e61d..462912995 100644
--- a/nim/magicsys.pas
+++ b/nim/magicsys.pas
@@ -16,7 +16,7 @@ interface
 
 uses
   nsystem,
-  ast, astalgo, hashes, msgs, platform, nversion, ntime, idents, rodread;
+  ast, astalgo, nhashes, msgs, platform, nversion, ntime, idents, rodread;
 
 var // magic symbols in the system module:
   SystemModule: PSym;
diff --git a/nim/main.pas b/nim/main.pas
index c888e5c3c..b1c58c2b9 100644
--- a/nim/main.pas
+++ b/nim/main.pas
@@ -152,7 +152,7 @@ begin
   semanticPasses();
   registerPass(cgen.cgenPass());
   registerPass(rodwrite.rodwritePass());
-  registerPass(cleanupPass());
+  //registerPass(cleanupPass());
   compileProject(filename);
   //for i := low(TTypeKind) to high(TTypeKind) do
   //  MessageOut('kind: ' +{&} typeKindToStr[i] +{&} ' = ' +{&} toString(sameTypeA[i]));
diff --git a/nim/msgs.pas b/nim/msgs.pas
index 0eb1651d9..53e1b3388 100644
--- a/nim/msgs.pas
+++ b/nim/msgs.pas
@@ -96,10 +96,10 @@ type
     errAttemptToRedefine,
     errStmtInvalidAfterReturn,
     errStmtExpected,
-    errYieldOnlyInInterators,
     errInvalidLabel,
     errInvalidCmdLineOption,
     errCmdLineArgExpected,
+    errCmdLineNoArgExpected,
     errInvalidVarSubstitution,
     errUnknownVar,
     errUnknownCcompiler,
@@ -138,7 +138,7 @@ type
     errStaticAssertCannotBeEval,
     errDotRequiresRecordOrObjectType,
     errUndeclaredFieldX,
-    errIndexNoIntType,
+    errNilAccess,
     errIndexOutOfBounds,
     errIndexTypesDoNotMatch,
     errBracketsInvalidForType,
@@ -348,17 +348,17 @@ const
     'exception expected',
     'exception already handled',
     '''return'' only allowed in routine',
-    '''yield'' only allowed in iterator',
+    '''yield'' only allowed in a loop of an iterator',
     'invalid number of ''yield'' expresions',
     '''return'' not allowed in iterator',
     'current routine cannot return an expression',
     'attempt to redefine ''$1''',
     'statement not allowed after ''return'', ''break'' or ''raise''',
     'statement expected',
-    '''yield'' statement is only allowed in iterators',
     '''$1'' is no label',
     'invalid command line option: ''$1''',
     'argument for command line option expected: ''$1''',
+    'invalid argument for command line option: ''$1''',
     'invalid variable substitution in ''$1''',
     'unknown variable: ''$1''',
     'unknown C compiler: ''$1''',
@@ -397,7 +397,7 @@ const
     'argument to ''staticAssert'' cannot be evaluated at compile time',
     '''.'' requires a record or object type',
     'undeclared field: ''$1''',
-    'index has to be an integer type',
+    'attempt to access a nil address',
     'index out of bounds',
     'index types do not match',
     '''[]'' operator invalid for this type',
diff --git a/nim/hashes.pas b/nim/nhashes.pas
index 0d7eb205d..0564f6f47 100644
--- a/nim/hashes.pas
+++ b/nim/nhashes.pas
@@ -6,7 +6,7 @@
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
-unit hashes;
+unit nhashes;
 
 {$include 'config.inc'}
 
diff --git a/nim/strtabs.pas b/nim/nstrtabs.pas
index 4fcf32891..bcb10f2ed 100644
--- a/nim/strtabs.pas
+++ b/nim/nstrtabs.pas
@@ -6,7 +6,7 @@
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
 //
-unit strtabs;
+unit nstrtabs;
 
 // String tables.
 
@@ -15,7 +15,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, nos, hashes, strutils;
+  nsystem, nos, nhashes, strutils;
 
 type
   TStringTableMode = (
@@ -93,9 +93,9 @@ end;
 function myhash(t: PStringTable; const key: string): THash;
 begin
   case t.mode of
-    modeCaseSensitive: result := hashes.GetHashStr(key);
-    modeCaseInsensitive: result := hashes.GetHashStrCI(key);
-    modeStyleInsensitive: result := hashes.getNormalizedHash(key);
+    modeCaseSensitive: result := nhashes.GetHashStr(key);
+    modeCaseInsensitive: result := nhashes.GetHashStrCI(key);
+    modeStyleInsensitive: result := nhashes.getNormalizedHash(key);
   end
 end;
 
diff --git a/nim/nversion.pas b/nim/nversion.pas
index de0ad2b79..ae6392db9 100644
--- a/nim/nversion.pas
+++ b/nim/nversion.pas
@@ -1,42 +1,42 @@
-//
-//
-//           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
-//
-//    See the file "copying.txt", included in this
-//    distribution, for details about the copyright.
-//
-
-unit nversion;
-
-// this unit implements the version handling
-
-interface
-
-{$include 'config.inc'}
-
-uses
-  strutils;
-
-const
-  MaxSetElements = 1 shl 16; // (2^16) to support unicode character sets?
-  defaultAsmMarkerSymbol = '!';
-
-  //[[[cog
-  //from koch import NIMROD_VERSION
-  //from string import split
-  //cog.outl("VersionAsString = '%s';" % NIMROD_VERSION)
-  //ver = split(NIMROD_VERSION, '.')
-  //cog.outl('VersionMajor = %s;' % ver[0])
-  //cog.outl('VersionMinor = %s;' % ver[1])
-  //cog.outl('VersionPatch = %s;' % ver[2])
-  //]]]
-  VersionAsString = '0.7.6';
+//

+//

+//           The Nimrod Compiler

+//        (c) Copyright 2008 Andreas Rumpf

+//

+//    See the file "copying.txt", included in this

+//    distribution, for details about the copyright.

+//

+

+unit nversion;

+

+// this unit implements the version handling

+

+interface

+

+{$include 'config.inc'}

+

+uses

+  strutils;

+

+const

+  MaxSetElements = 1 shl 16; // (2^16) to support unicode character sets?

+  defaultAsmMarkerSymbol = '!';

+

+  //[[[cog

+  //from koch import NIMROD_VERSION

+  //from string import split

+  //cog.outl("VersionAsString = '%s';" % NIMROD_VERSION)

+  //ver = split(NIMROD_VERSION, '.')

+  //cog.outl('VersionMajor = %s;' % ver[0])

+  //cog.outl('VersionMinor = %s;' % ver[1])

+  //cog.outl('VersionPatch = %s;' % ver[2])

+  //]]]

+  VersionAsString = '0.7.8';
   VersionMajor = 0;
   VersionMinor = 7;
-  VersionPatch = 6;
-  //[[[[end]]]]
-
-implementation
-
-end.
+  VersionPatch = 8;
+  //[[[[end]]]]

+

+implementation

+

+end.

diff --git a/nim/options.pas b/nim/options.pas
index d6f6d14da..f84d8458c 100644
--- a/nim/options.pas
+++ b/nim/options.pas
@@ -13,7 +13,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, nos, lists, strutils, strtabs;
+  nsystem, nos, lists, strutils, nstrtabs;
 
 type
   // please make sure we have under 32 options
@@ -150,12 +150,12 @@ end;
 
 function getConfigVar(const key: string): string;
 begin
-  result := strtabs.get(gConfigVars, key);
+  result := nstrtabs.get(gConfigVars, key);
 end;
 
 procedure setConfigVar(const key, val: string);
 begin
-  strtabs.put(gConfigVars, key, val);
+  nstrtabs.put(gConfigVars, key, val);
 end;
 
 function getOutFile(const filename, ext: string): string;
diff --git a/nim/osproc.pas b/nim/osproc.pas
new file mode 100644
index 000000000..dd6bd10f0
--- /dev/null
+++ b/nim/osproc.pas
@@ -0,0 +1,30 @@
+//

+//

+//           The Nimrod Compiler

+//        (c) Copyright 2009 Andreas Rumpf

+//

+//    See the file "copying.txt", included in this

+//    distribution, for details about the copyright.

+//

+unit osproc;

+

+// This module provides Nimrod's osproc module in Pascal

+// Note: Only implement what is really needed here!

+

+interface

+

+{$include 'config.inc'}

+

+uses

+  nsystem, nos;

+

+function executeCommand(const cmd: string): int;

+

+implementation

+

+function executeCommand(const cmd: string): int;

+begin

+  result := executeShellCommand(cmd);

+end;

+

+end.

diff --git a/nim/parsecfg.pas b/nim/parsecfg.pas
index 3c10cc8fc..620335aa6 100644
--- a/nim/parsecfg.pas
+++ b/nim/parsecfg.pas
@@ -17,7 +17,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, charsets, llstream, sysutils, hashes, strutils, lexbase;
+  nsystem, charsets, llstream, sysutils, nhashes, strutils, lexbase;
 
 type
   TCfgEventKind = (
diff --git a/nim/paslex.pas b/nim/paslex.pas
index c0136e4d8..da9283163 100644
--- a/nim/paslex.pas
+++ b/nim/paslex.pas
@@ -17,7 +17,7 @@ interface
 
 uses
   charsets, nsystem, sysutils,
-  hashes, options, msgs, strutils, platform, idents,
+  nhashes, options, msgs, strutils, platform, idents,
   lexbase, wordrecg, scanner;
 
 const
diff --git a/nim/pragmas.pas b/nim/pragmas.pas
index 9a60e6bd3..df48f27c9 100644
--- a/nim/pragmas.pas
+++ b/nim/pragmas.pas
@@ -1,7 +1,7 @@
 //
 //
 //           The Nimrod Compiler
-//        (c) Copyright 2008 Andreas Rumpf
+//        (c) Copyright 2009 Andreas Rumpf
 //
 //    See the file "copying.txt", included in this
 //    distribution, for details about the copyright.
@@ -143,7 +143,7 @@ begin
   else v := expectStrLit(c, n);
   Include(s.flags, sfImportc); // magics don't need an implementation, so we
   // treat them as imported, instead of modifing a lot of working code
-  Include(s.loc.Flags, lfNoDecl); // magics don't need to be declared!
+  // BUGFIX: magic does not imply ``lfNoDecl`` anymore!
   for m := low(TMagic) to high(TMagic) do
     if magicToStr[m] = v then begin
       s.magic := m; exit
diff --git a/nim/ropes.pas b/nim/ropes.pas
index 864afd5b8..6b6540c24 100644
--- a/nim/ropes.pas
+++ b/nim/ropes.pas
@@ -64,7 +64,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, msgs, strutils, platform, hashes, crc;
+  nsystem, msgs, strutils, platform, nhashes, crc;
 
 const
   CacheLeafs = true;
diff --git a/nim/rst.pas b/nim/rst.pas
index 0c5377646..6d0d476c9 100644
--- a/nim/rst.pas
+++ b/nim/rst.pas
@@ -16,7 +16,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, nos, msgs, strutils, platform, hashes, ropes, charsets, options;
+  nsystem, nos, msgs, strutils, platform, nhashes, ropes, charsets, options;
 
 type
   TRstNodeKind = (
@@ -79,6 +79,7 @@ type
     rnImage,
     rnFigure,
     rnCodeBlock,
+    rnContainer,   // ``container`` directive
     rnIndex,       // index directve:
                    // .. index::
                    //   key
@@ -111,9 +112,9 @@ const
     'TableRow', 'TableHeaderCell', 'TableDataCell', 'Label', 'Footnote',
     'Citation', 'StandaloneHyperlink', 'Hyperlink', 'Ref', 'Directive',
     'DirArg', 'Raw', 'Title', 'Contents', 'Image', 'Figure', 'CodeBlock',
-    'Index', 'SubstitutionDef', 'GeneralRole', 'Sub', 'Sup', 'Idx',
-    'Emphasis', 'StrongEmphasis', 'InterpretedText', 'InlineLiteral',
-    'SubstitutionReferences', 'Leaf'
+    'Container', 'Index', 'SubstitutionDef', 'GeneralRole', 
+    'Sub', 'Sup', 'Idx', 'Emphasis', 'StrongEmphasis', 'InterpretedText', 
+    'InlineLiteral', 'SubstitutionReferences', 'Leaf'
   );
 
 type
@@ -1178,12 +1179,12 @@ end;
 
 type
   TDirKind = ( // must be ordered alphabetically!
-    dkNone, dkAuthor, dkAuthors, dkCodeBlock,
+    dkNone, dkAuthor, dkAuthors, dkCodeBlock, dkContainer,
     dkContents, dkFigure, dkImage, dkInclude, dkIndex, dkRaw, dkTitle
   );
 const
-  DirIds: array [0..10] of string = (
-    '', 'author', 'authors', 'code-block',
+  DirIds: array [0..11] of string = (
+    '', 'author', 'authors', 'code-block', 'container',
     'contents', 'figure', 'image', 'include', 'index', 'raw', 'title'
   );
 
@@ -1993,6 +1994,14 @@ begin
   result.kind := rnCodeBlock
 end;
 
+function dirContainer(var p: TRstParser): PRstNode;
+begin
+  result := parseDirective(p, {@set}[hasArg], parseSectionWrapper);
+  assert(result.kind = rnDirective);
+  assert(rsonsLen(result) = 3);
+  result.kind := rnContainer;
+end;
+
 function dirImage(var p: TRstParser): PRstNode;
 begin
   result := parseDirective(p, {@set}[hasOptions, hasArg, argIsFile], nil);
@@ -2071,6 +2080,7 @@ begin
       dkImage:      result := dirImage(p);
       dkFigure:     result := dirFigure(p);
       dkTitle:      result := dirTitle(p);
+      dkContainer:  result := dirContainer(p);
       dkContents:   result := dirContents(p);
       dkRaw:        result := dirRaw(p);
       dkCodeblock:  result := dirCodeBlock(p);
diff --git a/nim/scanner.pas b/nim/scanner.pas
index d035b973b..51532c801 100644
--- a/nim/scanner.pas
+++ b/nim/scanner.pas
@@ -21,7 +21,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  charsets, nsystem, sysutils, hashes, options, msgs, strutils, platform,
+  charsets, nsystem, sysutils, nhashes, options, msgs, strutils, platform,
   idents, lexbase, llstream, wordrecg;
 
 const
diff --git a/nim/sem.pas b/nim/sem.pas
index 3494754fd..09f9bf49b 100644
--- a/nim/sem.pas
+++ b/nim/sem.pas
@@ -112,6 +112,23 @@ begin
   end
 end;
 
+function semAfterMacroCall(c: PContext; n, p: PNode): PNode;
+begin
+  result := n;
+  if (p = nil) or (p.kind <> nkIdent) then
+    liMessage(n.info, errInvalidParamKindX, renderTree(p))
+  else begin
+    case p.ident.id of
+      ord(wExpr): result := semExprWithType(c, result);
+      ord(wStmt): result := semStmt(c, result);
+      ord(wTypeDesc): 
+        result.typ := semTypeNode(c, result, nil);
+      else
+        liMessage(p.info, errInvalidParamKindX, p.ident.s)
+    end
+  end
+end;
+
 function semMacroExpr(c: PContext; n: PNode; sym: PSym): PNode;
 var
   p: PEvalContext;
@@ -128,7 +145,7 @@ begin
   result := s.params[0];
   popStackFrame(p);
   if cyclicTree(result) then liMessage(n.info, errCyclicTree);
-  result := semStmt(c, result);
+  result := semAfterMacroCall(c, result, sym.ast.sons[paramsPos].sons[0]);
   // now, that was easy ...
   // and we get more flexibility than in any other programming language
 end;
@@ -137,14 +154,12 @@ end;
 {$include 'seminst.pas'}
 {$include 'sigmatch.pas'}
 
-
 procedure CheckBool(t: PNode);
 begin
   if (t.Typ = nil) or (skipVarGeneric(t.Typ).kind <> tyBool) then
     liMessage(t.Info, errExprMustBeBool);
 end;
 
-
 procedure typeMismatch(n: PNode; formal, actual: PType);
 begin
   liMessage(n.Info, errGenerated,
@@ -167,13 +182,17 @@ var
   prc: PSym;
   it: PNode;
 begin
-  for i := 0 to sonsLen(c.generics)-1 do begin
+  for i := c.lastGenericIdx to sonsLen(c.generics)-1 do begin
     it := c.generics.sons[i].sons[1];
     if it.kind <> nkSym then InternalError('addCodeForGenerics');
     prc := it.sym;
-    if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then 
+    if (prc.kind in [skProc, skConverter]) and (prc.magic = mNone) then begin
+      if (prc.ast = nil) or (prc.ast.sons[codePos] = nil) then 
+        InternalError(prc.info, 'no code for ' + prc.name.s);
       addSon(n, prc.ast);
+    end
   end;
+  c.lastGenericIdx := sonsLen(c.generics);
 end;
 
 function myOpen(module: PSym; const filename: string): PPassContext;
@@ -212,10 +231,21 @@ end;
 function myProcess(context: PPassContext; n: PNode): PNode;
 var
   c: PContext;
+  a: PNode;
 begin
   result := nil;
   c := PContext(context);
   result := semStmt(c, n);
+  // BUGFIX: process newly generated generics here, not at the end!
+  if sonsLen(c.generics) > 0 then begin
+    a := newNodeI(nkStmtList, n.info);
+    addCodeForGenerics(c, a);
+    if sonsLen(a) > 0 then begin
+      // a generic has been added to `a`:
+      addSonIfNotNil(a, result);
+      result := a
+    end
+  end
 end;
 
 function myClose(context: PPassContext; n: PNode): PNode;
@@ -226,7 +256,8 @@ begin
   closeScope(c.tab);    // close module's scope
   rawCloseScope(c.tab); // imported symbols; don't check for unused ones!
   if n = nil then result := newNode(nkStmtList)
-  else result := n;
+  else InternalError(n.info, 'n is not nil');
+  //result := n;
   addCodeForGenerics(c, result);
   popOwner();
   c.p := nil;
diff --git a/nim/semdata.pas b/nim/semdata.pas
index 3393ed4b3..acca48376 100644
--- a/nim/semdata.pas
+++ b/nim/semdata.pas
@@ -55,6 +55,7 @@ type
     libs: TLinkedList;       // all libs used by this module
     p: PProcCon;             // procedure context
     fromCache: bool;         // is the module read from a cache?
+    lastGenericIdx: int;     // used for the generics stack
     semConstExpr: function (c: PContext; n: PNode): PNode;
       // for the pragmas module
   end;
diff --git a/nim/semfold.pas b/nim/semfold.pas
index 781c3b97d..fdbad9f4c 100644
--- a/nim/semfold.pas
+++ b/nim/semfold.pas
@@ -24,7 +24,7 @@ function getConstExpr(module: PSym; n: PNode): PNode;
   // evaluates the constant expression or returns nil if it is no constant
   // expression
 
-function evalOp(m: TMagic; n, a, b: PNode): PNode; 
+function evalOp(m: TMagic; n, a, b, c: PNode): PNode; 
 function leValueConv(a, b: PNode): Boolean;
 
 function newIntNodeT(const intVal: BiggestInt; n: PNode): PNode;
@@ -113,8 +113,8 @@ begin
   InternalError(a.info, 'no symbol for ordinal value: ' + toString(x));
 end;
 
-function evalOp(m: TMagic; n, a, b: PNode): PNode;
-// if this is an unary operation, b is nil
+function evalOp(m: TMagic; n, a, b, c: PNode): PNode;
+// b and c may be nil
 begin
   result := nil;
   case m of
@@ -127,8 +127,9 @@ begin
     mBitnotI, mBitnotI64: result := newIntNodeT(not getInt(a), n);
 
     mLengthStr: result := newIntNodeT(length(getStr(a)), n);
-    mLengthSeq, mLengthArray,
-    mLengthOpenArray: result := newIntNodeT(lengthOrd(a.typ), n);
+    mLengthArray: result := newIntNodeT(lengthOrd(a.typ), n);
+    mLengthSeq, mLengthOpenArray: 
+      result := newIntNodeT(sonsLen(a), n); // BUGFIX
 
     mUnaryPlusI, mUnaryPlusI64, mUnaryPlusF64: result := a; // throw `+` away
     mToFloat, mToBiggestFloat:
@@ -273,6 +274,11 @@ begin
       else
         result := newStrNodeT('true', n)
     end;
+    mCopyStr: 
+      result := newStrNodeT(ncopy(getStr(a), int(getOrdValue(b))+strStart), n);
+    mCopyStrLast: 
+      result := newStrNodeT(ncopy(getStr(a), int(getOrdValue(b))+strStart, 
+                                             int(getOrdValue(c))+strStart), n);
     mFloatToStr: result := newStrNodeT(toStringF(getFloat(a)), n);
     mCStrToStr, mCharToStr: result := newStrNodeT(getStrOrChar(a), n);
     mStrToStr: result := a;
@@ -281,7 +287,7 @@ begin
       result := copyTree(a);
       result.typ := n.typ;
     end;
-    mExit, mInc, ast.mDec, mAssert, mSwap,
+    mNewString, mExit, mInc, ast.mDec, mAssert, mSwap,
     mAppendStrCh, mAppendStrStr, mAppendSeqElem, mAppendSeqSeq,
     mSetLengthStr, mSetLengthSeq, mNLen..mNError: begin end;
     else InternalError(a.info, 'evalOp(' +{&} magicToStr[m] +{&} ')');
@@ -376,7 +382,7 @@ end;
 function getConstExpr(module: PSym; n: PNode): PNode;
 var
   s: PSym;
-  a, b: PNode;
+  a, b, c: PNode;
   i: int;
 begin
   result := nil;
@@ -443,10 +449,14 @@ begin
             if a = nil then exit;
             if sonsLen(n) > 2 then begin
               b := getConstExpr(module, n.sons[2]);
-              if b = nil then exit
+              if b = nil then exit;
+              if sonsLen(n) > 3 then begin
+                c := getConstExpr(module, n.sons[3]);
+                if c = nil then exit;
+              end
             end
             else b := nil;
-            result := evalOp(s.magic, n, a, b);
+            result := evalOp(s.magic, n, a, b, c);
           end
         end
       except
diff --git a/nim/semstmts.pas b/nim/semstmts.pas
index ebf14693c..a5242b526 100644
--- a/nim/semstmts.pas
+++ b/nim/semstmts.pas
@@ -354,7 +354,8 @@ var
 begin
   result := n;
   checkSonsLen(n, 1);
-  if (c.p.owner = nil) or (c.p.owner.kind <> skIterator) then
+  if (c.p.owner = nil) or (c.p.owner.kind <> skIterator)
+  or (c.p.nestedLoopCounter <= 0) then
     liMessage(n.info, errYieldNotAllowedHere);
   if (n.sons[0] <> nil) then begin
     n.sons[0] := SemExprWithType(c, n.sons[0]);
diff --git a/nim/tigen.pas b/nim/tigen.pas
index 937883e5e..687b70920 100644
--- a/nim/tigen.pas
+++ b/nim/tigen.pas
@@ -17,7 +17,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, ast, astalgo, strutils, hashes, trees, treetab, platform, magicsys,
+  nsystem, ast, astalgo, strutils, nhashes, trees, treetab, platform, magicsys,
   options, msgs, crc, idents, lists, types, rnimsyn;
   
 function gcWalker(t: PType): PNode;
diff --git a/nim/transf.pas b/nim/transf.pas
index 5d9f44143..c4ed5740c 100644
--- a/nim/transf.pas
+++ b/nim/transf.pas
@@ -801,7 +801,7 @@ begin
       inc(j);
       if isConstExpr(a) then 
         while (j < sonsLen(m)) and isConstExpr(m.sons[j]) do begin
-          a := evalOp(op.magic, m, a, m.sons[j]);
+          a := evalOp(op.magic, m, a, m.sons[j], nil);
           inc(j)
         end;
       addSon(result, a);
diff --git a/nim/treetab.pas b/nim/treetab.pas
index dbd7b5276..31d7aa0cf 100644
--- a/nim/treetab.pas
+++ b/nim/treetab.pas
@@ -15,7 +15,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, hashes, ast, astalgo, types;
+  nsystem, nhashes, ast, astalgo, types;
 
 function NodeTableGet(const t: TNodeTable; key: PNode): int;
 procedure NodeTablePut(var t: TNodeTable; key: PNode; val: int);
diff --git a/nim/wordrecg.pas b/nim/wordrecg.pas
index dd2df0047..7957d354b 100644
--- a/nim/wordrecg.pas
+++ b/nim/wordrecg.pas
@@ -19,7 +19,7 @@ interface
 {$include 'config.inc'}
 
 uses
-  nsystem, hashes, strutils, idents;
+  nsystem, nhashes, strutils, idents;
 
 type
   TSpecialWord = (wInvalid,
diff --git a/objdata.txt b/objdata.txt
deleted file mode 100644
index 653ae5931..000000000
--- a/objdata.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-nodes: 2224942
-syms:    39562
-Types:   28189
-
-nodes: 2224942
-syms:    39562
-Types:   29054
-Ropes: 1245961
diff --git a/rod/nimrod.ini b/rod/nimrod.ini
index 755c1dd17..a32c78e57 100644
--- a/rod/nimrod.ini
+++ b/rod/nimrod.ini
@@ -81,6 +81,7 @@ Files: "lib/base/lua/*.nim"
 
 [Windows]
 Files: "bin/nimrod.exe"
+Files: "bin/nimrodd.exe"
 Files: "dist/mingw"
 BinPath: r"bin;dist\mingw\bin"
 
diff --git a/tests/csvtest.csv b/tests/csvtest.csv
new file mode 100644
index 000000000..6e7e14103
--- /dev/null
+++ b/tests/csvtest.csv
@@ -0,0 +1,8 @@
+headerField1,headerField2,headerField3
+12,12132,"hallo ""
+ du"
+1,,
+,2,
+,,3
+1,2,3
+
diff --git a/tests/data.csv b/tests/data.csv
new file mode 100644
index 000000000..ea73f7387
--- /dev/null
+++ b/tests/data.csv
@@ -0,0 +1,6 @@
+Algo_A; Algo_B; Algo_C
+12; 12; 16
+2; 5; 9
+63; 65.3; 90
+0; 1.2; 3
+
diff --git a/tests/gctest.nim b/tests/gctest.nim
index 2f8b97b38..f58dc3217 100644
--- a/tests/gctest.nim
+++ b/tests/gctest.nim
@@ -28,6 +28,16 @@ type
     of nkList: sons: seq[PCaseNode]
     else: unused: seq[string]
 
+  TIdObj* = object of TObject

+    id*: int                  # unique id; use this for comparisons and not the pointers

+  

+  PIdObj* = ref TIdObj

+  PIdent* = ref TIdent

+  TIdent*{.acyclic.} = object of TIdObj

+    s*: string

+    next*: PIdent             # for hash-table chaining

+    h*: int                   # hash value of s

+
 var
   flip: int
 
@@ -134,7 +144,17 @@ proc buildBTree(father: var TBNode) =
     father.t.data = @["ha", "lets", "stress", "it"]
   setSons(father)
 
+proc getIdent(identifier: cstring, length: int, h: int): PIdent = 
+  new(result)

+  result.h = h

+  result.s = newString(length)
+
 proc main() =
+  discard getIdent("addr", 4, 0)
+  discard getIdent("hall", 4, 0)
+  discard getIdent("echo", 4, 0)
+  discard getIdent("huch", 4, 0)
+  
   var
     father: TBNode
   for i in 1..1_00:
@@ -156,9 +176,6 @@ proc main() =
   writeln(stdout, s[89])
   write(stdout, "done!\n")
 
-#main()
-
-#GC_disable()
 var
     father: TBNode
     s: string
@@ -177,4 +194,4 @@ main()
 write(stdout, "finished\n")
 GC_fullCollect()
 GC_fullCollect()
-write(stdout, GC_getStatistics())
+writeln(stdout, GC_getStatistics())
diff --git a/tests/toop1.nim b/tests/toop1.nim
index bf3d2021d..8bae002e7 100644
--- a/tests/toop1.nim
+++ b/tests/toop1.nim
@@ -31,7 +31,7 @@ proc init(my: var TRectangle) =
   my.height = 10
   my.draw = drawRectangle
 
-macro `!` (n: expr): expr = 
+macro `!` (n: expr): stmt = 
   result = newNimNode(nnkCall, n)
   var dot = newNimNode(nnkDotExpr, n)
   dot.add(n[1])    # obj
diff --git a/todo.txt b/todo.txt
index 3e80ba6f1..66c4762f6 100644
--- a/todo.txt
+++ b/todo.txt
@@ -4,27 +4,17 @@ TO IMPLEMENT
 Plan
 ----
 
-* implement new memory manager --> hopefully faster turnaround times
 * implement LLVM backend --> faster turnaround times
-
-
-RST
----
-- footnotes; prefix :i: whitespace before :i:, _reference, `reference`__
-  __ anonymous: www.nimrod.org
+* implement ``p(.int, int.): string`` notation for resolution of overloaded
+  procs
 
 Bugs
 ----
 
-- BUG: check if "break" is valid is not complete: "break" within "for"
-  may be incorrect, if the called iterator is not in a loop
-  --> check that "yield" is inside a loop!
 - BUG: returning an array does not work --> see md5.nim module
 - BUG: if not nodeOfDegree(g, 1) >= 0: inc(counter)
-- BUG: addr/deref may not work when interpreting
 - BUG: the parser allows empty object case branches
 - BUG: when optmizing cgen.c with Visual C++, GCC, LLVM (O3), it breaks.
-- BUG: ``-cc:bcc`` command line option does not error
 - BUG: symbol files still do not work
 - BUG: tlastmod returns wrong results on BSD (Linux, MacOS X: works)
 
@@ -32,6 +22,12 @@ Bugs
 High priority
 -------------
 
+- new $$ string interpolation operator? 
+  $$"The value is $var &var" -- too hard to implement
+
+- find a way to reindroduce the cleanup() pass for C code generation: this
+  is hard because of partial evaluation --> symbol files will fix this as
+  a side effect
 - typeAllowed() for parameters...
 - implicit conversions from ``ptr/ref T`` to ``var T`` and from
   ``ptr/ref T`` to ``T``? Yes.
@@ -44,15 +40,40 @@ High priority
   implement
 - language change: inheritance should only work with reference types, so that
   the ``type`` field is not needed for objects! --> zero overhead aggregation
+- resizing of strings/sequences could take into account the memory that
+  is allocated
+
+
+Library
+-------
+
+- socket, http, ftp, email, fastcgi: implement from scratch
+- osproc for Windows
+- bignums
+
+- gui module
+- finish json module: hard
+
+- YAML module
+- ncurses bindings
+- python
+- TCL
+- automate module: expect-like module for Nimrod
+
+- for system:
+  proc `@` [T](a: openArray[T]): seq[T] = 
+    newSeq(result, a.len)
+    for i in 0..a.len-1: result[i] = a[i]
+    
+  --> ensure @[] calls the array version!
+
 
 For the next versions
 =====================
 
 - multi-processor support
 - IDE
-- better support for GDB?
 - support for generation of dynamic libraries
-- better code generator: skip ropes datastructure, it uses too much memory
 - make set optimizations part of the transformation (--> all backends profit
   from it), but this really needs a more abstract code generator
 
@@ -60,11 +81,8 @@ For the next versions
 Further ideas/nice to have
 ==========================
 
-- queues additional to streams: have to positions (read/write) instead of one
+- queues additional to streams: have two positions (read/write) instead of one
 - introduce: refany type???
-- CLR code generator; better use XYZ? --> Version 1.2?
-- provide an interactive shell: if the user wants his commands
-  to be executed, the command should end with #
 - implement packed arrays (bit arrays)/ packed records
 - implement tables (implement as library? - no! Builtin because of
   constructor syntax is nice to have)
@@ -119,23 +137,6 @@ Version 2
     
 
 
-Library
--------
-
-- gui module
-- finish json module: hard
-- socket, http, ftp, email, fastcgi: implement from scratch
-- ncurses bindings
-- osproc for Windows
-- bignums
-- python
-- TCL
-- automate module: expect-like module for Nimrod
-- parsecsv module
-
-- YAML module
-
-
 Low priority
 ------------
 
@@ -176,23 +177,25 @@ Low priority
         
   o.x = 13 # ambigious
 
-- implement stack walking via assembler for horribly advanced optimizers
-- use `` notation for identifier concatenation?
+- use `` notation for identifier concatenation
 - Visual C++: emit ``default: __assume(0);`` for optimization
 - macros: ``typecheck`` pragma; this is really a good idea! This allows
   transformations based on types!
 - make callconv a set
 - partial generic instantation is missing
-- get code generation for C++ exception handling right!
 - find a way for easy constructors and destructors; though constructors are
   flawed... destructors are not, however!
 - multiple dispatch: no, but provide a proc ``typeId`` to allow the user to
   implement it efficiently
-- replace ropes with strings in the C code generator: This may yield a HUGE
-  speedup of the compiler! (10%)
 - code generated for type information is wasteful
 
 
+RST
+---
+- footnotes; prefix :i: whitespace before :i:, _reference, `reference`__
+  __ anonymous: www.nimrod.org
+
+
 Changelog
 =========
 
@@ -542,4 +545,39 @@ Changelog
 - BUGFIX: iterators using open arrays
 - BUGFIX: [$anyEnum]
 
+0.7.6: release
+0.7.7:
+- implemented the "parsecsv" module
+- added ``math.TRunningStat`` object and its methods
+- added ``strutils.validIdentifier``
+- reStructuredText parser: implemented ``.. container ::`` directive
+- updated the website
+- ``cgi.stackTraceNewLine`` functionality
+- added ``cgi.decodeData`` 
+- BUGFIX: evaluation for ``mLengthSeq``, ``mLengthOpenArray``, 
+  ``evalSetLengthSeq``, ``evalNewSeq``
+- ``copy`` and ``newString`` are magics now; thus several more things
+  can be evaluated
+- ``evalAddr`` fixed
+- BUGFIX: generics are now processed earlier in the pipeline; thus 
+  generics can be used within macros
+- new module ``xmlgen``
+- ``macros.error`` now prints a stack trace
+- changed bootstrapping in ``koch.py`` and ``boot.nim`` to fix bug 
+  #369607.
+- implemented the new memory management; the GC does not take advantage of
+  it yet
+- BUGFIX: magics don't imply ``lfNoDecl`` any longer
+- BUGFIX: ``newString`` is not evaluated at compile-time anymore, unless
+  evaluation is requested
+- the GC now relies on the new memory manager
+- BUGFIX: check that "yield" is inside a loop!
+- BUGFIX: ``isAllocatedPtr`` still had a small bug
+- overflow checking for ``newSeq`` now works
+- BUGFIX: ``commands.processSwitch`` no errors if an argument is given to a
+  switch that does not receive one
+
+0.7.8: release
+
+
 
diff --git a/tools/niminst b/tools/niminst
index a21ff1486..628e7632a 100644
--- a/tools/niminst
+++ b/tools/niminst
Binary files differdiff --git a/tools/nimweb.nim b/tools/nimweb.nim
index 135be9570..63f13ea25 100644
--- a/tools/nimweb.nim
+++ b/tools/nimweb.nim
@@ -1,7 +1,7 @@
 #
 #
 #        The Nimrod Website Generator
-#        (c) Copyright 2008 Andreas Rumpf
+#        (c) Copyright 2009 Andreas Rumpf
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -15,7 +15,7 @@ type
   TConfigData = object of TObject
     tabs, links: seq[TKeyValPair]
     doc, srcdoc, webdoc: seq[string]
-    authors, projectName, projectTitle, infile, outdir, ticker: string
+    authors, projectName, projectTitle, logo, infile, outdir, ticker: string
     vars: PStringTable
     nimrodArgs: string
 
@@ -29,6 +29,9 @@ proc initConfigData(c: var TConfigData) =
   c.outdir = ""
   c.nimrodArgs = ""
   c.authors = ""
+  c.projectTitle = ""
+  c.projectName = ""
+  c.logo = ""
   c.ticker = ""
   c.vars = newStringTable(modeStyleInsensitive)
 
@@ -37,7 +40,7 @@ include "sunset.tmpl"
 # ------------------------- configuration file -------------------------------
 
 const
-  Version = "0.5"
+  Version = "0.6"
   Usage = "nimweb - Nimrod Installation Generator Version " & version & """
 
   (c) 2008 Andreas Rumpf
@@ -119,6 +122,7 @@ proc parseIniFile(c: var TConfigData) =
           case normalize(k.key)
           of "name": c.projectName = v
           of "title": c.projectTitle = v
+          of "logo": c.logo = v
           of "authors": c.authors = v
           else: quit(errorStr(p, "unknown variable: " & k.key))
         of "var": nil
diff --git a/tools/sunset.tmpl b/tools/sunset.tmpl
index e10f58eff..44f7ac486 100644
--- a/tools/sunset.tmpl
+++ b/tools/sunset.tmpl
@@ -14,7 +14,9 @@
     <div id="links">
       <!-- **** INSERT LINKS HERE **** -->
     </div>
-    <div id="logo"><h1>$c.projectTitle</h1></div>
+    <div id="logo"><h1>$c.projectTitle</h1>
+    <h2>$c.logo</h2>
+    </div>
     <div id="content">
       <div id="menu">
         <ul>